Community
Participate
Working Groups
I have developed my own Cloneable interface to take advantage of generics. /** A more useful Cloneable interface using generics. */ public interface Cloneable<T extends Cloneable<T>> { public T clone(); } I also have a Map interface called ClonableMap, to make it more convenient to create deep copies of maps. The same idea could be used for making deep copies of the other Collection interfaces. /** Interface for a clonable map. */ public interface CloneableMap<K, V extends Cloneable<V>> extends Map<K, V>, Cloneable<CloneableMap<K, V>> {} /** TreeMap implementation of CloneableMap. */ public class CloneableTreeMap<K, V extends Cloneable<V>> extends TreeMap<K, V> implements CloneableMap<K, V> { public CloneableTreeMap() {} public CloneableTreeMap(CloneableMap<K, V> map) { super(map); for (Map.Entry<K, V> entry : entrySet()) entry.setValue(entry.getValue().clone()); } public CloneableMap<K, V> clone() { return new CloneableTreeMap<K, V>(this); } } So far, so good. The problem I'm running into is that if I define a generic interface that extends Cloneable<T>: public interface C<T extends C<T>> implements Cloneable<T> {} And then add a few concrete implementation classes: public class D implements C<D> { public D clone() { return new D(); } } public class E implements C<E> { public E clone() { return new E(); } } Based on this structure there seems to be no way to create a CloneableMap<Key, C<?>>. CloneableMap<String, C<?>> map = new CloneableTreeMap<String, C<?>>(); ^ map.put("first", new D()); map.put("second", new E()); Changing the generic type from C<?> to raw type C does not help. Maybe I'm looking at this the wrong way, but since C<T extends C<T>> extends Cloneable<T>, with T bounded to implement C<T>, doesn't that guarantee that C<? > must at a minimum implement Cloneable<C<?>>? My compiler doesn't think so: Bound mismatch: The type C is not a valid substitute for the bounded parameter <V extends Cloneable<V>> of the type CloneableMap<K,V> So far the only way I have found to overcome this is to change the interface so it directly implements Cloneable for that interface, and have each implementing class directly implement Cloneable for the concrete type: public interface C implements Cloneable<C> {} public class D implements C, Cloneable<D> { public D clone() { return new D(); } } public class E implements C, Cloneable<E> { public E clone() { return new E(); } } This gets me the functionality I need but I am quite confused about why the first case will not compile.
javac complains if you re-implement the Cloneable<T> interface in the concrete class. The new lowest common denominator is that you can refine the return type but not implement the Cloneable<T> interface for the concrete class: public interface C implements Cloneable<C> {} public class D implements C { public D clone() { return new D(); } } public class E implements C { public E clone() { return new E(); } }
CloneableMap< ..., C<?>> doesn't meet the bound expectation on C<?>; since it it spec'ed to be: CloneableMap<K, V extends Cloneable<V>> which means that, it needs: C<?> <: Cloneable<C<?>> however per construction, this isn't true as: interface C<T extends C<T>> implements Cloneable<T> {} which here means: C<?> <: Cloneable<?> (and not Cloneable<C<?>>) remember that even if String <: Object, List<String> is not a subtype of List<Object>
I'm guessing that you use <: as a left-to-right "implements" or "extends" relationship. I get what you're saying. Do you see a way I could rearrange this to work? Right now it appears that because I'm not properly expressing the guarantee that a Cloneable creates clones of the same class, I can only implements Cloneable<T> *once* in a class heirarchy. Given the following interface heirarchy: interface I extends Cloneable<I> {} interface A extends I {} interface B extends A {} interface C extends A {} interface D extends I {} interface E extends D {} interface F extends D {} I'm not restricted from refining the return type of clone() in each interface, however I can't create a CloneableMap<?, A> because A implements Cloneable<I>, not Cloneable<A>. I can only instantiate a CloneableMap<?, I>. And I can't refine interface A so it extends Cloneable<A>.
'<:' denotes subtype relationship (from the JLS). As for the latter issue, this is indeed mandated by the language that you can only extend/implement one instance of a given generic type. I do not see any workaround to this. Added GenericTypeTest#test766-767