解释变量隐藏在这个Java代码中是如何工作的

考虑下面的代码

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(bx); System.out.println(((A)b).x); b.foo(); } } 

该计划的输出是

 6 5 5 

我理解前两个但是无法理解最后一个。 b.foo()如何打印5.B类将inheritancefoo方法。 但它不应该打印bx会打印什么? 到底发生了什么?

是的, B类inheritance了foo方法。 但是B的变量x隐藏了Ax ; 它不会取代它。

这是一个范围问题。 Afoo方法只能看到范围内的变量。 范围中唯一的变量是A的实例变量x

foo方法在Binheritance但未被覆盖。 如果您使用相同的确切代码显式覆盖foo

 class B extends A { int x = 6; @Override void foo() { System.out.println(this.x); } } 

然后,当x引用时将在范围内的变量将是Bx ,并且将打印6 。 虽然方法的文本是相同的,但由于范围的原因,引用是不同的。

顺便说一句,如果你真的想在B类中引用Ax ,你可以使用super.x

嗯,这是因为静态绑定。

1)Java中的静态绑定发生在编译时,而动态绑定发生在运行时。

2)私有方法,最终方法和静态方法和变量使用静态绑定并由编译器绑定,而虚拟方法在运行时基于运行时对象绑定。

3)静态绑定使用Type(Java中的Class)信息进行绑定,而Dynamic绑定使用Object来解析绑定。

4)使用静态绑定绑定重载方法,而在运行时使用动态绑定绑定重写方法。

字段在Java和具有相同字段名称的子类中不可覆盖,父类阴影“仅”父类的字段。
所以this.x指的是当前类中定义的xA
结果: 5

更确切地说: foo()方法由B子类inheritance,但它并不意味着inheritance方法的行为将因引用的实例字段而改变,因为所述字段不可覆盖:引用的this.x表达式foo()方法中的Ax字段继续引用Ax

这与之前的两个陈述完全相同:

  B b = new B(); System.out.println(bx); // refers Bx -> 6 System.out.println(((A)b).x); // refers Ax -> 5 b.foo(); // refers under the hood Ax -> 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; } } 

JAVA中 ,可以覆盖方法,而变量则不能。 因此,由于您的方法foo未在B被覆盖,因此它从A获取成员变量。

你打电话时

 b.foo(); 

它检查B是否覆盖了方法foo() ,它没有。 然后它看起来是一个级别,超级类A并调用该方法。

然后你调用了Afoo()版本然后打印出来

 this.x 

现在, A看不到Bx版本。


为了解决这个问题,您必须覆盖B的方法

 class B extends A { int x = 6; @Override void foo() { System.out.println(this.x); } } 

现在,打电话

 b.foo(); 

将调用Bfoo()版本,您将获得预期的结果。