【问题标题】:Why does java.lang.Class's getInterfaces() method return Class<?>[] and not Class<? super T>[]?为什么 java.lang.Class 的 getInterfaces() 方法返回 Class<?>[] 而不是 Class<?超级T>[]?
【发布时间】:2011-11-18 22:48:24
【问题描述】:

(为了澄清问题,'T'指的是在Class中声明的类型参数)

仅作为示例,请查看以下应用程序:

public class TestClass {

    interface InterfaceA{}

    interface InterfaceB{}

    interface InterfaceC{}

    class ClassA implements InterfaceA, InterfaceB,  InterfaceC{}


    public static void main(String[] args){    

        Class<? super ClassA> superClass1 = ClassA.class;
        Class<? super ClassA> superclass2 = InterfaceA.class;
        Class<? super ClassA> superclass3 = InterfaceB.class;
        Class<? super ClassA> superclass4 = InterfaceC.class;

        for(Class<?> clazz : ClassA.class.getInterfaces()){
            System.out.println(clazz.getName());
        }   
    }
}

输出是预期的:

TestClass$InterfaceA
TestClass$InterfaceB
TestClass$InterfaceC

因此,根据上面的示例,我们可以看到编译器识别出 InterfaceA 确实 满足通配符的边界,所有其他接口也是如此。

直觉上,我希望以下内容是安全的,但事实并非如此:

Class<? super ClassA>[] interfaces = ClassA.class.getInterfaces();

编译器给出警告,因为签名说它返回Class;但是,Class 的 javadoc 声明如下:

如果这个对象代表一个类,返回值是一个数组 包含表示由 类。

'这个对象'在我们的例子中是指ClassA。基于这个陈述,如果我们调用:

ClassA.class.getInterfaces()

那么我们从逻辑上知道,返回数组中的每个Class&lt;?&gt; 都将包含对ClassA 超类型的引用。

作为附加参考点:

来自 Java 语言参考,第三版:

一个类必须实现它直接的所有接口 超类和直接超接口可以。这个(多个)接口 继承允许对象支持(多个)常见行为 不共享任何实现。

阅读规范的本部分和其他部分,我认为任何由类T 实现或扩展的类或接口都将落入&lt;? super T&gt; 的范围内。

已编辑:

有人认为我的问题没有具体原因。我举个例子:

1    import java.util.Map;
2    import java.util.HashMap;
3    
4    public class MapWrapper<T> {
5        private final Map<Class<?>, OtherClass<T,?>> map = new HashMap <Class<?>, OtherClass<T,?>>();
6    
7        public <W> void addToMap(Class<W> type, OtherClass<T,? super W> otherClass){
8            map.put(type, otherClass);
9        }
10    
11        public <W> OtherClass<T,? super W> getOtherClassForAnyInterface(Class<W> type){
12            if(type.getInterfaces()!=null){
13                for(Class<?> interfaceType : type.getInterfaces()){
14                    // Here, a cast is necessary.  It throws a compiler warning for unchecked operations (rightfully so)
15                    OtherClass<T,? super W> otherClass = (OtherClass<T,? super W>)getOtherClassForInterface(interfaceType);
16                    if(null!=otherClass){
17                        return otherClass;
18                    }
19                }
20            }
21            return null;
22        }
23    
24        
25        public class OtherClass<T,V> {}
26    
27    }

问题出在第 15 行。您必须强制转换为 &lt;? super W&gt; 才能获得正确的类型。编译器警告可以被抑制,但它是否合理?是否存在这种演员表不正确的情况?

【问题讨论】:

    标签: java generics interface bounded-wildcard


    【解决方案1】:

    你是对的,返回类型可以更具体。

    但是,Class&lt;? super X&gt; 无论如何都不是很有用。 Class&lt;?&gt; 对于大多数用途来说已经足够了。

    如果我们有一个声明G&lt;T&gt;,为了使G&lt;? super X&gt; 有用,通常G 应该有接受T 的方法。例如,List&lt;T&gt; 具有 add(T)。所以List&lt;? super X&gt; 很有用,我们可以在上面调用add(x)xX 类型)

    Class 没有这样的方法。

    您是否有一个令人信服的用例表明您确实需要Class&lt;? super ClassA&gt;

    【讨论】:

    • Class 可能没有实际使用 T 的任何超类的方法,但是,它代表一个类型本身,它确实声称提供有关超类型的信息。如果你查看 Class 的 getSuperclass() 方法,它的返回类型是Class&lt;? super T&gt;。在这种情况下,getInterfaces() 以类似方式返回给我似乎更合适。如果他们认为,正如您所建议的那样,Class 永远不会使用通过允许有界通配符访问的任何这些方法,为什么 Class 会提供一个指定为 &lt;? super T&gt; 的超类?
    • 这可能是API设计者的错误。我认为无论如何都无所谓。
    • 我添加了一个以这种方式使用 Class 的具体案例。它现在就在任务本身中。
    【解决方案2】:

    再一次,假设你有这个泛型方法声明:

    非数组示例

    <T super Integer> void add(T number) // hypothetical! currently illegal in Java

    你有这些变量声明:

    Integer anInteger Number aNumber Object anObject String aString

    您对&lt;T super Integer&gt;(如果合法)的意图是它应该允许add(anInteger)add(aNumber),当然还有add(anObject),但不允许add(aString)。好吧,String 是一个对象,所以add(aString) 仍然可以编译。

    复制自:Stack Overflow - Bounding generics with 'super' keyword

    它帮助了我。也可以帮助你:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      • 2011-05-26
      • 2018-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多