在Java中隐藏名称的误导性示例

时间:2017-09-24 16:58:55

标签: java object liskov-substitution-principle

请查看以下来源:

public class Base {
    public String className = "Base";

    public void setClassName(String className){
        this.className = className;
    }
}

public class Derived extends Base {
    private String className = "Derived";
}

public class PrivateMatter {

    private static void test (Base b){
        System.out.println(b.className);
    }

    public static void main (String[] args){

        Derived d = new Derived();
        d.setClassName("d");

        Base b = new Base();
        b.setClassName("b");

        test(b); // it prints b
        test(d); // it prints d

    }
}

我期待输出:

b
Base  

应该做什么test?它应该从类className中检索Base,因为在Derived类中它是private

但是,如果是setClassName,则设置者className设置公开BaseclassName设置私有字段Derived。这是我的直觉。

为了总结(我的思维方式):

Derived d = new Derived();
d.setClassName("d"); // it set private field (which did hide field from class Base)

Base b = new Base();
b.setClassName("b"); // it set public field (which is originally placed in `Base` class

test(b); // it prints b - it is ok for me
test(d); // it prints d - why ? After all, d.setClassName("d")  should modify private field, however test should print public field  

有人可以解释这个奇怪的事吗?

1 个答案:

答案 0 :(得分:1)

简短回答:字段无法覆盖同名字段,只能使其不可见。这是方法的一个主要区别。

为什么" b"和" d"打印

您有两个字段,一个在Base,另一个在Derived,其中(按错误样式)碰巧具有相同的名称className。但它们完全不同。如果将Base类1重命名为baseClassName,将Derived one重命名为derivedClassName,则代码的行为将相同。 (从现在开始,我将使用新名称来说明会发生什么。)

setClassName()中有一个Base方法,它设置了className类中已知的Base字段,即baseClassName字段。这种方法甚至不知道在某些子类中可能会有另一个字段发生碰撞名称。由于Java中没有字段覆盖,因此设置baseClassName,而不是derivedClassName

test()方法引用Base.className,即baseClassName字段,而不是derivedClassName。因此,此方法打印在setClassName()调用中设置的值。