Class<? extends Algorithm> alg = AlgorithmAllFrom9AndLastFrom10Impl.class
Constructor<Algorithm> c = alg.getConstructors()[0];
开发者_高级运维
For "alg.getConstructors()[0];" I am getting a warning in eclipse
Type safety: The expression of type Constructor needs unchecked conversion to conform to Constructor
How do I fix this?
The documentation for Class<T>.getConstructors()
reveals the issue:
Constructor<?>[] getConstructors()
: Note that while this method returns an array ofConstructor<T>
objects (that is an array of constructors from this class), the return type of this method isConstructor<?>[]
and notConstructor<T>[]
as might be expected. This less informative return type is necessary since after being returned from this method, the array could be modified to holdConstructor
objects for different classes, which would violate the type guarantees ofConstructor<T>[]
.
Compare this with Class<T>.getConstructor()
overload:
Constructor<T> getConstructor(Class<?>... parameterTypes)
This overload actually returns Constructor<T>
.
In your case, since you have Class<? extends Algorithm> alg
, alg.getConstructor(parameterTypes)
returns a Constructor<? extends Algorithm>
(which by the way, can NOT be safely cast to Constructor<Algorithm>
).
Whenever possible, i.e. when you know the parameter types, you should always prefer getConstructor(parameterTypes)
to getConstructors()[arbitraryIndex]
, since with the latter you're never quite guaranteed which constructor will be selected. Selecting based on parameter types is most specific, and as shown here, is also more compiler-friendly with regards to the generic type information.
If by getConstructors()[0]
you really meant to get the nullary constructor, then simply do this instead:
Constructor<? extends Algorithm> nullaryConstructor = alg.getConstructor();
Summary
So your problem was two fold:
getConstructors()
returns aConstructor<?>[]
, meaning all type information are lost- Even if type information isn't lost (e.g. by using
getConstructor(parameterTypes)
overload), you'd still only get aConstructor<? extends Algorithm>
at best (not aConstructor<Algorithm>
).Class<T>.getConstructor(parameterTypes)
returns aConstructor<T>
- In your case, the type parameter
T
is? extends Algorithm
See also
- Java Tutorials/Generics/More fun with wildcards
Related questions
- What is the difference between
<E extends Number>
and<Number>
?
Discussion
It is unfortunate that getConstructors()
returns an array because as explained in the dcoumentation, because since arrays covariant, this forced the signature to Constructor<?>
, losing generic type information. The fact that arrays are mutable also means that getConstructors()
must create a new array instance every time!
System.out.println(int.class.getConstructors().length); // prints "0"
System.out.println(
int.class.getConstructors() == int.class.getConstructors()
); // prints "false"!
Ideally getConstructors()
should return a List<Constructor<T>>
, which should be wrapped by Collections.unmodifiableList
; not only would this keep the type information, but Class<T>
could also then return the same List
object on every getConstructors()
.
For more discussion on this subject, read Effective Java 2nd Edition, Item 25: Prefer lists to arrays.
Actually without a cast to Constructor<Algorithm>
I get an error.
One solution is to do Constructor<?> c = alg.getConstructors()[0];
since that's the type that getConstructors() returns.
Another is to add @SuppressWarnings("unchecked")
to that line, basically telling the compiler "I know for sure that this is a Constructor<Algorithm>
" which the compiler can't tell.
The Constructor
array returned from getConstructors()
has an unbounded wildcard type paramter. You can use:
Constructor<?> c = alg.getConstructors()[0];
I assume that the reason getConstructors()
doesn't bound its wildcard is because that would result in a generic array. Perhaps one of the getConstructor()
methods is better suited for what you need.
精彩评论