2010-03-24 17 views
87

Kolekcje Java przechowują tylko obiekty, a nie typy pierwotne; jednak możemy przechowywać klasy opakowania.Dlaczego kolekcje Java nie mogą bezpośrednio zapisywać typów pierwotnych?

Dlaczego to ograniczenie?

+2

Ograniczenie to jest zasysane, gdy mamy do czynienia z prymitywami i chcemy używać kolejki do wysyłania, a współczynniki wysyłania są bardzo szybkie. Mam teraz do czynienia z tym problemem autoboxingu, biorąc za dużo czasu. – JPM

Odpowiedz

73

Była to decyzja dotycząca projektowania w języku Java, którą niektórzy uważają za błąd. Kontenery: Obiekty i prymitywy nie pochodzą z Object.

Jest to jedno miejsce, które projektanci .NET uczyli się z JVM i zaimplementowali typy wartości i generyczne, dzięki czemu w wielu przypadkach boks jest eliminowany. W środowisku CLR standardowe pojemniki mogą przechowywać typy wartości jako część podstawowej struktury kontenera.

Java wybrał opcję dodania ogólnej obsługi w 100% w kompilatorze bez obsługi JVM. JVM jest tym, czym jest, nie obsługuje obiektu "nieobiektowego". Generics Java pozwala ci udawać, że nie ma opakowania, ale wciąż płacisz cenę wykonania boksu. Jest to WAŻNE w przypadku niektórych klas programów.

Boks to techniczny kompromis i wydaje mi się, że szczegóły implementacji przenikają do tego języka. Autoboxing jest przyjemnym cukrem syntaktycznym, ale nadal jest karą za wyniki. Jeśli w ogóle, chciałbym, aby kompilator ostrzegł mnie, gdy będzie autoboxes. (Z tego co wiem, może teraz, napisałem tę odpowiedź w 2010 roku).

dobre wyjaśnienie na SO o boksie: Why do some languages need Boxing and Unboxing?

i krytyki rodzajowych Java: Why do some claim that Java's implementation of generics is bad?

W obronie Java, nie jest łatwo spojrzeć wstecz i krytykować. Maszyna JVM przetrwała próbę czasu i jest dobrym wzornictwem pod wieloma względami.

+0

+1 dla typów wartości. – Thilo

+5

Nie pomyłka, starannie dobrany kompromis, który moim zdaniem bardzo dobrze służył Javie. – DJClayworth

+12

To było wystarczająco dużo pomyłki, że .NET dowiedział się od niego i zaimplementował autoboxing od samego początku, oraz generyczne na poziomie VM bez boksowania narzutowego. Własna próba korekty Java była tylko rozwiązaniem na poziomie składni, które wciąż cierpi z powodu uderzenia w autoboxing vs. bez boksowania. Implementacja języka Java wykazała słabą wydajność w przypadku dużych struktur danych. – codenheim

7

Istnieje koncepcja auto-boxing i automatycznego rozpakowywania. Jeśli spróbujesz zapisać int w List<Integer>, kompilator Java automatycznie przekonwertuje go na Integer.

+0

Myślę, że jego dodane po java 1.5 ..right? – JavaUser

+1

Autoboxing został wprowadzony w Javie 1.5 wraz z Generics. – Jeremy

+1

Ale to czas na kompilację; składnia cukru bez korzyści wydajności. Autobiorkę kompilatora Java, stąd kara za wydajność w porównaniu do implementacji VM, takich jak .NET, których generics nie obejmuje boksowania. – codenheim

3

To naprawdę nie jest ograniczenie?

Zastanów się, czy chcesz utworzyć kolekcję przechowującą wartości pierwotne. Jak napisałbyś kolekcję, która może przechowywać int, float lub char? Najprawdopodobniej skończysz z wieloma kolekcjami, więc będziesz potrzebować intlist i listy charytatywnej itp.

Korzystając z obiektowej natury Javy podczas pisania klasy kolekcji można przechowywać dowolny obiekt, więc potrzebujesz tylko jednego klasa kolekcji. Ta idea, polimorfizm, jest bardzo potężna i znacznie upraszcza projektowanie bibliotek.

