私有访问与自我限制的泛型

时间:2011-09-02 20:42:47

标签: java generics visibility

将私有字段访问与Java中的CRTP相结合似乎在可见性规则中发现了一个奇怪的边缘情况:

public abstract class Test<O extends Test<O>> implements Cloneable {
    private int x = 0;

    @SuppressWarnings("unchecked")
    @Override
    protected final O clone() {
        try {
            return (O) super.clone();
        } catch (CloneNotSupportedException ex) {
            throw new AssertionError(ex);
        }
    }

    public final int getX() {
        return x;
    }

    public final O withX(int x) {
        O created = clone();
        created.x = x;  // Compiler error: The field Test<O>.x is not visible
        return created;
    }
}

只需将withX()方法更改为此...

    public final O withX(int x) {
        O created = clone();
        Test<O> temp = created;
        temp.x = x;
        return created;
    }

...使代码编译。我在Oracle的javac和Eclipse的编译器中对此进行了测试。是什么给了什么?

1 个答案:

答案 0 :(得分:7)

这实际上不是泛型问题。 JLS inheritance rules使私有字段在子类中不可见。由于X是私有的,因此它不是O类型的成员,即使它是Test<O>类型的成员,O也是Test<O>的子类型。如果您使用过以下代码:

public final O withX(int x) {
    Test<O> created = clone();
    created.x = x;
    return (O) created;
}

它会起作用。这是Java不支持LSP的实例,但它只是类型系统的本地问题,因为私有字段仅可用于相同类型的对象。如果它不起作用,那么私有字段就不会私有。我不认为对递归模板的规则有一个特殊的例外是一个好主意。

注意,这实际上并不是对你能做什么的限制。当您想要进行更改时,您始终可以将子类型转换为超类型,就像您在替代代码中一样。