Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflection problem - Type Safety Warning

Tags:

java

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?

like image 609
jax Avatar asked Nov 25 '25 21:11

jax


1 Answers

The documentation for Class<T>.getConstructors() reveals the issue:

Constructor<?>[] getConstructors(): Note that while this method returns an array of Constructor<T> objects (that is an array of constructors from this class), the return type of this method is Constructor<?>[] and not Constructor<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 hold Constructor objects for different classes, which would violate the type guarantees of Constructor<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 a Constructor<?>[], 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 a Constructor<? extends Algorithm> at best (not a Constructor<Algorithm>).
    • Class<T>.getConstructor(parameterTypes) returns a Constructor<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.

like image 185
polygenelubricants Avatar answered Nov 28 '25 11:11

polygenelubricants



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!