Collections.copy
is defined as:
public static <T> void copy(List<? super T> dest, List<? extends T> src)
I understand how it works and have no issues. I tried writing an alternative way to exhibit the same as:
public static <T, E extends T> void copy(List<T> dest, List<E> src){
for(E e: src){
dest.add(e);
}//ignore implementation. it has flaws. The focus is declaration of copy
}
The idea is simple. For whatever type you read from source, the destination type should be its super type. So now you can do:
copy(new ArrayList<Number>(), new ArrayList<Number>());
copy(new ArrayList<Number>(), new ArrayList<Integer>());
copy(new ArrayList<Object>(), new ArrayList<Number>());
copy(new ArrayList<Object>(), new ArrayList<Double>());
It looks alright. But is there any flaw with above when compared to actual Collections.copy? Any place where the actual outbeats the above one from type-information perspective?
The collection. copy( ) method returns a deep copy of the collection instance. Deep copy means that objects or collections within the original collection are duplicated and do not share any reference with the returned collection.
The copy() method of java. util. Collections class is used to copy all of the elements from one list into another. After the operation, the index of each copied element in the destination list will be identical to its index in the source list. The destination list must be at least as long as the source list.
I think one place where the original is better, is from conciseness. Especially from code-generation point of view.
If I am calling original function with full declaration, I can
Collections.<Object>copy(new ArrayList<Object>(), new ArrayList<Number>());
In my case it would be:
MyClass.<Object, Number> copy(new ArrayList<Object>(), new ArrayList<Number>());
So its a bit more concise.
In terms of absolute information typing, I do not think there is a difference (but I would be happy to be proved wrong). In fact, it compiles and runs fine if the body of your static method is simply a call to Collections.copy
. A couple key points though, after a lot of thought and experimentation:
Collections.copy
is conceptually much more clear than the one you've suggested. It exemplifies the PECS principle (see also Josh Bloch's Effective Java).Collections.copy
, I observe that the type parameter T
is never actually used directly. Your version creates the same type bounding (source must generate a subtype of dest), but without such a clear connotation that there is some well-defined "middle type" where the wildcard bounds meet.Consider a class TypeCopier<T>
which copies parametrized types.
public class TypeCopier<T> {
void copyType(List<? super T> dest, List<? extends T> src) {
// copy
}
public static void main(String[] args) {
TypeCopier<Number> copier = new TypeCopier<>();
copier.copyType(new ArrayList<Object>(), new ArrayList<Integer>());
}
}
Notice a few things about this first example:
Number
with a single parameterdest
and src
to be any supertype and subtype of Number
respectivelyNow try to make a similar class using the signature you suggested:
public class TypeCopierBad<T, E extends T> {
void copyType(List<T> dest, List<E> src) {
// copy
}
public static void main(String[] args) {
TypeCopierBad<Object, Number> copier = new TypeCopierBad<>();
copier.copyType(new ArrayList<Object>(), new ArrayList<Integer>());
}
}
Notice a few things about this second example:
src
is not exactly the Number
typedest
and src
can be, compared to the previous exampleLooks like your declaration meets the requirement of PECS principle, so i think it's just about style, where Collections.copy
is more common version.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With