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