z Java5 możemy napisać:
Foo[] foos = ...
for (Foo foo : foos)
lub po prostu używając Iterable w pętli for. To jest bardzo przydatne.
Nie można jednak napisać ogólnej metody iterowalnej:
public void bar(Iterable<Foo> foos) { .. }
i wywoływanie go tablicą, ponieważ nie jest to Iterable:
Foo[] foos = { .. };
bar(foos); // compile time error
Zastanawiam się nad przyczynami tej decyzji projektowej.
java.lang.reflect.Array
, ale jego wydajność jest słaba. Możesz jednak pisać własne iteratory (lub implementacje List!), Aby zawijać tablice typów pierwotnych, jeśli chcesz.Odpowiedzi:
Tablice mogą implementować interfejsy (
Cloneable
ijava.io.Serializable
). Więc dlaczego nieIterable
? Myślę, żeIterable
wymusza dodanieiterator
metody, a tablice nie implementują metod.char[]
nawet nie zastępujetoString
. W każdym razie tablice referencji powinny być uważane za mniej niż idealne - użyjList
s. Jak komentuje dfa,Arrays.asList
zrobi to za Ciebie, jawnie.(Powiedziawszy to, możesz wywoływać
clone
tablice).źródło
Iterator<T>
wymaga równieżremove(T)
, choć wolno rzucaćUnsupportedOperationException
.java.lang.Object
.Tablica jest Obiektem, ale jej elementy mogą nie być. Tablica może zawierać prymitywny typ, taki jak int, z którym Iterable nie może sobie poradzić. Przynajmniej tak myślę.
źródło
Iterable
interfejs, pierwotne tablice muszą być wyspecjalizowane w użyciu klas opakowujących. Nie jest to jednak nic wielkiego, ponieważ parametry typu i tak są fałszywe.List<int>
ZamiastList<Integer>
itp.). Hack można zrobić z opakowania, ale ze stratą wydajności - i co ważniejsze - czy to hack, zostało zrobione, it'ld zapobiec wdrażaniu go poprawnie w języku Java w przyszłości (na przykładint[].iterator()
na zawsze zostać zablokowane, aby powrócićIterator<Integer>
zamiastIterator<int>
). Być może nadchodzące typy wartości + ogólna specjalizacja dla Java (projekt valhalla) wprowadzą tabliceIterable
.Tablice powinny obsługiwać
Iterable
, po prostu nie, z tego samego powodu, dla którego tablice .NET nie obsługują interfejsu, który umożliwia tylko losowy dostęp według pozycji (nie ma takiego interfejsu zdefiniowanego jako standard). Zasadniczo frameworki często mają irytujące małe luki, których naprawienie nie jest warte nikogo. Nie miałoby znaczenia, czy sami moglibyśmy je naprawić w optymalny sposób, ale często nie możemy.AKTUALIZACJA: Aby być zręcznym, wspomniałem o macierzach .NET, które nie obsługują interfejsu, który obsługuje losowy dostęp według pozycji (patrz także mój komentarz). Ale w .NET 4.5 ten interfejs został zdefiniowany i jest obsługiwany przez tablice i
List<T>
klasę:Wszystko wciąż nie jest do końca idealne, ponieważ interfejs listy zmiennych
IList<T>
nie dziedziczyIReadOnlyList<T>
:Być może istnieje taka gotowa kompatybilność wsteczna z taką zmianą.
Jeśli pojawią się jakieś postępy w podobnych sprawach w nowszych wersjach Javy, chciałbym wiedzieć w komentarzach! :)
źródło
IList<T>
ujawnia operacje modyfikacji. Byłoby wspaniale, gdybyIList<T>
odziedziczyła coś jakIReadonlyList<T>
interfejs, który właśnie miałCount
iT this[int]
i odziedziczonejIEnumerable<T>
(który już obsługuje wyliczanie tylko do odczytu). Kolejną świetną rzeczą byłby interfejs do uzyskiwania modułu wyliczającego w odwrotnym porządku, o któryReverse
metoda rozszerzenia mogłaby zapytać (podobnie jakCount
metoda rozszerzenia pyta się oICollection
jej optymalizację).IList
iICollection
od .NET 1.1IList<T>
iICollection<T>
od .NET 2.0. To kolejny przypadek, w którym Java jest daleko w tyle za konkurencją.IList
jest to, że nie dostarcza więcej zapytań o atrybuty. Powiedziałbym, że odpowiedni zestaw powinien zawierać IsUpdateable, IsResizable, IsReadOnly, IsFixedSize i ExistingElementsAreImmutable na początek. Pytanie, czy kod referencyjny może, bez rzutowania, modyfikować listę, jest odrębne od pytania, czy kod, który zawiera referencję do listy, której nie powinien modyfikować, może bezpiecznie udostępniać to odniesienie bezpośrednio z kodem zewnętrznym, czy też można bezpiecznie założyć, że jakiś aspekt listy nigdy się nie zmieni.Niestety tablice nie są „
class
wystarczające”. Nie implementująIterable
interfejsu.Podczas gdy tablice są teraz obiektami, które implementują Klonowalne i Serializowalne, uważam, że tablica nie jest obiektem w normalnym znaczeniu i nie implementuje interfejsu.
Powodem, dla którego można ich używać w pętlach dla każdej pętli, jest to, że Słońce dodało cukier syntetyczny do tablic (jest to szczególny przypadek).
Ponieważ tablice zaczęły się jako „prawie obiekty” w Javie 1, byłoby zbyt drastyczne zmiany, aby uczynić je prawdziwymi obiektami w Javie.
źródło
Cloneable
iSerializable
interfejsy.Kompilator faktycznie tłumaczy
for each
tablicę na prostąfor
pętlę ze zmienną licznika.Kompilowanie następujących
a następnie dekompilacja pliku .class daje
źródło