关于泛型和反射的Java基础知识

时间:2016-04-17 14:36:19

标签: java generics reflection

我有一个基本的java问题,因为我最近决定深入研究这门语言(我一直专注于C ++很长一段时间,并决定稍微扩展我的视野)。

假设我有一个名为BankAccount的类,我尝试在main中创建和对象,有什么区别:

Class baCls = BankAccount.class; 

Class<BankAccount> baCls = BankAccount.class;

每个案例中baCls的含义是什么?编译器输出是什么?

2 个答案:

答案 0 :(得分:4)

在这两种情况下,baCls都是对类BankAccount

的引用

泛型添加了编译时检查,但在运行时没有影响。

如果在IDE中使用javap -c -p或字节代码查看器,则可以看到生成的字节码。

答案 1 :(得分:0)

Peter Lawrey的回答解决了您的具体问题,但我认为它缺少一个重要的事实,即第二个案例为编译器提供了额外的宝贵信息。

不同之处在于第一种情况是原始类型

Class baCls = BankAccount.class;
     ^ Missing type parameters.

这有(至少)两种后果(这是使用原始类型的一般后果):

  1. 您无法调用Class.nextInstance()方法之类的生产者方法,并将结果分配给类型为BankAccount的引用而不进行强制转换:

    Class baCls = BankAccount.class;
    BankAccount instance = (BankAccount) baCls.newInstance(/* required args */);
    

    但是,在第二种情况下,您不需要演员,因为已知nextInstance方法将返回BankAccount的实例:

    Class<BankAccount> baClsSafe = BankAccount.class;
    BankAccount instance = baCls.newInstance(/* req args */);
    
  2. 如果要将这些内容放入集合中,则会失去类型安全性。例如:

    Class baCls = BankAccount.class;
    List<Class<String>> list = new ArrayList<>();
    list.add(baCls);  // Compiles fine.
    

    这看起来很好,但是如果您假设列表中的元素的类型正确,则会在以后遇到运行时异常:

    for (Class<String> clazz : list) {
      String instance = clazz.newInstance();  // ClassCastException.
    }
    

    因为instance实际上是BankAccount的一个实例(假设它有一个零参数构造函数)。

    在第二种情况下,您将永远无法将此项添加到列表中:

    Class<BankAccount> baCls = BankAccount.class;
    List<Class<String>> list = new ArrayList<>();
    list.add(baCls);  // Compiler error.
    
  3. 我建议您阅读有关原始类型的内容,例如:在generics tutorial,以及 Effective Java 2nd Ed 项目23&#34;不要在新代码中使用原始类型&#34;。