我不明白它究竟是如何运作的。
我们有两个A类和B类.B类扩展A. A类具有x属性,以及修改该属性的测试方法。 B类具有x属性,以及修改该属性的测试方法。
public class A {
int x;
public void test() {
this.x = 1;
System.out.println("A" + getX());
}
int getX() {return x;}
}
public class B extends A {
int x;
public void test() {
this.x = 2;
System.out.println("B" + getX());
}
int getX() {return x;}
}
public class Main {
public static void main(String[] args) {
A a = new A();
a.test();
System.out.println(a.getX());
System.out.println("point 1");
a = new B();
a.test();
System.out.println(a.x);
}
}
输出:
A1
1
point 1
B2
0
我对最后一行输出的预测是2,但是为0.为什么是0?
答案 0 :(得分:5)
让我们理解这些代码:
a = new B();
a.test();
System.out.println(a.x);
B
的新对象。它会重新初始化变量 - A.x = 0
和B.x = 0
。 a.test()
,它将调用类test()
中的重写方法B
,该方法会使用B.x
将2
设置为this.x = 2;
}。请注意,A.x
仍为0
。a.x
,该x
将访问课程A
中的字段x
。这些字段不是多态的。您不会覆盖字段,但隐藏它们。 B
中的变量x
隐藏了A
中的变量{{1}}。答案 1 :(得分:2)
如果A和B都有一个名为x的成员,B中的成员将阻止访问从A继承的成员。从B中删除int x;
声明,或明确使用super.x
,如果你想要引用父类中的那个。
答案 2 :(得分:2)
从头开始。
写作时
A a;
你对JVM说请在内存中保留一个适合A
的地址。
之后
a = new A();
您对JVM说,创建一个A类的新对象,并在a
当你这样做时;
a.test();
你对JVM说,转到内存地址a
,然后从对象调用方法test()
。
接下来你要做的是:
a = new B();
您对JVM说,创建一个B类的新对象,并在a
下将地址保存到它。这里没有错误,因为B适合A,因为是子类。
(你松开了与A类对象的连接,你将它改为B)。
下一步操作是
a.test();
您也知道这一点,但这次在地址a
下是类B
的实例。这次JVM搜索B类中的方法,如果不喜欢那么将在A类中搜索。
答案 3 :(得分:1)
我认为你应该首先从继承/多态> 概念开始。
但要说清楚:你有一个对象“a”,它被声明为类型“A”。现在,当您调用方法测试(在这种情况下在B内部覆盖)时,JVM会调用 实际对象 方法。因此,在“point 1”之前 a.test调用A的测试方法,在“point1”之后调用B的测试方法。
问题是此功能(称为多态)仅适用于方法。当您调用实例变量(作为a.x)时,JVM会调用 声明的对象 变量。在这种情况下是A.如果您先进行演员表,您将获得正确的价值:((B)a).x
注意,实际和声明对象之间的区别是基于“new”运算符之后的类型(如new B()
)和对象声明中的类型