开发者

Reflection problem - Type Safety Warning

开发者 https://www.devze.com 2023-01-01 07:33 出处:网络
Class<? extends Algorithm> alg = AlgorithmAllFrom9AndLastFrom10Impl.class Constructor<Algorithm> c = alg.getConstructors()[0];
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 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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消