关于在Java中隐藏/隐藏成员变量的问题

时间:2011-06-24 20:37:54

标签: java shadowing member-hiding

我想了解隐藏在Java中是如何工作的。 所以我们假设你有以下代码

public class A{
    protected SomeClass member;
    public A(SomeClass member){
        this.member = member;
    }
}  

public class B extends A{
    protected SomeClass member;
    public B(SomeClass member){
        super(member);
    }
    public static void main(String[] args){
        SomeClass sc = new SomeClass();
        B b = new B(sc);
        System.out.println(b.member.toString());
    }
}

如果我编译我很荣幸有NullPointerException。我以为这将是sc.toString();

的输出

我将此代码更改为

public class A{
    protected SomeClass member;
    public A(SomeClass member){
        setMember(member);
    }
    public void setMember(SomeClass sc){
       this.member = sc;
    }

}  

public class B extends A{
    protected SomeClass member;
    public B(SomeClass member){
        super(member);
    }
    public void setMember(SomeClass sc){
       this.member = sc;
    }
    //...main
}

并按预期获得输出... ok setMember of B覆盖A中的那个,所以我可以这样解释。 我玩了一下,从B中删除了setMember,得到了我的NullPointerException。但是如果我将A的代码改为

,它会再次编译并给出输出
public class A{
    protected SomeClass member;
    public A(SomeClass member){
        setMember(member);
    }
    public void setMember(SomeClass sc){
       member = sc;
    }

} 

在我看来,实际上有两个SomeClass成员实例......但是如果有两个实例则意味着什么?隐藏只对第二种情况有用吗?

1 个答案:

答案 0 :(得分:3)

我假设您的第一个代码示例的最后一行是b.member.toString()

有两个名为“member”的成员变量,在两个示例中,只设置了其中一个变量,因为只调用了一个this.member赋值。要修复第一个例子,你通常会说

public B(SomeClass member) {         
    super(member);
    this.member = member;
} 

但我认为你已经理解了这一点,并且真的在问为什么语言是这样设计的。它与超类实现的封装有关。超类的作者应该能够在不破坏子类的情况下重写它,反之亦然。想象一下,如果B.member首先出现是因为B的作者虽然是“成员”会是一件好事,后来A的作者也有同样的想法。

然而,这个系统并不完美,你的第二个例子说明了原因。如果B.setMember()首先出现,然后更高版本的A引入A.setMember(),那么A的作者可能无法预测覆盖B.setMember()方法,并按照您显示的方式编写构造函数, A.member永远不会被初始化的结果。 C#引入了“覆盖”关键字来捕获这种东西,Java将其作为“@overrides”借用,但是这个注释在Java中并不是疯狂的,所以它不那么有效。