I understand why I cannot do the following:
private class Parent {
};
private class Child extends Parent {
};
private class Grand开发者_StackOverflow中文版Child extends Child {
};
public void wontCompile(List<? extends Parent> genericList, Child itemToAdd) {
genericList.add(itemToAdd);
}
My question is there ANY practical way to have a typesafe List where you can call add(E) where E is known to be only a Parent or a Child?
I vaguely remember some use of the "|" operator as used for wildcard bounds, but I cannot find it in the spec...
Thanks!
There is not.
In add(E)
, the determination of the exact type of E could be made only at runtime. Any variable declared to be of type Parent can hold a reference to a GrandChild object, due to the subtype relationship; there's no way to create a list where you can't add objects of a subtype of the element type (at least, where such an operation will be prohibited by the compiler).
The real question is: why do you even want that? Perhaps your inheritance hierarchy is upside down.
Why not? All you need is a matching generic type for both the List and item arguments that satisfies both the calling parameters, you can achieve that pretty simply:
import java.util.ArrayList;
import java.util.List;
public class TestClass {
private class Parent {
};
private class Child extends Parent {
};
private class GrandChild extends Child {
};
public <T extends Parent> void compilesNow(final List<T> genericList, final T itemToAdd) {
genericList.add(itemToAdd);
}
public void addSomeDescendents() {
final List<Parent> list = new ArrayList<Parent>();
compilesNow(list, new Parent());
compilesNow(list, new Child());
compilesNow(list, new GrandChild());
}
}
EDIT: Sorry I missed the bit about excluding GrandChild... however, my example is a step further into how Generics can be utilized to make this scenario at least compile
Your class hierarchy
public class Parent {
}
public class Child extends Parent {
}
public class GrandChild extends Child {
}
How to add a type and its subtypes to a generic List
public class Runner {
//List that contains anything that has a super class Parent
private static List<? super Parent> genericList = new ArrayList<>();
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
GrandChild grandChild = new GrandChild();
genericList.add(parent);
genericList.add(child);
genericList.add(grandChild);
genericList.forEach(System.out::println);
}
}
The output
com.abd.test.generics.Parent@1218025c
com.abd.test.generics.Child@816f27d
com.abd.test.generics.GrandChild@87aac27
You could create a facade and do your own instanceof checking before delegating to an encapsulated List.
It would be ugly and is most likely a horrible idea.
精彩评论