왜 배열을 Iterable에 할당 할 수 없습니까?


186

Java5를 사용하면 다음과 같이 작성할 수 있습니다.

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

또는 for 루프에서 Iterable을 사용하십시오. 이것은 매우 편리합니다.

그러나 다음과 같이 iterable에 대한 일반적인 메소드를 작성할 수 없습니다.

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

Iterable이 아니기 때문에 배열로 호출하십시오.

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

이 디자인 결정의 이유에 대해 궁금합니다.


8
Arrays.asList는 제가 생각하기에 충분합니다
dfa

17
그것은 철학적 인 질문이다
dfa

2
Java 5 이상에서 배열을 다루는 좋은 이유는 varargs 메소드입니다.
Jeff Walker

2
@ Torsten : true, 그러나 Iterable을 허용하는 메소드에 전달하면 어쨌든 변경되지 않을 것입니다.
Michael Myers

5
사실, Arrays.asList은 하지 가 원시적 형의 배열에 작동하지 않기 때문에 충분히 좋은. 기본 유형의 요소를 일반적으로 반복 (박스형)하는 기본 제공 방법은을 사용하는 리플렉션을 사용하는 java.lang.reflect.Array것이지만 성능은 약합니다. 그러나 원하는 경우 기본 유형의 배열을 래핑하기 위해 고유 한 반복자 (또는 목록 구현!)를 작성할 수 있습니다.
Boann

답변:


78

배열은 인터페이스 ( Cloneablejava.io.Serializable)를 구현할 수 있습니다 . 왜 안돼 Iterable? 필자 Iterableiterator메소드를 추가해야 한다고 생각 하고 배열은 메소드를 구현하지 않습니다. char[]재정의하지도 않습니다 toString. 어쨌든 참조 배열은 이상적인 용도보다 덜 고려되어야합니다 List. dfa 의견 Arrays.asList으로 명시 적으로 변환을 수행합니다.

(단, clone배열을 호출 할 수 있다고 말했습니다 .)


23
> "... 및 배열은 메소드를 구현하지 않습니다." 저는 이것이 또 다른 철학적 질문이라고 생각합니다. 배열은 원시적 유형이 아니었고 Java 철학은 "모든 것이 객체 (기본적 유형 제외)"라고 읽습니다. 그렇다면 처음부터 배열을 사용하려는 gazillion 연산이 있어도 배열이 메소드를 구현하지 않는 이유는 무엇입니까? 아, 맞습니다. 제네릭이 유감스러운 후시로 등장하기 전에 배열은 유일하게 강력한 형식의 컬렉션이었습니다.
fatuhoku

2
배열에 데이터가있는 경우 스트림에서 바이트 []의 읽기 처리와 같은 저수준의 성능이 중요한 작업을 수행 할 수 있습니다. 배열을 반복 할 수 없다는 것은 @Gareth가 아래에 설명하는 것처럼 기본 인수를 유형 인수로 지원하지 않는 Java 제네릭에서 비롯된 것입니다.
Drew Noakes

2
@FatuHoku 제네릭을 제안하는 것은 죄송합니다. 후시가 잘못되었습니다. 제네릭의 바람직 함은 항상 높이 평가되었습니다. 배열은 프리미티브가 아니지만 (저는 그렇게 말하지는 않았지만) 저수준입니다. 배열로하고 싶은 한 가지는 벡터와 같은 구조의 구현 세부 사항으로 사용하는 것입니다.
Tom Hawtin-tackline

1
Iterator<T>또한 remove(T)을 던질 수는 있지만 을 요구 합니다 UnsupportedOperationException.
wchargin

배열은 메소드를 구현합니다 java.lang.Object.의 모든 메소드를 구현합니다 .
mhsmith

59

배열이 Object이지만 해당 항목이 아닐 수 있습니다. 배열은 int와 같은 기본 유형을 보유 할 수 있으며 Iterable은 대처할 수 없습니다. 적어도 그것이 내가 생각하는 것입니다.


3
이는 Iterable인터페이스 를 지원하기 위해 래퍼 클래스를 사용하려면 기본 배열을 특수화해야합니다. 형식 매개 변수가 모두 가짜이기 때문에 이것 중 어느 것도 실제로 큰 문제는 아닙니다.
thejoshwolfe

8
이것은 Object 배열이 Iterable을 구현하는 것을 방해하지 않습니다. 또한 기본 배열이 랩 유형에 대해 Iterable을 구현하는 것을 막지 않습니다.
Boann

1
오토 박싱이이를 처리 할 수 ​​있음
Tim Büthe

