原始类型总是不好的吗?

Are raw types always bad?

Effective Java 的第 23 条(不要在新代码中使用原始类型)声称在 java 代码中使用原始类型总是危险的

比如声称以下方法危险不安全

// Use of raw type for unknown element type - don't do this!
static int numElementsInCommon(Set s1, Set s2) {
    int result = 0;
    for (Object o1 : s1)
        if (s2.contains(o1))
            result++;
    return result;
}

虽然,我可以看到对 s1 和 s2 进行任何类型的写操作或 class 转换操作都会导致各种异常,但我不明白为什么上述方法不安全。作者 Joshua Bloch 继续推荐以下方法。

// Unbounded wildcard type - typesafe and flexible
static int numElementsInCommon(Set<?> s1, Set<?> s2){
  int result = 0;
  for (Object o1 : s1)
    if (s2.contains(o1))
        result++;
  return result;
}

换句话说,如果一个方法只使用Object.Class的方法,不对传递的参数做任何修改,为什么不好呢?

从某种意义上说,这很糟糕,因为它会阻止编译器对您的更多代码进行类型检查。

当然,没有它你也可以写出好的和安全的代码。人们每天都用 Perl 和 Javascript 来做这件事。即使在 Java 中,使用原始类型和在运行时 使用类型化集合 之间也没有区别。但是,让编译器尽可能多地为您检查是有道理的。

因此,使用您示例中的方法,使用通配符类型 (Set<?>) 而不是原始类型。那样的话,如果你确实写了 "dangerous" 像 s1.addAll(s2); 这样的代码,编译器就会对你大喊大叫。