为什么数组不能分配给Iterable?

时间:2009-07-21 15:49:21

标签: java language-design

使用Java5我们可以写:

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

或者只是在for循环中使用Iterable。这非常方便。

但是你不能像这样编写一个可迭代的泛型方法:

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

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

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

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

5 个答案:

答案 0 :(得分:70)

数组可以实现接口(Cloneablejava.io.Serializable)。那么为什么不Iterable?我猜Iterable强制添加iterator方法,而数组不实现方法。 char[]甚至不会覆盖toString。无论如何,引用数组应该被认为不太理想 - 使用List s。正如dfa评论,Arrays.asList将明确地为您进行转换。

(话虽如此,你可以在数组上调用clone。)

答案 1 :(得分:55)

数组是一个Object,但它的项可能不是。该数组可能包含像int这样的基本类型,Iterable无法应对。至少那是我认为的。

答案 2 :(得分:16)

数组应该支持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中类似的东西有任何进展,我有兴趣在评论中知道! :)

答案 3 :(得分:14)

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

虽然数组现在是实现Clonable和Serializable的对象,但我相信数组不是正常意义上的对象,并且不实现接口。

你可以在for-each循环中使用它们的原因是因为Sun在数组中添加了一些合成糖(这是一个特例)。

由于数组最初是用Java 1创建的“几乎对象”,因此在Java中使用真正的对象进行更改将非常激烈。

答案 4 :(得分:2)

编译器实际上将数组上的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);
    }
}