如何在特定情况下Java不是类型安全的?

bra*_*eep 8 java java-ee spring-data-jpa

今天我发现了一个非常奇怪的JVM 行为,一个(通常是类型安全的)List<Date>确实List<MyObject>在运行时保持了!

我想知道怎么会发生,但在网络上找不到任何东西.

情况就是这样:我正在和Spring Data JPA 1.2.0一个人JBoss EAP 6.0 Server一起工作JRE 1.6.0_18-b07.

错误地,在Spring Data JPA Repository类中,@Query表达式中写入了错误的结果类型.应该是:

  @Query("select distinct trunc(record.orderDateTime) from MyType record [...]" )
  public List<Date> getOrderDates(...);
Run Code Online (Sandbox Code Playgroud)

但是:

  @Query("select record from MyType record [...]" )
  public List<Date> getOrderDates(...);
Run Code Online (Sandbox Code Playgroud)

因此,目的是加载一个日期(java.util.Date)列表,如果在第一个代码片段中正确定义了查询,该列表工作正常.

但是编码错误导致了以下结果:在运行时,实际上List<MyType>返回了WAS ,即使方法的签名定义了一个List<Date>.同样在我的模型List<Date>中,a/的属性包含a List<MyType>.我调试了它,无法相信我的眼睛!我甚至可以写这个列表的JSP的内容(我只认识到了这个怪异的行为,因为JSP不能显示任何更由于春季表达式语言错误与试图从类型匹配存在的MyTypeDate,这当然有坠毁).

天哪,我现在应该放弃对Java类型安全性的信任吗?

有没有人遇到过这样的问题?

是否存在对此的解释?

我可以做任何事情来解决这个问题,还是一般问题?也许是另一个版本的JRE,JBOSS,......?

Jon*_*eet 9

我想知道怎么会发生,但在网络上找不到任何东西.

之所以发生这种情况,是因为泛型主要是仅编译时功能.元数据是根据类的类型参数,字段等来维护的......但是在执行时,类型参数(大部分)都会丢失.例如:

Object x = new ArrayList<String>();
Object y = new ArrayList<Integer>();
System.out.println(x.getClass() == y.getClass()); // True
Run Code Online (Sandbox Code Playgroud)

JVM无法区分 - 这就是为什么当您尝试强制转换时会收到警告的原因:

// At execution time, this cast will *really* only check for List
List<String> dodgyCast = (List<String>) y;
Run Code Online (Sandbox Code Playgroud)

大多数情况下,编译器使用泛型保持"常规"代码安全.但是当你有像ORM这样的东西通过反射或动态字节代码提供值时,所有这些安全性就会消失.


Cae*_*alf 5

可悲的是,由于类型擦除,可能会发生这种情况.您在集合中设置的类型仅在编译时检查,而不是在运行时检查.

问题是您的查询未编译,因此Java无法知道它将返回哪种对象.为了避免这种行为,我总是创建我的查询测试.