Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does java.lang.Class's getInterfaces() method return Class<?>[] and not Class<? super T>[]?

(To clear up the question, 'T' refers to a type parameter declared in Class)

Just as an example, please review the following application:

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());
        }   
    }
}

The output is what one would expect:

TestClass$InterfaceA
TestClass$InterfaceB
TestClass$InterfaceC

So, based on this example above, we can see that the compiler recognizes that InterfaceA does meet the bounds of the wildcard , as do all of the other interfaces.

Intuitively, I would expect the following to be safe, but it is not:

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

The compiler gives a warning, because the signature says that it returns Class; however, the javadoc for Class states the following:

If this object represents a class, the return value is an array containing objects representing all interfaces implemented by the class.

'This object' refers in our case to ClassA. Based on this statement, if we call:

ClassA.class.getInterfaces()

then we know, logically, that every Class<?> in the returned array will contain a reference to a super type of ClassA.

As an additional point of reference:

From the Java Language Reference, Third Edition:

A class necessarily implements all the interfaces that its direct superclasses and direct superinterfaces do. This (multiple) interface inheritance allows objects to support (multiple) common behaviors without sharing any implementation.

Reading this and other parts of the specification, I would think that any class or interface implemented or exteneded by a class T would fall into the bounds <? super T>.

EDITED:

It has been suggested that there is no concrete reason for my question. I will provide an example:

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    }

The problem is at line 15. You have to cast to <? super W> to get the correct type. The compiler warning can be suppressed, but is it justified? Is there some scenario where this cast is not true?

like image 355
sager Avatar asked Nov 18 '11 22:11

sager


1 Answers

You are right, the return type could be more specific.

However, Class<? super X> isn't very useful anyway. Class<?> is enough for most usages.

If we have a declaration G<T>, for G<? super X> to be useful, usually G should have methods that accept T. For example, List<T> has add(T). So List<? super X> is useful, we can call add(x) on it (x being of type X)

Class doesn't have such methods.

Do you have a convincing use case that you really need Class<? super ClassA>?

like image 154
irreputable Avatar answered Oct 22 '22 13:10

irreputable