java.lang.Class generics and wildcards

谁说胖子不能爱 提交于 2019-11-28 00:47:04

问题


Why is is that the following code does not compile?

interface Iface<T> { }

class Impl<T> implements Iface<T> { }

class TestCase {
    static Class<? extends Iface<?>> clazz = Impl.class;
}

The error is

java: incompatible types: java.lang.Class<Impl> cannot be converted to java.lang.Class<? extends Iface<?>>

but I don't see why the wildcard doesn't capture.


回答1:


The subtyping relationship here is:

          Class<? extends Iface>
           ╱                  ╲
Class<? extends Iface<?>>   Class<Impl>

(Which I explained in my answer to 'Cannot convert from List<List> to List<List<?>>'.)

So essentially it doesn't compile because it's a sideways conversion.

If it's possible, you can do the casting I described over there:

(Class<? extends Iface<?>>)(Class<? extends Impl>)Impl.class

If you can't do the cast, then you probably just have to deal with a raw bounded Class<? extends Iface>. It's annoying primarily because of the warnings but it opens up the possibility for an error:

interface Iface<T> {
    void accept(T a);
}

class Impl2 implements Iface<String> {
    public void accept(String a) { }
}

class TestCase {
    static Class<? extends Iface> clazz = Impl2.class;

    public static void main(String[] args) throws Exception {
        // throws ClassCastException
        clazz.newInstance().accept(new Object());
    }
}

Unlikely to happen, but it depends on what you're doing I suppose.


I tend to think this is a problem with the Java type system.

  • Possibly there should be a special rule that a type argument ? extends T<?> contains a type argument ? extends T such that e.g. a Class<? extends T> converts to a Class<? extends T<?>>. This doesn't make sense from the perspective of the existing way that subtyping is defined (T is a supertype of T<?>) but it makes sense from the perspective of type safety.

  • Or e.g. List.class should be a Class<List<?>> instead of a Class<List>.

  • Or some other clever thing people smarter than me can think up.

The interesting thing about the ClassCastException I described above is that it's completely artificial. And in fact, preventing it with the unchecked cast causes a warning.

Just a sign that generics in Java are not done yet, I guess.




回答2:


Because of type-erasure, when you say Impl.class you get a Class<Impl>. That is, you can say

Class<Impl> clazz = Impl.class;

Generics are a compile time type-safety feature.



来源:https://stackoverflow.com/questions/30090242/java-lang-class-generics-and-wildcards

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!