首页 > 试题广场 >

下面代码的输出是什么?

[单选题]
下面代码的输出是什么?
public class Base
{
    private String baseName = "base";
    public Base()
    {
        callName();
    }

    public void callName()
    {
        System. out. println(baseName);
    }

    static class Sub extends Base
    {
        private String baseName = "sub";
        public void callName()
        {
            System. out. println (baseName) ;
        }
    }
    public static void main(String[] args)
    {
        Base b = new Sub();
    }
}

  • null
  • sub
  • base
推荐
答案:A
 new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。
创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null
编辑于 2015-01-17 11:36:28 回复(74)
1.首先,需要明白类的加载顺序
(1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
(2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
(3) 父类非静态代码块( 包括非静态初始化块,非静态属性 )
(4) 父类构造函数
(5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
(6) 子类构造函数
其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)
2.其次,需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。
Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。
当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中 父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。
由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。
编辑于 2017-05-25 11:09:56 回复(73)
public class Base {
	private String baseName = "base";
	public Base() {
		callName();
	}
	public void callName() {
		System.out.println(baseName);
	}
	public static void main(String[] args) {
		Base b = new Sub();
	}
}
class Sub extends Base {
	private String baseName = "sub";
	public void callName() {
		System.out.println(baseName);
	}
}
本题与内部类无关系,去掉内部类后代码如上,
执行 Base b = new Sub();时由于多态 b编译时表现为Base类特性,运行时表现为Sub类特性,
Base b = new Sub();不管是哪种状态都会调用Base构造器执行 callName()方法;
执行方法时,由于多台表现为子类特性,所以会先在子类是否有 callName();
而此时子类尚未初始化(执行完父类构造器后才会开始执行子类),
如果有就执行,没有再去父类寻找
如果把父类 callName()改为 callName2(),则会输出base
编辑于 2016-03-08 12:05:22 回复(20)
这题考察的是java的初始化顺序,先初始化父类的成员变量,再初始化父类的构造函数,因为父类里面的构造函数里面的方法在子类中已经进行了重写所以会调用子类的这个方法,但是子类成员变量还没初始化,所以其为null
发表于 2016-03-05 10:03:29 回复(2)
A.
new一个子类对象,默认会先调用父类的构造方法来初始化父类的成员变量,执行Base()方法,在Base()方法中执行CallName()方法,而子类已经重写了父类的CallName()方法,所以执行的是子类的CallName()方法,而父类的成员变量还没有被初始化,所以为null

发表于 2015-08-18 16:58:52 回复(5)

从类加载机制和初始化层面来看,过程可以认为如下(大致如此,有交叉):
Sub类
1、加载(根据class文件在方法区中建立instanceofKlass对象)
2、验证
3、准备(此时除去final字段,Sub类字段都为初始值)
4、解析
4.1解析父类,即Base(要用类加载器加载父类,可以认为此时父类完成加载)
4.2解析字段,即baseName,根据字段简单名(注意是简单名,不是全名)从下往上递归解析,对于本题解析结果是子类常量池的字段,此时为null。
4.3解析方法,同样根据简单名解析,此时方法为子类覆盖父类的方法。
5、初始化,从顶到底,执行类的<clinit>()方法。此方法为java文件中所有静态代码段或静态赋值语句的总和。很显然,到这一步,父类和子类的baseName都是null。
6、创建对象。因为是new Sub(),所以先在虚拟机中方法区为子类申请空间,在堆中放置子类的instanceofklass对象句柄(这个是JVM中类的实例表示),内存分配成功,执行子类的<init>()函数(<init>()函数是字段赋值语句加上构造函数语句的合体</init>),在子类中的<init>()函数中调用父类的<init>()函数,在父类的函数中调用callName含数,注意callName函数是用invokevirtual语句调用的,invokevirtual语句表示,根据调用对象解析的方法来使用。调用对象是在本地变量表的第0位,用了this表示,这个this指的就是前面说的instanceofklass对象句柄,就是sub对象。所以此时print打印的就是sub对象的callName()方法,既然是sub的callName,自然打印null,因为sub的非静态字段赋值语句是在父类的<init>()方法结束后进行的。</init></init></init></init></clinit>

发表于 2019-01-11 23:17:53 回复(4)
 new Sub()先执行父类的构造方法,父类构造方法调用callName()方法,子类对其进重写。执行子类的callName()方法。输出的成员变量也就是子类的成员变量。但是由于子类还没执行构造函数。所以输出null。
发表于 2016-02-02 20:27:23 回复(5)
运行顺序,父类的构造方法执行的是子类的callName方法,原因是多态
发表于 2019-05-23 10:25:24 回复(2)
首先加载基类:基类成员变量->构造函数->子类成员变量->子类构造函数->
父类调用子类callName()时baseName还没加载 所以为空 可debug调试下 一目了然

发表于 2016-01-25 11:43:02 回复(1)
A.
考察类的加载顺序。
首先加载基类:1->构造函数->子类覆盖->基类成员变量->子类构造函数->子类成员变量
发表于 2015-08-21 09:25:46 回复(4)
1.首先,需要明白类的加载顺序。 (1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法) (2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 ) (3) 父类非静态代码块( 包括非静态初始化块,非静态属性 ) (4) 父类构造函数 (5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 ) (6) 子类构造函数 其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的) 2.其次,需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。 Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。 当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中 父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。 由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。
发表于 2019-04-02 22:40:51 回复(1)
这里的考点是继承的初始化先后和多态的转型
  1. 首先,初始化父类中的静态成员变量静态代码块,按照在程序中出现的顺序初始化;

  2. 然后,初始化子类中的静态成员变量静态代码块,按照在程序中出现的顺序初始化;

  3. 其次,初始化父类普通成员变量代码块,在执行父类的构造方法

  4. 最后,初始化子类普通成员变量代码块,在执行子类的构造方法


基于这道题,初始化流程如下
  1. 先初始化父类Base的静态成员变量静态代码块,由于无静态成员变量静态代码块于是,这一步跳过
  2. 接着,初始化子类Sub的静态成员变量静态代码块,由于无静态成员变量静态代码块于是,这一步跳过。
  3. 紧跟着,初始化父类Base的成员变量和调用构造方法,构造方法里面调用了callName方法
  4. 这个callName方法是调用Sub类的callName方法,因为这里是父类引用指向子类对象(编译看左边,执行看右边),于是调用了子类的callName方法
  5. 但是这时候子类的Sub的成员变量还未初始化,所以打印null

发表于 2023-01-22 22:02:02 回复(2)
发表于 2021-10-18 09:58:08 回复(0)
本题考查知识点是多态(上转型)以及类的先后加载顺序
 上转型 类似 Father father = new Son();
1:父类中的静态代码块
2:子类中的静态代码块
3:父类中构造方法
4:子类当中的构造方法

下面我来简单分析一下加载顺序
当执行到 Base b =newSub()时
所以本题的加载顺序是:加载父类Base类中的构造方法Base()进而调用callName()(因为子类把父类的这个方法给覆盖了,所以此方法执行的是子类中的)
因为子类中的baseName变量还没进行初始化,故为null

发表于 2017-07-08 20:01:00 回复(0)
解题要点:
1、静态内部类是不依赖于外部类的,静态内部类中只能访问外部类的静态成员(变量和方法),此处的内部类没有意义,静态非静态,只是在构造内部类对象时写法不同,但程序执行没有差异;
2、继承关系类的加载顺序(不考虑静态属性和静态代码的情况下):初始化父类的非静态成员属性或非静态代码块-->执行父类的构造函数-->初始化子类的非静态成员属性或非静态代码块-->执行子类的构造函数;本题中首先执行父类的 privateString baseName = "base";,然后执行父类的构造函数;执行过程中调用callName()方法;
3、多态:父类引用指向子类对象,父类引用b指向了子类对象new Sub();多态中,实际执行时如果子类重写了父类的方法,则执行子类的方法;
4、根据多态的原则,再执行父类的构造方法中调用callName方法,实际调用的是子类的callName方法,子类的callName方法输出的是属性baseName的值,可是这时子类的baseName属性还没有被初始化,因为此时仍处在父类构造函数执行过程中。
发表于 2016-10-15 15:03:13 回复(0)
package com.bjpowernode.test;

public class Base {
    private String subName="base";
    
    public Base(){
        callName();
    }
    
    public void callName(){
        System.out.println(subName);
    }
    
    static class Sub extends Base{
        
        
        public void callName(){
            System.out.println(super.subName);
        }
        
    }
    
    public static void main(String[] args) {
        Base base = new Sub();
    }
}
如果调用的是父类的subName,则会输出base;
但是因为调用的是子类的,而还没有创建,所以输出null
另外子类的baseName只是混淆视听,换成别的变量名,也是一样的
package com.bjpowernode.test;

public class Base {
    private String subName="base";
    
    public Base(){
        callName();
    }
    
    public void callName(){
        System.out.println(subName);
    }
    
    static class Sub extends Base{
        
        private String a = "sub";
        
        public void callName(){
            System.out.println(a);
        }
        
    }
    
    public static void main(String[] args) {
        Base base = new Sub();
    }
}

输出null
发表于 2018-03-21 17:39:43 回复(0)
本题特殊在于是在构造方法中调用普通方法,这种场景下成员变量都还未初始化完成,所以打印出来成员变量的值为null
发表于 2017-03-15 13:09:51 回复(1)
JAVA的入口是main函数,
函数中什么都没说,所以说打印的是空
发表于 2015-11-27 11:39:18 回复(6)
A
发表于 2015-01-03 15:15:21 回复(0)
先初始化父类的静态代码--->初始化子类的静态代码-->
初始化父类的非静态代码--->初始化父类构造函数--->
初始化子类非静态代码--->初始化子类构造函数
发表于 2016-07-11 13:51:42 回复(0)
 new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。 创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null
发表于 2016-04-11 19:18:26 回复(0)