为什么这个转换为泛型类型参数有效?

时间:2015-07-23 16:50:00

标签: java generics

了解类型擦除,我认为this cast不会在运行时编译或工作:

public class GenericDatumReader<D> implements DatumReader<D> {
    ...
    @SuppressWarnings("unchecked")
    public D read(D reuse, Decoder in) throws IOException {
      return (D) read(reuse, actual, expected != null ? expected : actual, in);
    }

然而,它有效!

程序如何在运行时知道D是什么?

修改

我写了一个简单的测试:

  1 public class Main {                                                                                                                                                           
  2                                                                                                                                                                               
  3     public static class Something<D> {                                                                                                                                        
  4                                                                                                                                                                               
  5         private Object getObj() { return new Object(); }                                                                                                                      
  6         private String getStr() { return new String("hello"); }                                                                                                               
  7                                                                                                                                                                               
  8         public <D> D get(boolean str) {                                                                                                                                       
  9            return (D) (str ? getStr() : getObj());                                                                                                                            
 10         }                                                                                                                                                                     
 11     }                                                                                                                                                                         
 12                                                                                                                                                                               
 13     public static void main(String[] args) {                                                                                                                                  
 14         Something<String> something = new Something<>();                                                                                                                      
 15         String str = something.get(true);                                                                                                                                     
 16         String notStr = something.get(false);                                                                                                                                 
 17     }                                                                                                                                                                         
 18 } 

如果没有(D)强制转换,则无法编译:

Main.java:9: error: incompatible types: bad type in conditional expression
           return (str ? getStr() : getObj());
                               ^
    String cannot be converted to D
  where D is a type-variable:
    D extends Object declared in method <D>get(boolean)
Main.java:9: error: incompatible types: bad type in conditional expression
           return (str ? getStr() : getObj());
                                          ^
    Object cannot be converted to D
  where D is a type-variable:
    D extends Object declared in method <D>get(boolean)
2 errors

使用(D)演员,我只会获得一个未经检查的警告,但它会编译。但是,在运行时:

$ java Main
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
        at Main.main(Main.java:16)

1 个答案:

答案 0 :(得分:3)

这里有两个方面:

  1. 编译时:这是有效的,因为你在编译时唯一知道的DObject,所以返回的值实际上可能是{{}} {1}} - 编译器无法确定。
  2. 运行时:由于Java通过擦除实现泛型,因此泛型类型几乎完全是编译时的概念。这个方法实际上不知道D在运行时是什么,因此强制转换根本不做任何事情。如果非泛型方法将结果分配给运行时已知的某种类型(即非泛型),那么如果该对象的类型不正确,则可能会创建强制转换异常。