Java – private access with self-contained generics
Combining private field access with CRTP in Java seems to find a strange edge in visibility rules:
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;
}
}
Just change the withx () method to this
public final O withX(int x) {
O created = clone();
Test<O> temp = created;
temp.x = x;
return created;
}
... make the code compile I tested this in Oracle's javac and eclipse compilers What gives?
Solution
This is not really a generic problem JLS inheritance rules make private fields invisible in subclasses Because x is private, it is not a member of type O, even if it is a member of type test < o > O is a subtype of test < o > If you have used the following code:
public final O withX(int x) {
Test<O> created = clone();
created.x = x;
return (O) created;
}
It will work This is an instance of LSP that Java does not support, but it is only a local problem of the type system, because private fields can only be used for objects of the same type If it doesn't work, the private field won't be private I don't think it's a good idea to have a special exception to the rules of recursive templates
Please note that this is not really a limitation on what you can do You can convert subtypes to supertypes at any time to make changes, just as in alternative code
