为什么数组不能赋值给 Iterable?

用 Java5我们可以写:

Foo[] foos = ...
for (Foo foo : foos)

或者只是在 for 循环中使用 Iterable。

然而,你不能像下面这样为迭代编写一个通用的方法:

public void bar(Iterable<Foo> foos) { .. }

并使用数组调用它,因为它不是 Iterable:

Foo[] foos = { .. };
bar(foos);  // compile time error

我想知道这个设计决定背后的原因。

54015 次浏览

不幸的是,数组不够“ class-enough”,它们不实现 Iterable接口。

虽然数组现在是实现 Clable 和 Serializable 的对象,但是我相信 数组不是一般意义上的对象并没有实现接口。

之所以可以在 for-each 循环中使用它们,是因为 Sun 为数组添加了一些语法糖(这是一个特例)。

由于数组最初是 Java1中的“几乎是对象”,因此在 Java 中将它们改为 真的对象将是一个过于激烈的变化。

数组可以实现接口(Cloneablejava.io.Serializable)。那为什么不用 Iterable呢?我猜想 Iterable强制添加一个 iterator方法,而数组不实现方法。char[]甚至不能覆盖 toString。无论如何,引用的数组应该被认为比理想的使用 List的数组要少。作为 dfa 注释,Arrays.asList将显式地为您执行转换。

(尽管如此,您还是可以在数组上调用 clone。)

数组应该支持 Iterable,但是它们不支持 Iterable。NET 数组不支持允许按位置只读随机访问的接口(没有定义为标准的接口)。基本上,框架中经常有恼人的小缺口,这不值得任何人花时间去修复。如果我们能够以某种最佳方式自己修复它们,那也无关紧要,但通常我们做不到。

为了公平起见,我提到。NET 数组不支持支持按位置随机访问的接口(请参阅我的评论)。但是在。NET 4.5已经定义了精确的接口,并得到了数组和 List<T>类的支持:

IReadOnlyList<int> a = new[] {1, 2, 3, 4};
IReadOnlyList<int> b = new List<int> { 1, 2, 3, 4 };

所有这些还不够完美,因为可变的列表接口 IList<T>不继承 IReadOnlyList<T>:

IList<int> c = new List<int> { 1, 2, 3, 4 };
IReadOnlyList<int> d = c; // error

也许有一个可能的向下兼容抓住了你这样的变化。

如果在 Java 的新版本中有类似的进展,我很想在评论中知道!:)

数组是一个 Object,但它的项可能不是。数组可能包含类似 int 的基本类型,Iterable 无法处理这种类型。至少我是这么想的。

编译器实际上将数组上的 for each转换为带有计数器变量的简单 for循环。

编译以下代码

public void doArrayForEach() {
int[] ints = new int[5];


for(int i : ints) {
System.out.println(i);
}
}

然后反编译. class 文件的结果

public void doArrayForEach() {
int[] ints = new int[5];
int[] var2 = ints;
int var3 = ints.length;


for(int var4 = 0; var4 < var3; ++var4) {
int i = var2[var4];
System.out.println(i);
}
}