이것이 올바른 이유라고 생각합니다. Generics가 프리미티브 유형을 지원할 때까지 (예 : List<int>대신 List<Integer>등) 프리미티브 유형의 배열에는 만족스럽지 않습니다 . 더 중요하고 - - 해킹이 래퍼로하지만 성능 손실에서 할 수있는이 해킹이 수행 된 경우, it'ld 미래에 제대로 자바를 실행 방지 (예를 들면 int[].iterator()영원히 돌아 잠겨 것 Iterator<Integer>보다는 Iterator<int>). 아마도, 다가오는 value-types + generic-specialization for Java (프로젝트 valhalla)는 배열을 구현할 것 Iterable입니다.
Bjarke

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에서 비슷한 일이 진행되면 의견을 알고 싶습니다. :)


8
.NET 어레이는 IList의 인터페이스 구현
톰 길렌

2
@ Aphid-나는 읽기 전용 랜덤 액세스를 말했다 . IList<T>수정 조작을 공개합니다. 있다면 그것은 좋은 것 IList<T>유사한 상속 뭔가했다 IReadonlyList<T>단지했을 것이다 인터페이스 CountT this[int]상속 IEnumerable<T>(이미 읽기 전용 열거를 지원하는 참조). 또 다른 좋은 점은 Reverse확장 방법이 쿼리 할 수 있는 역순 열거자를 얻기위한 인터페이스 일 것 입니다 ( Count확장 방법이 ICollection자체 최적화 를 요청 하는 것처럼 )
Daniel Earwicker

그렇습니다. 사물이 그렇게 설계되면 훨씬 좋습니다. IList 인터페이스는 IsReadOnly 및 IsFixedSize 속성을 정의하며,이 속성은 배열로 적절하게 구현됩니다. 주어진 목록이 실제로 읽기 전용인지 확인하는 컴파일 시간을 제공하지 않기 때문에 항상 나에게 매우 나쁜 방법이라고 생각했습니다. 그리고 이러한 속성을 확인하는 코드는 거의 볼 수 없습니다.
Tom Gillen

1
.NET에서 배열 구현 IListICollection.NET 1.1 이후, 그리고 IList<T>ICollection<T>.NET 2.0입니다. 이것은 Java가 경쟁에서 훨씬 뒤쳐지는 또 다른 경우입니다.
Amir Abiri

@ TomGillen : 내 가장 큰 문제 IList는 더 쿼리 가능한 속성을 제공하지 않는다는 것입니다. 적절한 세트에는 IsUpdateable, IsResizable, IsReadOnly, IsFixedSize 및 ExistingElementsAreImmutable이 포함되어야한다고 말하고 싶습니다. 타입 캐스팅없이 목록을 수정할 수있는 코드에 대한 질문은 수정하지 않아야하는 목록에 대한 참조를 보유한 코드가 외부 코드와 직접 참조를 안전하게 공유 할 수 있는지의 여부와는 별개입니다. 목록의 일부 측면이 절대 변경되지 않는다고 가정 할 수 있습니다.
supercat

14

불행히도, 배열은 ' class충분 하지'않습니다 . Iterable인터페이스를 구현하지 않습니다 .

배열은 이제 Clonable 및 Serializable을 구현하는 객체이지만 배열은 정상적인 의미의 객체 가 아니며 인터페이스를 구현하지 않는다고 생각합니다.

for-each 루프에서 사용할 수있는 이유는 Sun이 배열을 위해 일부 신택스 설탕을 추가했기 때문입니다 (특별한 경우입니다).

배열은 Java 1에서 '거의 객체'로 시작되었으므로 Java에서 실제 객체 로 만들기 위해 변경이 너무 과감 할 것 입니다.


14
아직도 for-each 루프에는 설탕이 있는데 왜 Iterable에 설탕이 없을까요?
Michael Myers

8
@mmyers : for-each에 사용되는 설탕은 컴파일 타임 설탕입니다. VM 설탕 보다 훨씬 쉽습니다 . .NET 어레이가이 분야에서 훨씬 더 우수하다고 말한 것은 ...
Jon Skeet

12
배열 인터페이스 구현할 수 있습니다. 그들은 구현 Cloneable하고 Serializable인터페이스합니다.
notnoop

34
자바 배열은 모든 의미에서 객체입니다. 잘못된 정보를 제거하십시오. Iterable을 구현하지 않습니다.
ykaganovich

5
배열은 객체입니다. 유용한 : : wait (), wait (n), wait (n, m), notify (), notifyAll (), finalize (), toString ()의 무의미한 구현과 같은 P 메소드를 지원 합니다 . 유용한 유일한 메소드는 getClass () .
Peter Lawrey

1

컴파일러는 실제로 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);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.