假设您有以下代码
class A {
int i = 4;
A() {
print();
}
void print () {
System.out.println("A");
}
}
class B extends A {
int i = 2; //"this line"
public static void main(String[] args){
A a = new B();
a.print();
}
void print () {
System.out.println(i);
}
}
这将打印0 2
现在,如果您删除标有&#34的行;此行" 代码将打印4 4
A a = new B();
将调用A类,将i初始化为4,调用构造函数,
它控制print()
中的class B
方法,最后打印4.
a.print()
将在类B中调用print()
方法,因为这些方法将在运行时绑定,这也将使用在类A,4中定义的值。
(当然如果我的推理有任何错误,请告诉我)
为什么如果插入代码,第一部分(创建对象)将突然打印0而不是4?为什么不将变量初始化为i = 4,而是指定默认值?
答案 0 :(得分:8)
它是Java中几种行为的组合。
我将简单介绍代码中发生的事情,看看你是否理解。
您的代码在概念上看起来像这样(跳过main()):
class A {
int i = 0; // default value
A() {
A::i = 4; // originally in initialization statement
print();
}
void print () {
System.out.println("A");
}
}
class B extends A {
int i = 0; // Remember this shadows A::i
public B() {
super();
B::i = 2;
}
void print () {
System.out.println(i);
}
}
因此,当您在原始main()
中调用A a = new B();
时,它正在构建B
,为此会发生这种情况:
A::i
和B::i
都是默认值0
A::i
设置为4 print()
被调用。由于后期绑定,它必然会B::print()
B::print()
正在尝试打印B::i
,其仍为0 B::i
设置为2 然后当您在a.print()
中拨打main()
时,它会被B::print()
限制为打印出B::i
(此时为2)。
因此你看到的结果
答案 1 :(得分:7)
新对象中的所有实例变量(包括在超类中声明的那些变量)都被初始化为其默认值 - JLS 12.5
因此,您的变量B::i
将初始化为0. B中的构造函数将类似于:
B() {
super();
i = 2;
}
所以当你打电话
A a = new B();
A中的构造函数将调用B中的print
方法,该方法将在类B中打印i
,即0。
答案 2 :(得分:5)
在你的情况下,B级," i"隐藏" i"的声明在A中,所有引用" i"在子类中指的是B.i而不是A.i。
所以你在A.i中看到的是java中任何int属性的默认值,它是零。
无法在子类中重写Java实例变量。
您想尝试这一点以获得更多说明。
class B extends A {
int i = 2; //"this line"
public static void main(String[] args){
B b = new B();
A a = b;
System.out.println("a.i is " + a.i);
System.out.println("b.i is " + b.i);
}
void print () {
System.out.println(i);
}
}
输出继电器:
a.i is 4
b.i is 2