【问题标题】:Java compiler ignores type safetyJava 编译器忽略类型安全
【发布时间】:2012-08-26 04:03:08
【问题描述】:
public class POJO<T> {

    private List<Integer> integer = new ArrayList<Integer>();

    public POJO() {
        integer.add(1);
        integer.add(2);
    }

    public List<Integer> getInteger() {
        return integer;
    }

    public static void main(String[] args) {
        POJO pojo = new POJO();
        List<String> integer = pojo.getInteger(); // No compile error?
        System.out.println(integer); // prints [1, 2]
    }
}

如何编译以下行:

List<String> integer = pojo.getInteger();

如果getInteger() 输入如下

public List<Integer> getInteger()

【问题讨论】:

  • 你的类声明没有意义:POJO&lt;DateOrString extends Date &amp; CharSequence&gt;---这将类型参数限制为 both DateCharSequence 的子类型,但来自其名称看来您期望它会允许两者中的 any
  • @MarkoTopolnik 如果 POJO 在没有泛型的情况下实例化,它可以工作。
  • @assylias 怎么会?在这种情况下,它会忽略 any 泛型类型信息,甚至那些与类的类型参数无关的信息?奇怪。
  • @assylias 检查了它,只是发出警告。不知道那件事。如果它是静态方法,那么它会发出错误。这不愧是Java Puzzler。
  • @MarkoTopolnik - 他们可能会写一整本书的仿制药难题:-(

标签: java oop generics types type-safety


【解决方案1】:

由于pojo 未声明为泛型

POJO pojo = new POJO();

编译器假定您在预通用代码中使用它。即在编写代码后添加泛型。所以当你这样做时

List<String> integer = pojo.getInteger(); 

您会收到警告而不是错误。

即如果类型是非泛型的,则所有泛型检查都将关闭,而不仅仅是那些与您未提供的类型相关的检查。我相信这是为了最大程度地向后兼容。

用于比较。

Map mapOfInteger = new Map(); // no generics
Set<String> entries = map.entrySet(); // gives a warning, not an error.

在此示例中,如果不是泛型,您可能希望 Set&lt;Entry&lt;K, V&gt;&gt; 变为 Set&lt;Entry&gt;,但编译器会退回到将类视为非泛型 Set

【讨论】:

  • 所以我们终于在POJOPOJO&lt;?&gt;之间有了一个明确的、清晰的区别。
  • 只有一条评论:您使用map.keySet() 的行不如原始示例强,其中该方法返回明确的List&lt;Integer&gt;keySet() 只返回Set&lt;K&gt;,所以没有提供K,这对我来说总是有意义的。这个更让人头疼。
  • @MarkoTopolnik entrySet() 是一个更好的例子。
  • @PeterLawrey 我喜欢它简洁明了,所以我找到了支持您声明的 JLS 参考 ;-)
【解决方案2】:

这是一个未经检查的分配,出于兼容性原因不被视为错误。

Interoperating with Legacy Code

实际上,分配是合法的,但会产生未经检查的警告。

【讨论】:

    【解决方案3】:

    我在JLS 4.8 中找到了支持@PeterLawrey 所说的话的参考:

    未从其超类或超接口继承的原始类型 C 的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 8.3 节)的类型是原始类型对应于 C 对应的泛型声明中擦除其类型的类型。

    因此,您的原始POJO 对象的所有实例方法都将被删除,包括那些不引用POJO&lt;T&gt;T 类型的方法,这意味着(JLS 4.6):

    [...] 方法的类型参数(第 8.4.4 节)和方法的返回类型(第 8.4.5 节)如果 [...] 方法的签名被删除,也会被删除。

    【讨论】:

      猜你喜欢
      • 2022-01-17
      • 2011-11-27
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 2013-09-10
      相关资源
      最近更新 更多