+6

"Jak napisałbyś kolekcję, która może przechowywać int, float lub char?"- Z prawidłowo zaimplementowanymi generycznymi/szablonami takimi jak inne języki, które nie ponoszą kary za udawanie, że wszystko jest przedmiotem ... – codenheim

+0

Prawie nigdy w ciągu sześciu lat Java nie chciała przechowywać kolekcji prymitywów. Nawet w nielicznych przypadkach, w których mógłbym chciałem poświęcić dodatkowy czas, a koszty przestrzeni korzystania z obiektów referencyjnych były znikome, w szczególności uważam, że wiele osób myśli, że chcą Map , zapominając, że tablica bardzo ładnie to zrobi – DJClayworth

+0

@DJClayworth To działa tylko jeśli Kluczowe wartości nie są rozrzedzone, można oczywiście użyć tablicy pomocniczej do śledzenia kluczy, ale ma to swoje własne problemy: względnie wydajny dostęp wymagałby zachowania obu tablic posortowanych w oparciu o kolejność klawiszy, aby umożliwić wyszukiwanie binarne, co z kolei spowodowałoby niewspółmierne wstawianie i usuwanie, chyba że wstawienie/usunięcie jest tak ukształtowane, że wstawione elementy mogą skończyć się w tutaj wcześniej usunięty element był i/lub niektóre bufory są przeplatane w tablicach, itp. Są zasoby dostępne, ale byłoby miło mieć w samej Jawie. – JAB

9

Jest to kombinacja dwóch faktów:

  • Java prymitywne typy nie są odwołać typów (np int nie jest Object)
  • Java robi rodzajowych przy użyciu typu skasowaniu typów referencyjnych (np List<?> jest naprawdę List<Object> w czasie wykonywania)

Ponieważ oba te są prawdziwe, ogólne kolekcje Java nie mogą bezpośrednio zapisywać typów pierwotnych. Dla wygody, wprowadzono autoboxing, aby umożliwić pierwotne typy, które są automatycznie zapakowane jako typy odniesienia. Nie popełnij tego błędu, kolekcje wciąż przechowują odwołania do obiektów niezależnie.

Czy można tego uniknąć? Być może.

  • Jeśli int jest Object, to nie ma potrzeby typów nadwozi w ogóle.
  • Jeśli generics nie są wykonywane przy użyciu usuwania typu, to prymitywy mogły zostać użyte dla parametrów typu.
14

Sprawia realizacja łatwiejsze. Ponieważ prymitywy Java nie są uznawane za obiekty, należy utworzyć oddzielną klasę kolekcji dla każdego z tych elementów podstawowych (bez kodu szablonu do udostępnienia).

Możesz to zrobić, oczywiście, po prostu zobacz GNU Trove, Apache Commons Primitives lub HPPC.

O ile nie masz naprawdę dużych kolekcji, koszty dla owijki nie mają znaczenia dla ludzi do opieki (a kiedy masz naprawdę duże prymitywne kolekcje, możesz chcieć poświęcić wysiłek, aby przyjrzeć się użyciu/budowie wyspecjalizowanych struktura danych dla nich).

+0

dzięki za pradziadów apache commons i wzmianek o gnu. Przydatne linki –

0

Myślę, że możemy zobaczyć postęp w tej przestrzeni w JDK prawdopodobnie w Javie 10 na podstawie tego JEP - http://openjdk.java.net/jeps/218.

Jeśli chcesz uniknąć prymitywów bokserskie w kolekcjach dzisiaj, istnieje kilka alternatyw osobom trzecim. Oprócz wspomnianych wcześniej opcji stron trzecich dostępne są także Eclipse Collections, FastUtil i Koloboke.

Porównanie prymitywnych mapach został również opublikowany jakiś czas temu pod tytułem: Duży przegląd HashMap: JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove. Biblioteka kolekcji GS (Goldman Sachs) została przeniesiona do Eclipse Foundation i jest teraz kolekcjami Eclipse.

Powiązane problemy