public class A {
public A() {
init();
}protected void init() {}public void print() {
System.out.print("1");
}
}
public class B extends A{
private String b1=null;
protected void init() {
this.b1 = "0";
print();
}
public void print() {
// TODO Auto-generated method stub
System.out.print(b1);
}
        public static void main(String[] args) {
// TODO Auto-generated method stub
A a =new B();//输出0
a.print();//输出null?
}}结果为是么是0null?
0还好理解 a.print()结果为什么是null? b不是0吗面试题Java

解决方案 »

  1.   

    private String b1=null;
    的写法等同于
    private String b1;
    {
       b1 = null;
    }而{}块中的赋值是在构造方法之后执行的。所以最终b1被指向null。
      

  2.   


    a.print();B覆盖了A类的print方法,所以这是多态。会调用B类的print方法.B类的方法只是打b1,而b1是String类型,是引用类型,默认为null。又因为B类没显式构造器,b1没显式在构造器里初始化,所以一直还是null啊
      

  3.   

    我有个不明白的地方,就是为什么子类还没初始化就能调用子类的print方法
      

  4.   

    B类没有覆写父类的构造方法,所以new B();是先调用A的构造方法,在A的构造方法里调用B类覆写A类的init()方法。所以B类的属性b1的值还是null
      

  5.   

    “在A的构造方法里调用B类覆写A类的init()方法”,B类的init方法里已经给b1赋值为“0”了,你这不是自相矛盾吗?按照你的说法就该输出0而不是null了吧!
      

  6.   

    A a =new B();当这句代码执行的时候,先调用父类A的构造函数,在A中调用init()方法,发现子类重写了init()方法,所以直接调用子类的init()方法,调用子类init()方法时,b1赋值为"0",所以打印了0,此时父类A对象构造完毕,然后开始构造子类B对象,先对字段b1赋值为null,再调用子类无参的构造函数。至此,A a =new B();执行完毕,所以b1的值为null。
      

  7.   

    这是一个多态的问题,首先我们分析一下他执行的步骤:
    1.new B();首先在堆中创建一个B类的对象,在创建的时候要先调用构造方法,由于B中没有自己的构造方法,所以要调用父类的构造方法作为自己的去用他。
    2.在调用的时候,要执行init()方法,B已经覆盖了A中的方法,所以执行B中的protected void init() {
    this.b1 = "0";
    print();
    }此时b1被赋值为0,然后执行print()方法,打印出0.
    3.执行完构造方法后,做private String b1=null;b1被指向了一个空值,然后做a.print();,打印后当然是null,不知道这样解释你懂了吗?不懂可以问我。。
      

  8.   


    public class B extends A {
    //4、super()执行完就开始构造B类
    //调用B()的构造之前,会先执行静态代码
    //此时b1=0,然后执行b1=1,然后b1=2
    private String b1 = "1";
    {
    b1="2";
    }
    public B(){
    //2、然后new B()的时候执行到这
    //此时b1=null,然后进入A类的构造方法
    super();
    //5、静态代码执行完后,b1=2
    //然后才是B类自己的构造代码,执行b1=3
    b1="3";
    } protected void init() {
    //3、A类构造方法调用init后执行到这
    //此时b1=null,接下来b1=0并print输出0
    this.b1 = "0";
    print();
    } public void print() {
    // TODO Auto-generated method stub
    System.out.print(b1);
    } public static void main(String[] args) {
    //1、先分配A类的内存,再分配B类的内存
    //此例中可视为A类不占内存,B类只有b1占内存
    //虽然给b1分配了内存,但b1是引用类型,所以此时b1=null
    //如果b1是基础类型(比如int),那分配内存的时候就有默认值
    A a = new B();// 输出0
    //6、B构造完了,此时b1=3
    a.print();// 输出null?
    }}
      

  9.   

     A a = new B(); 
    会调用父类的构造方法,因为父类构造方法中调用了init方法,但是子类复写了init方法所以调用了子类的init方法。子类init中调用print方法也是调用的子类中的。。b1在子类的init方法中被赋值为0.所以会输出0.。
    在执行完父类构造函数的时候会执行到 private String b1=null; 所以此时b1=null了。
     a.print();
    执行依然是子类复写了的print方法。。所以这个地方就输出null咯。表达能力不是很好,希望能看到。
      

  10.   

    A a = new B();调用父类的构造方法

    public A() {
    init();
    }执行其中的init();时,因子类重写了该方法,所在实际上执行的是子类B的init()方法
    于是,输出0
    再执行B类的构造方法
    接着初始化B类的成员
    private String b1 = null;再接着执行
    a.print();
    此时执行的是B类重写的print()方法

     public void print() {
        System.out.print(b1);
      }于是输出了null
      

  11.   

    全出结果是0这是肯定的,
    至于第二个为什么是null,a对象没有被赋值.
      

  12.   

    http://www.ehelper.com.cn/blog/post/40.html
      

  13.   

    其实很简单,Java对象初始化顺序是:
    1.父类实例变量的初始化
    2.父类构造器
    3.子类实例变量的初始化
    4.子类构造器
      

  14.   

    1,进入B的构造函数,给B的成员变量分配空间。(只是分配空间,没有初始化)。2,隐式调用父类A的的构造函数。super().3,给B类成员变量初始化。(这时会将成员变量初始化,引用类型默认null,整型默认0)。4,执行B的构造函数体代码。