分配给泛型类型的Java原始类型值运行时getClss()方法错误

时间:2017-08-18 12:51:18

标签: java generics casting runtime

#fecf0f

此代码给出了运行时错误:

public class Box<T> {
    private T t;
    public Box(T t){
        this.t = t;
    }
    public void add(T t) {
      this.t = t;
    }
    public T get() {
      return t;
    }
    public static void main(String[] args) {
      Box<Integer> b = new Box(new String("may be"));
      System.out.println(b.get()); // successfully print out "may be"
      System.out.println(b.get().getClass()); // error
   }
}
  1. 为什么exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 没有触发运行时错误?
  2. 为什么只有在我尝试获取类变量的类时才会发生运行时错误?
  3. 更确切地说:为什么编译器将b.get()指令插入 second checkcast的字节码 (导致例外)?

4 个答案:

答案 0 :(得分:2)

请注意:

  • 在第一种情况下,get()的结果用于println(Object):换句话说:接收方需要一个对象,并且“条件”将始终为真。
  • 在第二种情况下,将对返回的对象进行方法调用。现在,如果返回的类型是预期,则可以产生巨大差异。因此,编译器正在添加此检查以保证以下方法调用声音

作为背景,可以查看Java语言规范,第5.52章:

  

演员表是经过检验的演员。

     

此类演员需要运行时有效性检查。如果运行时的值为null,则允许转换。否则,令R为运行时引用值引用的对象的类,并且让T为转换运算符中指定的类型的擦除(第4.6节)。强制转换必须在运行时通过§5.5.3中的算法检查类R是否与类型T兼容。

分别为第5.53章Checked Casts at Run Time

答案 1 :(得分:2)

此变量声明不一致。

  Box<Integer> b = new Box(new String("may be")); :

实例化对象是原始对象,因此编译器会发出警告,但允许将原始类型分配给通用变量:Box<Integer>

b.get()不会因为您没有将结果分配给变量而失败。
因此,编译器不需要将其转换为任何内容。

试试:

Integer value = b.get();

它将编译正常,但您将在运行时获得相同的异常 JVM将尝试将值转换为Integer

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

当您调用时:

System.out.println(b.get().getClass()); // error

事情已接近。

为什么此处需要Integer课程?

在编译时,b被声明为Box<Integer> b 因此,编译器知道b参数化为Integer类型 所以在编译之后是,擦除了泛型,但编译器根据声明的代码添加了一些强制转换。

这就是这种情况。
您对使用getClass()参数化的变量调用Integer
Class是一个通用类:Class<T>。因此,编译器添加了对Integer的强制转换以符合Class<Integer>

当然,通过将泛型用于变量声明和实例化:

  Box<Integer> b = new Box<>(new String("may be"));

这种不一致是不可能的,因为编译器现在停止了你。

答案 2 :(得分:1)

除了这里的答案之外,字节指令checkcast在类型为Object的typechecks上被调用。例如

 public static void main(String[] args) {
          Box<Integer> b = new Box(new String("may be"));
          doStuff(b.get()); // no checkcast needed - works fine
          doIntegerStuff(b.get()); // run-time error with checkcast
          doStringStuff(b.get()); // compile error
       }

 public static void doStuff(Object object){}
 public static void doStringStuff(String integer){}
 public static void doIntegerStuff(Integer integer){}

答案 3 :(得分:-1)

代码行Box<Integer> b = new Box(new String("may be")); 在创建新的Box对象时,缺少类型Info,并假定为默认的Object类。

Box<String> b = new Box<>(new String());这是正确的方法

--------添加了--------

Object类的方法getClass()中返回运行时Class对象。并且在返回时,您的代码Box<Integer>会使getClass()方法返回Class<Integer>而不是Class<String>

你给了new B(new String());的原始类型,所以编译器传递了语法,但在调用getClass()时,它将内部对象String强制转换为Integer并抛出RuntimeException