Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么数组不能分配给Iterable?_Java_Language Design - Fatal编程技术网

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

Java 为什么数组不能分配给Iterable?,java,language-design,Java,Language Design,使用Java5,我们可以编写: Foo[] foos = ... for (Foo foo : foos) 或者只是在for循环中使用Iterable。这很方便 但是,您不能像这样为iterable编写通用方法: public void bar(Iterable<Foo> foos) { .. } 我想知道这一设计决策背后的原因。不幸的是,数组“不够”类。他们没有实现Iterable接口 虽然数组现在是实现可克隆和可序列化的对象,但我相信数组不是正常意义上的对象,也不实现接口

使用Java5,我们可以编写:

Foo[] foos = ...
for (Foo foo : foos) 
或者只是在for循环中使用Iterable。这很方便

但是,您不能像这样为iterable编写通用方法:

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

我想知道这一设计决策背后的原因。

不幸的是,数组“不够”
类。他们没有实现
Iterable
接口

虽然数组现在是实现可克隆和可序列化的对象,但我相信数组不是正常意义上的对象,也不实现接口

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


由于数组一开始是Java 1中的“几乎是对象”,因此在Java中使它们成为真正的对象的变化太大了。

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


(话虽如此,您可以在数组上调用
clone

数组应该支持
Iterable
,它们只是不支持,原因与.NET数组不支持允许按位置进行只读随机访问的接口相同(没有定义为标准的此类接口)。基本上,框架中经常有令人讨厌的小缺口,不值得任何人花时间来修复。如果我们能以某种最佳的方式自己修复它们,这并不重要,但通常我们不能

更新:为了公平起见,我提到了.NET阵列不支持支持按位置随机访问的接口(另请参见我的评论)。但是在.NET 4.5中,已经定义了确切的接口,并且由数组和
列表
类支持:

IReadOnlyList<int> a = new[] {1, 2, 3, 4};
IReadOnlyList<int> b = new List<int> { 1, 2, 3, 4 };
IReadOnlyList a=new[]{1,2,3,4};
IReadOnlyList b=新列表{1,2,3,4};
由于可变列表接口IList
没有继承
IReadOnlyList
,所以还不是很完美:

IList c=新列表{1,2,3,4};
IReadOnlyList d=c;//错误
也许有一个可能的向后兼容性,有这样的变化


如果在较新版本的Java中有类似的进展,我很想在评论中了解!)

数组是一个对象,但其项可能不是。数组可能包含像int这样的基本类型,Iterable无法处理。至少我是这么认为的。

编译器实际上将数组中每个
转换为一个简单的
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);
    }
}
public void doArrayForEach(){
int[]ints=新的int[5];
int[]var2=int;
int var3=int.length;
for(int var4=0;var4
for-each循环仍然有糖,为什么不能有糖用于Iterable?@mmyers:for-each中使用的糖是编译时糖。这比VM糖容易多了。已经说过,.NET阵列在这方面明显更好…阵列可以实现接口。它们实现
Cloneable
Serializable
接口。请消除那一点误传。它们只是没有实现Iterable。数组是一个对象。它支持有用的:P方法,如wait()、wait(n)、wait(n,m)、notify()、notifyAll()、finalize(),toString()的一个无意义实现唯一有用的方法是getClass()。Arrays.asList足够好了,我想这是一个哲学问题Java 5+中处理数组的一个很好的理由是varargs方法。@Torsten:true,但是,如果将其传递给接受Iterable的方法,则可能不会进行任何更改。实际上,Arrays.asList不够好,因为它不适用于基元类型的数组。通用迭代(装箱)基元类型元素的唯一内置方法是使用反射,使用
java.lang.reflect.Array
,但其性能较弱。但是,如果需要,您可以编写自己的迭代器(或列表实现!)来包装基元类型的数组。这意味着为了支持
Iterable
接口,基元数组必须专用于使用包装类。但这些都不是什么大问题,因为类型参数都是假的。这不会阻止对象数组实现Iterable。它也不会阻止基元数组为包装类型实现Iterable。自动装箱可以处理这个问题。我认为这是正确的原因。除非泛型支持基元类型(例如,
List
而不是
List
等),否则它对基元类型数组的效果不会令人满意。可以使用包装器进行黑客攻击,但会导致性能损失——更重要的是——如果进行了这种黑客攻击,它将阻止将来在Java中正确实现它(例如
int[])。迭代器()
将永远锁定为返回
iterator
,而不是
iterator
)。也许,即将到来的Java值类型+泛型专门化(project valhalla)将使数组实现
Iterable
。NET数组实现IListinterface@Aphid-我说的是只读随机访问<代码>IList
公开用于修改的操作。如果
IList
继承了像
IReadonlyList
接口这样的东西,那就太好了,它只需要
Count
T this[int]
和继承的
IEnumerable
public void doArrayForEach() {
    int[] ints = new int[5];

    for(int i : ints) {
        System.out.println(i);
    }
}
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);
    }
}