使用通用集合

3

它成功编译并且运行顺利!

List a=new ArrayList<String>();
a.add(new Integer(5));

有人能解释这个吗?

6个回答

6
原因是您将变量a声明为一个原始列表,即没有任何关联类型的列表(List):
List a = new ArrayList<String>();

事实上,即使这样也可以编译和运行:

List a = new ArrayList<Date>();
a.add(new Integer(5));

关于泛型和类型擦除的说明:

Java编译器通过一种称为擦除的前端转换来实现泛型。 类型擦除适用于泛型的使用。当使用泛型时,它们被转换为编译时检查和运行时类型转换。

由于类型擦除机制,这段代码:

List<String> a = new ArrayList<String>();
a.add("foo");
String x = a.get(0);

编译后会生成:

List a = new ArrayList();
a.add("foo");
String x = (String) a.get(0);

同样地,你的代码:
List a = new ArrayList<String>();
a.add(new Integer(5));

由于类型擦除的缘故,这段代码将被编译为以下形式:

List a = new ArrayList();
a.add(new Integer(5));

因此不会生成编译时或运行时错误。
但是当您尝试从列表中获取项目时,您将注意到差异:
int i = a.get(0); // compilation error due to type mismatch

由于您的列表被声明为原始类型,因此出现了这种情况。为避免此错误,您需要使用泛型声明列表,或者像上面那样进行类型转换。
即:要么在列表中使用通用类型,要么进行类型转换。
List<Integer> a = new ArrayList<Integer>();
a.add(new Integer(5));    
int i = a.get(0);

否则可以使用强制类型转换:(不推荐使用
List a=new ArrayList<Date>();
a.add(new Integer(5));
int i = (Integer) a.get(0);

提示: 注意,在运行时无法找到声明列表对象所使用的特定类型,例如String。


1
您在实际定义中没有指定通用类型。
如果您编写了:
List<String> a = new ArrayList<String>();
a.add(new Integer(5));

不会编译。

我知道了,谢谢。我在想为什么它没有抛出任何异常。 - Chuck Worker
它没有异常地运行,因为ArrayList在底层使用Object[]来存储数据,而Integer是Object的子类。 - David Xu

1

你应该这样做

List<String> a = new ArrayList<String>();
a.add(new Integer(5));
  • 列表意味着编译器将检查是否只添加了String对象到集合中。

有人能解释一下吗?

这是可能的,因为

  • 由于类型擦除,在运行时没有类型安全性
  • 语句List a表示在列表中添加哪些对象没有进行编译时检查。

自Java 7以来,您不必为了类型安全而编写List<String> a = new ArrayList<String>()。您可以简单地使用钻石操作符并使用List<String> a = new ArrayList();实现相同的效果。


1
< p > 列表a是一种不带泛型的原始类型。这也是您能够向其中添加整数的确切原因。

为了强制执行正确的行为,请将列表更改为使用泛型。

List<String> a

1
编译后,通用数据将被清除。这意味着:
List<String> a=new ArrayList<String>();

将被更改为您在类文件中看到的内容

List a=new ArrayList();

现在回答你的问题,a 的类型是 List,它是一个原始列表,你可以向其中添加任何内容。泛型存在是为了实现编译时限制。这意味着,假设你有...
List<String> a=new ArrayList<String>();

这行代码将会在编译时出现错误

a.add(new Integer(1)); //error

1
这是因为旧的遗留代码允许将任何东西(除了基本类型)放入集合中。为了支持遗留代码,Java 5和Java 6允许您的新类型安全代码使用旧代码。 因此,即使您的代码调用接受非类型安全参数并对其进行任何操作的旧类的方法,Java 5或Java 6编译器也会强制让您编译新的类型安全代码。 事实上,编译器会警告您。编译器从编译中生成了一个完全有效的类文件,但它很友好地告诉您,用自己的话说,“我真的希望您知道自己在做什么,因为这个旧代码没有尊重(甚至不知道)您的 <String> 类型,并且可以随意对您珍贵的 ArrayList<String> 进行任何操作。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接