With Java, is it acceptable to use an unbounded wildcard type as a method's argument, and then check and cast it to a parameterized type?
If I use unbounded wildcard types for two collections (each collection will have a different type) as the arguments for a method:
private void doAssertion(List<?> testLis开发者_如何学编程t, List<?> generatedList)
Inside this method, can I first check the type of objects in these collections, and then cast the collection to a parameterized type? This just smells bad, and I get an unchecked cast warning.
if (testList.get(0) instanceof X) {
List<X> xList = (List<X>) testList;
// call methods specific to X for each object
}
else if (testList.get(0) instanceof Y){
List<Y> yList = (List<Y>) testList;
// call methods specific to Y for each object
}
Part of my problem is that I don't have the ability to touch the code that defines classes X or Y. Otherwise, I know I can have them implement a common interface, and use a bounded type parameter. I can't overload assertEqual
because both methods have the same erasure.
In my case, X and Y are always going to be children of other classes, and I'm not modifying the objects in anyway, just calling the get()
methods of the objects.
No, you shouldn't do this. Take for example:
List<Integer> myIntList = ...;
if (myIntList.get(0) instanceof Number) {
List<Number> myNumberList = (List<Number>)myIntList;
myNumberList.put(Double.valueOf(100)); // BAD!
}
Generic arguments are not necessarily substitutable in sub/superclass hierarchies.
You can declare multiple methods with concrete types X and Y:
private void doAssertion(List<X> testList, List<X> generatedList, X x) {
// call methods specific to X for each object
}
private void doAssertion(List<Y> testList, List<Y> generatedList, Y y) {
// call methods specific to Y for each object
}
The 3rd parameter is simply used simply to hint method resolution.
private <T, U> void doAssertion(List<T> testList, List<U> generatedList);
In my case, X and Y are always going to be children of other classes, and I'm not modifying the objects in anyway, just calling get() methods.
If the above statement is true, then are these getXX() methods on the parent class. If so, why can't you do:
private void doAssertion(List<? extends SomeFoo> testList, List<? extends SomeFoo> generatedList)
Assuming SomeFoo has the functions you want then I can call it with any subclass of SomeFoo.
Warning:
List<?>
means list of unknown type. You will be able to get() from this list but will not be able to add() to it, except null.
In case you need to add elements it's best to just use non-generic version and check the type as you proposed. The result will be the same.
private void doAssertion(List testList, List generatedList){
if (testList.get(0) instanceof X) {
List<X> xList = (List<X>) testList;
// call methods specific to X for each object
} else if (testList.get(0) instanceof Y){
List<Y> yList = (List<Y>) testList;
// call methods specific to Y for each object
}
}
Also make sure that lists are not empty before doing (testList.get(0) instanceof X)
Afaik, there is no notion of Unbound Wild Card Types in C#. If so, it's nice as I think there is only that much one can do with UnboundWildCardTypes (or not?) - c below:
private static void demoUnboundedWildcardType(List<?> aList, List<?> anotherList, Object obj){
//aList.add(""); You can't do this because at compile time capture is ? and not string.
aList.contains(""); // you can only methods that don't take a generic type.
Set<?> gs = (Set<?>) obj; // But must do this and not Set<?> gs = (Set) obj; aka don't use raw types
}
精彩评论