Class.asSubclass signature

后端 未结 3 1199
有刺的猬
有刺的猬 2021-02-05 10:03

my question is quite theoretic... This is the signature of Class.asSubclass (Javadoc):

public  Class asSubclass(Class clazz)         


        
3条回答
  •  一整个雨季
    2021-02-05 10:27

    In case of the return type Class. Lets first try understanding, the getClass signature:

    AbstractList ls = new ArrayList<>();
    Class x = ls.getClass();
    

    Now had the compiler allowed us to do:

    Class x = ls.getClass();
    

    This would have been wrong. Because at runtime, ls.getClass would be ArrayList.classand not AbstractList.class. Neither can ls.getClass return Class because lsis of type AbstractList<> and not Arraylist

    So the compiler, now says - Ok! I cant return Class nor can I return Class. But because I know ls is an AbstractList for sure, so the actual class object can only be a subtype of AbstractList. So Class is a very safe bet. Because of wild card: You cannot do:

    AbstractList ls = new ArrayList<>();
    Class x = ls.getClass();
    Class> xx = x;
    Class> xxx = x;
    

    The same logic applies to your question. say suppose it was declared as:

     public  Class asSubClass(Class c)
    

    The below would have compiled:

     List ls = new ArrayList<>();
     Class x = ls.getClass();
     Class aClass = x.asSubclass(AbstractList.class); //BIG ISSUE
    

    Above aClass at runtime is Class and not Class. So this should not be allowed!! Class is the best bet.



    The first thought I had on looking at the question was, why wasn't it declared as:

     public  Class asSubClass(Class c)
    

    it makes more sense to have a compile time restriction on the arguments I can pass. But the reason I think it was not preferred was - this would have broken the backward compatibility of pre-java5 code. For example, code such as below which compiled with pre-Java5 would no longer compile if it asSubClass was declared as shown above.

    Class x = List.class.asSubclass(String.class); //pre java5
    // this would have not compiled if asSubclass was declared above like
    

    Quick check:

        public static  Class asSubClaz(Class t, Class c){
            return t.asSubClass(c);
        }
        public static  Class asSubClazOriginal(Class t, Class c){
            return t.asSubClass(c);
        }
        asSubClazOriginal(List.class, String.class);
        asSubClaz(List.class, String.class); //error. So would have broken legacy code
    

    PS: For the edited question, on why asSubClass rather than cast? - Because cast is betrayal. For example:

    List ls = new ArrayList<>();
    Class x = ls.getClass();
    Class aClass = (Class) x;
    

    Above would always succeed because generics are erased. So its class cast to a class. But aClass.equals(ArrayList.class) would give false. So definitely cast is wrong. In case you need type safety, you can use asSubClaz above

提交回复
热议问题