Java 变量多态性中的初始化
假设您有以下代码Java 变量多态性中的初始化,java,variables,constructor,initialization,polymorphism,Java,Variables,Constructor,Initialization,Polymorphism,假设您有以下代码 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
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
现在,如果删除标记为“this line”的行
代码将打印4
- 我理解如果没有int I=2;行,
A A=新B()代码>将调用类A,将i初始化为4,调用构造函数,
它控制类B中的print()
方法,最后打印4
a.print()
将调用类B中的print()
方法,因为这些方法将在运行时绑定,这也将使用在类a,4中定义的值
(当然,如果我的推理有任何错误,请告诉我)
- 然而,我不明白的是,是否有int i=2
为什么如果插入代码,第一部分(创建对象)会突然打印0而不是4?为什么它不将变量初始化为i=4,而是指定默认值
新对象中的所有实例变量(包括在超类中声明的实例变量)都初始化为其默认值-
因此,变量B::i
将被初始化为0。B中的构造函数如下所示:
B() {
super();
i = 2;
}
所以当你打电话的时候
A a = new B();
A中的构造函数将调用B中的print
方法,该方法将在类B中打印i
,即0。在类B中,“i”的声明隐藏了A中的“i”声明,子类中对“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
它是Java中几种行为的组合
方法重写
实例变量阴影
构造器顺序
我将简单地检查一下代码中发生了什么,看看您是否理解
您的代码在概念上如下所示(跳过main()):
因此,当您在原始的main()
中调用A A=new B()代码>,它正在构造一个B
,为此:
A::i
和B::i
都是默认值0
- super(),这意味着调用了
A::i
设置为4
- 调用
print()
。由于后期绑定,它被绑定到B::print()
B::print()
正在尝试打印出仍为0的B::i
B::i
设置为2
然后,当您在main()
中调用a.print()
时,它被绑定到B::print()
,它正在打印出B::i
(此时为2)
因此,当你调用某个类的构造函数时,你看到的结果是,它的超类的构造函数将在它的构造函数之前被调用,我想你是知道的。你知道吗,在调用构造函数之前,超类的字段也会被初始化?这是一个很好的例子,说明了为什么从构造函数中调用可重写的方法是一个坏主意-结果充其量是令人困惑的,更经常是危险的(有可能泄漏对部分初始化对象的引用)。感谢@Hulk指出了这个打字错误。。用更正更新了我的答案
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);
}
}