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

2

13

(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?

Flatfoot answered 18/11, 2011 at 22:48 Comment(0)
D
5

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>?

Devanagari answered 18/11, 2011 at 23:43 Comment(3)
Class<T> may not have such methods that actually use any superclass of T, but, representing a type itself, it does claim to provide information about super types. If you look at Class's getSuperclass() method, it's return type is Class<? super T>. This being the case, it seems even more appropriate for getInterfaces() to return similarly to me. If they were thinking, as you suggest, that Class would never use any of those methods accessible by allowing the bounded wildcard, why would Class provide a superclass being specified as <? super T>?Flatfoot
It's probably a mistake by API designer. I'm arguing that it doesn't matter anyway.Devanagari
I've added a concrete case of using Class in this manner. It is in the quest itself now.Flatfoot
C
0

Again, let's say that you have this generic method declaration:

A non-array example

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

And you have these variable declarations:

Integer anInteger Number aNumber Object anObject String aString

Your intention with <T super Integer> (if it's legal) is that it should allow add(anInteger), and add(aNumber), and of course add(anObject), but NOT add(aString). Well, String is an Object, so add(aString) would still compile anyway.

copy from : Stack Overflow - Bounding generics with 'super' keyword

It helped me. May help u too :)

Coffey answered 29/1, 2018 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.