Java流量控制

时间:2014-11-19 09:51:43

标签: java flow-control

有人可以解释为什么这段代码输出为null?当我尝试拨打new A()而不是new B()时,它会打印当前日期。

class A
{
    Date d = new Date();

    public A()
    {
        printDate();
    }

    void printDate() 
    {
        System.out.println("parent");
        System.out.println(d);
    }
}

class B extends A
{
    Date d = new Date();

    public B()
    {
        super();
    }

    @Override
    void printDate()
    {
        System.out.println("child");
        System.out.println(d);
    }
}

public class Test 
{
    public static void main(String[] args) 
    {
        new B();
    }
}

5 个答案:

答案 0 :(得分:4)

new B()调用B的构造函数,它调用A的构造函数.A的构造函数调用printDate(),由于重写,执行B的printDate(),它打印{的值{ {1}}变量d。但是,B的{​​{1}}变量尚未初始化(它只会在执行A的构造函数后初始化)。因此它仍然为null(这是引用变量的默认值)。

另一方面,当您创建dB)的实例时,会调用A new A(),并打印printDate变量A,在d的构造函数被执行之前初始化。

如果不清楚,B.d不会覆盖A.d,它只是隐藏它。只能覆盖方法。

答案 1 :(得分:1)

Date声明为静态

static Date d = new Date();
    public B(){
        super();
    }
    @Override
    void printDate(){
        System.out.println("child");
        System.out.println(d);
    }

答案 2 :(得分:1)

实例化B

  1. B构造函数链到A构造函数

  2. A构造函数调用printDate,但它是B.printDate覆盖,称为

  3. B.printDate打印B.d

  4. 由于null字段尚未初始化而提供B.d

  5. printMethod返回,A构造函数返回

  6. 初始化B的字段,将B.d设置为非空值。但是影响输出的时间太晚了。


  7. 从中吸取教训:

    • 构造函数在创建的对象上调用实例方法是个坏主意,除非该实例方法是privatefinal。如果你设法调用一个已经被子类重载的方法,那么该方法将在它们被初始化之前看到子类的实例变量 ......并且这是有问题的。

      < / LI>
    • 在类和子类中对(非私有)字段使用相同的名称是个坏主意。这两个字段都将存在,并且阅读代码的人可能很难将其保持在正确的位置。

    • 非私有实例字段不是一个好主意。它们不适合封装。

答案 3 :(得分:1)

这是因为当你调用super()时,A类中定义的Date变量d被初始化。 因为在类B中,变量d是一个对象变量,它从父类重写变量d,并且只有在构造this指针后才构造对象变量,否则变为空。 如果您希望它按预期工作,请将B类中的变量d作为静态变量,然后使用类加载进行初始化。

答案 4 :(得分:1)

在所有输入之后,我希望以下答案满足,

由于B也有字段d,因此A.d不会继承到B,其中B有自己的d副本。

因此,当控件在B.printDate()中时,它会尝试查找A.d(因为函数是从A调用的)。

如果从B

中删除以下行,这可以正常工作
Date d = new Date();