需要Java代码段输出说明

我的代码是:

class Foo { public int a=3; public void addFive() { a+=5; System.out.print("f "); } } class Bar extends Foo { public int a=8; public void addFive() { this.a += 5; System.out.print("b "); } } public class TestClass { public static void main(String[]args) { Foo f = new Bar(); f.addFive(); System.out.println(fa); } } 

输出:

 b 3 

请向我解释,为什么这个问题的输出是“b 3”而不是“b 13”,因为该方法被覆盖了?

你不能在Java中覆盖变量,因此你实际上有两个变量 – 一个在Foo ,一个在Bar 。 另一方面, addFive()方法是多态的,因此它修改了Bar.aBar.addFive() ,尽管f静态类型是Foo )。

但最后你访问fa并且使用已知类型的f (即Foo在编译期间解析此引用。 因此Foo.a从未被触及过。

Java中的BTW非最终变量永远不应该公开。

FFoo类型的引用,并且变量不是多态的,因此fa指的是来自Foo的变量,即3

如何validation?

要测试这个,你可以从Foo删除a变量,它会给你编译时错误

注意:将成员变量设为private并使用访问者访问它们


另见

  • 为什么要使用getter和setter?

有了这样一个问题,SCJP考试正在评估你对所谓隐藏的知识。 审查员故意使事情变得复杂,试图让你相信程序的行为只取决于多态性,但事实并非如此。

让我们在删除addFive()方法时让事情更清晰一些。

 class Foo { public int a = 3; } class Bar extends Foo { public int a = 8; } public class TestClass { public static void main(String[]args) { Foo f = new Bar(); System.out.println(fa); } } 

现在情况有点不那么令人困惑了。 main方法声明一个Foo类型的变量,在运行时为其分配一个Bar类型的对象。 这是可能的,因为Barinheritance自Foo 。然后程序引用Foo类型变量的公共字段a

这里的错误是相信称为覆盖的同类概念适用于类字段。 但是对于字段没有这样的概念:类Bar的公共字段a不会覆盖 Foo类的公共字段a ,但它会执行所谓的隐藏 。 顾名思义,它意味着在Bar类的范围内, a将引用Bar自己的字段,它与Foo的字段无关。 ( JLS 8.4.8 – inheritance,覆盖和隐藏 )

那么,当我们写fa ,我们指a是哪a ? 回想一下,字段a解析是在编译时使用对象f的声明类型完成的,即Foo 。 结果,程序打印’3’。

现在,让我们在类Foo添加一个addFive()方法,并在类Bar覆盖它,就像在考试问题中一样。 这里多态性适用,因此调用f.addFive()不使用编译时间而是使用对象f的运行时类型(即Bar f.addFive()来解析,因此打印为“b”。

但是仍然有一些我们必须理解的东西:为什么增加5个单位的场a仍然坚持价值’3’? 这里隐藏着玩耍。 因为这是被调用的类Bar的方法,并且因为在类Bar ,每个a引用了Bar的公共字段a ,这实际上是增加的Bar字段。

1)现在,一个附属问题:我们怎么能从main方法进入Bar的公共领域? 我们可以这样做:

 System.out.println( ((Bar)f).a ); 

这迫使编译器解析f的字段成员a作为Bar a字段。

这将在我们的示例中打印’b 13′

2)还有一个问题:我们怎样才能隐藏在类Bar addFive()方法中,而不是指向Bara字段而是指向它的超类eponimous字段? 只需在字段引用前添加super关键字就可以了:

 public void addFive() { super.a += 5; System.out.print("b "); } 

这将在我们的示例中打印’b 8′

注意初始声明

 public void addFive() { this.a += 5; System.out.print("b "); } 

可以提炼到

 public void addFive() { a += 5; System.out.print("b "); } 

因为当编译器解析字段a ,它将开始从方法addFive()查找最近的封闭范围,并找到Bar类实例,从而无需明确地使用this

但是, this可能是考生解决这个考试问题的线索!

既然你正在做fa你将从类Foo获得a的值。 如果你已经调用了一个方法来获取值,例如getA()那么你就可以从类Bar获得值。