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

Misleading example of hiding names in Java

请查看以下来源:

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?它应该从 class Base 中检索 className,因为在 Derived class 中它是 private

然而,setter setClassName 设置 public className 在 class Base 和私有字段 className 的情况下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  

谁能解释一下这个奇怪的事情?

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

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

您有两个字段,一个在 Base 中,一个在 Derived 中,它们(风格不佳)恰好具有相同的名称 className。但它们是完全不同的东西。如果将 Base class 重命名为 baseClassName,将 Derived 重命名为 derivedClassName,代码的行为将相同。 (从现在开始,我将使用新名称来说明发生了什么。)

您在 Base 中有一个 setClassName() 方法,它将 Base class 中已知的名为 className 的字段设置为 baseClassName 字段。该方法甚至不知道在某些子 class 中可能有另一个字段碰巧有一个冲突的名称。由于 Java 中没有字段覆盖,它设置 baseClassName,而不是 derivedClassName.

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