Instantiating a class assignable to Collection
I want to check if a given Class is assignable to a java.util.Collection, and if so create a new instance of it.
I tried the following:
Class<?> clazz = ... // I got this from somewhere
if (!clazz.isInterface() && java.util.Collection.class.isAssignableFrom(clazz)) {
jav开发者_Go百科a.util.Collection<?> collection = clazz.newInstance();
}
Predictably it doesn't work, since it cannot convert to an unknown type to a java.util.Collection. I thought of adding a cast but that seems like a hack.
I also thought of doing this:
Class<? extends java.util.Collection<?>> collectionClass = Class<? extends java.util.Collection<?>> clazz;
java.util.Collection<?> collection = clazz.newInstance();
Now there's no need for the cast at newInstance but I still have to cast the Class object.
What's the right way to do this? Thanks.
(for clarity I removed the try/catch around newInstance in case I'm trying to instantiate an abstract class)
Cast is a must because of the wild card you are using. i.e. Class<?> clazz
. Casting is not a hack, c'mon. And here its reasonably fine, as its under the check.
You have to use a cast when you are using newInstance() there is no way around that. Your first example is fine.
This is an interesting question. The second form avoids the need for an explicit type cast on the result of calling clazz.newInstance()
. In reality, the emitted code will include an implicit type cast because the compiler doesn't know whether the newInstance()
method cheats (does an "unsafe conversion") and returns something of the wrong type.
Try clazz.asSubClass(Collection.class).newInstance()
, this should give an already typed Collection<?>
instance
After the if statement, you know that clazz is a subclass of collection (even though the compilr does not know that). So you can cast it:
Class<?> clazz = ... // I got this from somewhere
if (!clazz.isInterface() && java.util.Collection.class.isAssignableFrom(clazz)) {
Class<Collection<?>> collectionClazz = (Class<Collection<?>>) clazz;
java.util.Collection<?> collection = collectionClazz.newInstance();
}
The compiler will complain that the cast is not checked at runtime (because at runtime the generic parameters go missing), but that's ok.
... just saw the "asSubclass" method. Does the same job, but it's checked at runtime - it redoes the test that your if() does.
Having said that - whenever I see the instanceof keyword these days I instantly suspect that there should be a generic type being used. That is, the class or method containing the code above should probably have access to a parameterised class T and be using Class.
精彩评论