9

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

我想知道这怎么可能发生,但在网上找不到任何东西。

情况就是这样:我正在Spring Data JPA 1.2.0使用JBoss EAP 6.0 Serverwith JRE 1.6.0_18-b07

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

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

但是是:

  @Query("select record from MyType record [...]" )
  public List<Date> getOrderDates(...);

因此,目的是加载日期列表java.util.Date

但是那个编码错误导致了以下结果:在运行时,实际上List<MyType>返回的是 a,即使方法的签名定义了一个List<Date>. 同样在我的模型中,一个属性List<Date>是/包含一个List<MyType>. 我调试了它,简直不敢相信自己的眼睛!MyType我什至可以将此列表的内容写入 JSP(我只认识到这种奇怪的行为,因为由于尝试键入 match from to时出现 Spring Expression Language 错误而无法再显示 JSP Date,这当然有坠毁)。

见鬼,我现在应该对 Java 的类型安全失去信心吗?

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

是否存在对此的解释?

我可以做些什么来解决这个问题还是这是一个普遍问题?也许是另一个版本的 JRE、JBOSS,...?

4

2 回答 2

10

我想知道这怎么可能发生,但在网上找不到任何东西。

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

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

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

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

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

于 2013-01-16T16:44:30.643 回答
5

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

问题是您的查询没有被编译,所以 Java 无法知道它将返回什么样的对象。为了避免这种行为,我总是为我的查询创建测试。

于 2013-01-16T16:51:05.993 回答