[英]Explain how variable hiding is working in this Java code
考虑下面的代码
class A
{
int x = 5;
void foo()
{
System.out.println(this.x);
}
}
class B extends A
{
int x = 6;
// some extra stuff
}
class C
{
public static void main(String args[])
{
B b = new B();
System.out.println(b.x);
System.out.println(((A)b).x);
b.foo();
}
}
该计划的输出是
6
5
5
我理解前两个但是无法理解最后一个。 b.foo()如何打印5.B类将继承foo方法。 但它不应该打印bx会打印什么? 到底发生了什么?
是的, B
类继承了foo
方法。 但是B
的变量x
隐藏了A
的x
; 它不会取代它。
这是一个范围问题。 A
的foo
方法只能看到范围内的变量。 范围中唯一的变量是A
的实例变量x
。
foo
方法在B
继承但未被覆盖。 如果您使用相同的确切代码显式覆盖foo
:
class B extends A
{
int x = 6;
@Override
void foo()
{
System.out.println(this.x);
}
}
然后该变量时提到了,这将是在范围this.x
将B
的x
,和6
将被打印。 虽然方法的文本是相同的,但由于范围的原因,引用是不同的。
顺便提一下,如果你真的想在B
类中引用A
的x
,你可以使用super.x
。
字段在Java和具有相同字段名称的子类中不能覆盖父类阴影“仅”父类的字段。
所以this.x
指的是当前类中定义的x
: A
。
结果: 5
。
更确切地说: foo()
方法由B
子类继承,但它并不意味着继承方法的行为将因引用的实例字段而改变,因为所述字段不可覆盖:引用的this.x
表达式foo()
方法中的Ax
字段继续引用Ax
。
这与之前的两个陈述完全相同:
B b = new B();
System.out.println(b.x); // refers B.x -> 6
System.out.println(((A)b).x); // refers A.x -> 5
b.foo(); // refers under the hood A.x -> 5
rgettman的非常好的答案显示了如何克服隐藏在子类中的字段。
克服隐藏的替代方法依赖于使实例字段为private
(建议使用)并提供返回值的方法。
通过这种方式,您可以从覆盖机制中受益,并且字段隐藏不再是类的客户端的问题:
class A
{
private int x = 5;
int getX(){
return x;
}
void foo()
{
System.out.println(this.getX());
}
}
class B extends A
{
private int x = 6;
int getX(){
return x;
}
}
嗯,这是因为静态绑定。
1)Java中的静态绑定在编译时发生,而动态绑定在运行时发生。
2)私有方法,最终方法和静态方法和变量使用静态绑定并由编译器绑定,而虚拟方法在运行时基于运行时对象绑定。
3)静态绑定使用Type(Java中的类)信息进行绑定,而动态绑定使用Object来解析绑定。
4)使用静态绑定绑定重载方法,而在运行时使用动态绑定绑定重写方法。
在JAVA中 ,可以覆盖方法,而变量则不能。 因此,由于您的方法foo
未在B
被覆盖,因此它从A
获取成员变量。
你打电话的时候
b.foo();
它检查B
是否覆盖了方法foo()
,它没有。 然后它向一个级别向上看,超类A
并调用该方法。
然后你调用了A
的foo()
版本然后打印出来
this.x
现在, A
看不到B
的x
版本。
为了解决这个问题,你必须覆盖B
的方法
class B extends A
{
int x = 6;
@Override
void foo()
{
System.out.println(this.x);
}
}
现在,打电话
b.foo();
将调用B
的foo()
版本,您将获得预期的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.