2016-07-04 52 views
4

,我有以下的Java代码初始化实例变量都在父母和孩子

public class Base { 
    private static boolean goo = true; 

    protected static boolean foo() { 
     goo = !goo; 
     return goo; 
    } 

    public String bar = "Base:" + foo(); 

    public static void main(String[] args) { 
     Base base = new Sub(); 
     System.out.println(base.bar); 
    } 
} 

public class Sub extends Base { 
    public String bar = "Sub:" + foo(); 
} 

而且我问是什么将打印。经过测试这个答案似乎是Base:false,但我真的不明白为什么它不是Sub:true

通过调试与断点对最终的打印,我有以下对象中运行: Debugger base

其显示具有相同名称的两个变量的基础!一个打印的基地:假和其他预期(由我)子:真。的确foo()被调用两次,但每次实例化一个不同的变量?不应该在子类中创建具有相同名称的变量(并且在创建第一个后初始化)覆盖父类中的变量吗? Java如何选择打印哪一个?

+0

'base'是Base'的'实例的引用,所以当你指的'基地。 goo',你实际上访问'Base.goo',而不是'Sub.goo'。请注意,如果您使用了'Base base = null;',它的工作原理是相同的。这就是为什么你不应该通过“通过实例”访问类的静态属性:你根本不使用实例。 –

+0

@AndyTurner据我所知,我感兴趣的是'bar'变量,它是一个实例变量,同时在'Base'和'Sub'中。 – Nescio

+0

好的。但是,基地。bar'指的是'Base'中的'bar',因为'base'是对'Base'的引用。 –

回答

6

...其中显示具有两个相同名称变量的基地!

是! base是对Sub实例的引用,并且Sub实例具有两个bar字段。让我们把他们Base$barSub$bar

 
     +------------------------+ 
base--->|  Sub instance  | 
     +------------------------+ 
     | Base$bar: "Base:false" | 
     | Sub$bar: "Sub:true" | 
     +------------------------+ 

Java允许对同一名称在不同层次的一个实例的类型层次结构中使用。 (它具有:通常这些都是私人字段等子类甚至可能不知道的是,超有一个具有相同的名称。)

的情况下这两个不同的领域有不同的价值观:Base$bar有值为Base:false,因为它是基于有史以来第一次致电foo进行初始化的,该号码翻转goo(开头为true)并使用翻转的结果。 Sub$bar的值为Sub:true,因为它已从第二次调用初始化为foo,因此goo会再次翻转并使用更新后的值。只创建了一个实例,但foo被调用两次。

其中bar你看到当你访问bar取决于你有实例的引用类型。因为base被声明为Base类型,所以当您执行时,您将访问Sub实例中的Base$bar字段。如果你有一个Sub参考实例,您需要访问Sub$bar代替:

System.out.println(base.bar);  // "Base:false" 
System.out.println(((Sub)base).bar); // "Sub:true" 

Live Example

+0

完美!谢谢! – Nescio

+0

@Nescio:不用担心。这不完美,我已经纠正它(现在肯定还不完美,但没有任何)。在你的代码中只有**一个**实例。我在哪里说“二审”,我的意思是“第二次调用”foo“”。对于那个很抱歉。 –