I've an interface ITransportable that force the classes who implements it to have two methods, one for produce a object based on "this", and one to load "this" from a object. In fact I'm using "transports" object to hide the underlying classes to the user, so every class that is "transportable", in this example "ItemDetalle" have a corresponding transport class. The GenericTransport class implements some generics methods I use to make the code more readable and all transports classes derive from it.
public interface ITransportable<T> {
public T getTransport();
public <U extends ITransportable<T>> U loadFromTransport(T transport);
}
public class GenericTransport {
[...]
public static <T extends ITransportable<U>,U extends GenericTransport> T loadFromTransport(U transport) {
try {
Method loadFromTransport=transport.getClass().getMethod("loadFromTransport");
T result = (T) loadFromTransport.invoke(transport);
return result;
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(GenericTransport.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static <T,U extends GenericTransport> LinkedList<T> loadFromTransport(List<U> list) {
if (list==null) return null;
LinkedList<T> ll=new LinkedList<>();
for (U element : list) ll.add((T) GenericTransport.loadFromTransport(element));
return ll;
}
}
here there are two "twin" classes, ItemDetalle class and ItemDetalleTransport
public ItemDetalleTransport extends GenericTransport {
[...]
}
public class ItemDetalle implements ITransportable<ItemDetalleTransport> {
public ItemDetalleTransport getTransport() {
[...]
}
public void loadFromTransport(ItemDetalleTransport t) {
[...]
}
}
and there is a class that I use for experimenting:
public class otherClass {
protected LinkedList<ItemDetalle> det
public void setDet(LinkedList<ItemDetalle> det) {
this.det=det;
}
[...]
public void test1(ItemDetalleTransport t) {
ItemDetalle det = GenericTransport.loadFromTransport(t);
}
public void test2(LinkedList<ItemDetalleTransport> t) {
LinkedList<ItemDetalle> localDet = GenericTransport.loadFromTransport(t);
this.setDet(localDet);
}
public void test3(LinkedList<ItemDetalleTransport> t) {
this.det = GenericTransport.loadFromTransport(t);
}
public void test4(LinkedList<ItemDetalleTransport> t) {
this.setDet(GenericTransport.loadFromTransport(t));
}
[...]
}
function "test4" does not work, claiming that a LinkedList of Objects cannot be converted to a LinkedList of ItemDetalle. I understand it's not a very big problem, but I'm curious, someone can explain why?
Thank you!
In Java, Generics are invariant, and I'll explain with an example.
Say you have a class Parent and another class Child which extends Parent. Generics being invariant means that List<Child> will not be considered as List<Parent> unlike arrays (Child[] arr is instanceof Parent[]).
The reason that Generics are invariant is that its implemented by erasure - which means that they enforce their type constraints only at compile time and discard their type information at runtime (again, unlike arrays). Since Generics can't enforce their type during runtime, and in order to be safe to use - Generics were made invariant.
Addendum: Due to the discussion below in the comments, reading this and this teaches us that arrays were made covariant as a trade-off between type-safety and the possibility to make your program more polymorphic. That trade-off was not needed when Generics were introduced because along with them came wildcards which enabled expressions of covariance. Many thanks to @user3580294!
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