有人可以解释为什么这段代码输出为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();
}
}
答案 0 :(得分:4)
new B()调用B的构造函数,它调用A的构造函数.A的构造函数调用printDate()
,由于重写,执行B的printDate()
,它打印{的值{ {1}}变量d
。但是,B
的{{1}}变量尚未初始化(它只会在执行A的构造函数后初始化)。因此它仍然为null(这是引用变量的默认值)。
另一方面,当您创建d
(B
)的实例时,会调用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
:
B构造函数链到A构造函数
A构造函数调用printDate
,但它是B.printDate
覆盖,称为
B.printDate
打印B.d
。
由于null
字段尚未初始化而提供B.d
printMethod
返回,A
构造函数返回
初始化B
的字段,将B.d
设置为非空值。但是影响输出的时间太晚了。
从中吸取教训:
构造函数在创建的对象上调用实例方法是个坏主意,除非该实例方法是private
或final
。如果你设法调用一个已经被子类重载的方法,那么该方法将在它们被初始化之前看到子类的实例变量 ......并且这是有问题的。
在类和子类中对(非私有)字段使用相同的名称是个坏主意。这两个字段都将存在,并且阅读代码的人可能很难将其保持在正确的位置。
非私有实例字段不是一个好主意。它们不适合封装。
答案 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();