求大神解释,为什么test调用父类i,却调用子类的方法
public class T1 {
int i = 0;
public void Test1() {
System.out.println(i);
}
public void Test2() {
System.out.println(i);
}
}
public class T2 extends T1 {
int i = 2;
public void Test2() {
System.out.println(i);
}
public static void main(String[] args) {
T1 test = new T2();
test.Test1();
test.Test2();
System.out.println(test.i);
test = (T2)test;
System.out.println(test.i);
}
}
==============解决方案=====================
这是java的重写,子类重写了父类的方法。
另外,你new的是子类,只是用了一个父类接口去引用,他本质还是子类的对象。所以你调用test2永远都是调用子类的。这点和c++不一样
===============解决方案=====================
test的引用类型是T1,实质是T2的实例
第一个输出test.Test1()运行的是T2实例的方法
T2实例的初始化过程是从根父类开始的,可以大致理解为栈状结构逐层构建
T2方法
T2域
T1方法
T1域
T0方法
T0域
test作为T2实例继承T1的Test1()方法实际并没有复制,运行Test1()时其实质是在栈中向下搜索至T1的Test1()方法,该方法中的println向下寻找i,于是结果是T1中的i。如果T1有父类T0也有一个域i,也会被覆盖。
第二个输出test.Test2()也可以作类似理解。其实T1作为引用类型只是限制了test可用“哪一些”方法,不可以调用子类独有父类没有的方法,仅此而已,至于运行“哪一个”(继承过程中的)方法就是由T2实例决定的,所以只要子类有的方法不会去找父类,没有的话就向下找。
上面关于方法的调用是由实例决定的,是多态的特性,同一个父类引用装入不同实例就有不同方法,但变量不一样,变量只是方法的辅助对象的属性,变量和多态没有直接关系不会受实例类型影响,获取的变量值和引用类型有关,所以第三个输出T1引用类型的test的i是0。
至于第四个输出前强制转型test = (T2)test;后test依然是T1引用类型并没有改变,所以输出依然是T1的i值0。如果句子是T2 test2 = (T2)test;输出test2的i值将会是2。
===================解决方案============================
T1和T2中都有i,这其实代表不同地址中的数据
为了便于理解,其实应该把T2中的i改成i2
T1 test = new T2();
这创建的是一个T1对象
无论是否强转,test.i都是最初创建时的值。所以System.out.println(test.i); 结果都是0
Test1() 打印结果肯定为0.
Test2() 被子类重写,打印的结果为1.