//: typeinfo/toys/GenericToyTest.java 
// Testing class Class. 
package typeinfo.toys; 
 
public class GenericToyTest { 
  public static void main(String[] args) throws Exception { 
    Class<FancyToy> ftClass = FancyToy.class; 
    // Produces exact type: 
    FancyToy fancyToy = ftClass.newInstance(); 
    Class<? super FancyToy> up = ftClass.getSuperclass(); 
    // This won’t compile: 
    // Class<Toy> up2 = ftClass.getSuperclass(); 
    // Only produces Object: 
    Object obj = up.newInstance(); 
  } 
} ///:~ 
If you get the superclass, the compiler will only  allow you to say that the superclass reference is "some class that is a superclass of  FancyToy " as seen in the expression Class <? super FancyToy >. It will not accept a declaration of  Class<Toy> . This seems a bit strange because  getSuperclass( ) returns the base class (not interface) and the compiler knows what that class is at compile time—in this case,  Toy.class , not just "some superclass of FancyToy." In any event, because of the vagueness, the return value of  up.newlnstance( ) is not a precise type, but just an Object.作者好像还是没有解释为什么程序中Class<Toy> up2 = ftClass.getSuperclass();这个不能编译通过的原因,好像是她自己也解释不好。请问是这样吗?该如何理解上述程序以及作者的阐述呢?麻烦大神们给予小弟一点指示~Java

解决方案 »

  1.   

    个人理解一下: Class<? super FancyToy>由于泛型比较暧昧, 所以newInstance()的时候,编译器可以返回Object对象,  但Class<Toy>泛型很确定, 所以JVM既不能返回Object 又不知道返回Toy的哪个子类对象,所有不允许.
      

  2.   

    终于找到那段中文了:如果你手头的是超类,那编译器将只允许你声明超类引用是“某个类,它是FancyToy的超类”,就像在表达式Class<? Super FancyToy>中所看到的,而不会接受Class<Toy>这样的声明。这看上去显得有些奇怪,因为getSuperClass()方法返回的是基类(不是接口),并且编译器在编译期就知道它是什么类型了——在本例中就是Toy.class——而不仅仅只是“某个类,它是FancyToy超类”。不管怎样,正是由于这种含糊性,up.newInstance()的返回值不是精确类型,而只是Object。
      

  3.   

    作者的确没有做出解释。我也没想出什么原因,同等大神给出最终解释。
    不过我也做出了一点点探索:
    这段代码要结合前面的一段“typeinfo/toys/ToyTest.java”以及泛型在Class中的运用来理解。带有泛型的class在有明确类型的情况下,newInstance返回的同样是明确类型的实例:
    Class<FancyToy> ftClass = FancyToy.class;
    FancyToy fancyToy = ftClass.newInstance;
    但是在遇到获取直接基类的情况下,却不能使用明确的泛型定义,只能是个范围声明:
    Class<? super FancyToy> up = ftClass.getSuperclass();
    ?表示不确定,那这个class的类型既然不确定,执行newInstance返回的也是不确定类型的对象,只能用Object类型的引用:
    Object obj = up.newInstance();
    类似这样的显示定义是编译不了的:
    Class<Toy> up2 = ftClass.getSuperclass();
    但是可以强制转换:
    Class<Toy> up2 = (Class<Toy>) ftClass.getSuperclass();
    这种转换是安全的,不会报错。起初我怀疑这么设计是因为编译器不知道ftClass的父类到底是谁,但java只是单继承,所以我怀疑可能是基于对父类的父类的考虑,但通过调试可得出结论:getSuperclass仅仅获取的是直接父类的class,因此证明了作者的结论:编译器其实是知道其父类类型的!但就是要保留这样一种模糊的声明方式,是为了日后扩展支持多继承吗?