int i = (int) new Object (); kompiluje się dobrze.
Sachin Verma
Odpowiedzi:
243
Generics w Javie jest konstrukcją całkowicie kompilującą się w czasie kompilacji - kompilator zamienia wszystkie ogólne zastosowania w rzutowania na odpowiedni typ. Ma to na celu zachowanie zgodności z poprzednimi wersjami środowiska wykonawczego JVM.
To:
List<ClassA> list =newArrayList<ClassA>();
list.add(newClassA());ClassA a = list.get(0);
zamienia się w (z grubsza):
List list =newArrayList();
list.add(newClassA());ClassA a =(ClassA)list.get(0);
Zatem wszystko, co jest używane jako ogólne, musi być konwertowane na Object (w tym przykładzie get(0)zwraca an Object), a typy pierwotne nie są. Dlatego nie można ich używać w ogólnych.
@DanyalAytekin - Tak naprawdę, generyczne Java nie są obsługiwane jak szablony C ++ w ogóle ...
Stephen C
20
Dlaczego kompilator Java nie może również umieścić pierwotnego typu przed użyciem? To powinno być możliwe, prawda?
vrwim
13
@vrwim - To może być możliwe. Ale to byłby po prostu cukier składniowy. Prawdziwy problem polega na tym, że generyczne Java z pudełkowymi operacjami pierwotnymi są stosunkowo drogie zarówno pod względem czasu, jak i przestrzeni w porównaniu z modelem C ++ / C # ... gdzie używany jest rzeczywisty typ pierwotny.
Stephen C,
6
@MauganRa tak, wiem, że mogę :) Stoję przy mym stanowisku, że to okropny projekt. Mam nadzieję, że zostanie to naprawione w java 10 (a przynajmniej tak słyszałem), a także funkcje wyższego rzędu. Nie cytuj mnie o tym.
Ced
4
@Ced w pełni zgadza się, że jest to zły projekt, który bez końca szkodzi początkującym i profesjonalistom
MauganRa
37
W Javie, generyczne działają w taki sposób, w jaki działają ... przynajmniej częściowo ... ponieważ zostały dodane do języka wiele lat po zaprojektowaniu języka 1 . Projektanci języków mieli ograniczone opcje generyczne, ponieważ musieli wymyślić projekt, który byłby wstecznie zgodny z istniejącym językiem i biblioteką klas Java .
Inne języki programowania (np. C ++, C #, Ada) pozwalają na stosowanie typów prymitywnych jako typów parametrów w rodzajach ogólnych. Ale drugą stroną tego procesu jest to, że implementacje generycznych (lub typów szablonów) takich języków zazwyczaj pociągają za sobą generowanie odrębnej kopii typu ogólnego dla każdej parametryzacji typu.
1 - Powodem, dla którego generycy nie zostali uwzględnieni w Javie 1.0, była presja czasu. Uważali, że muszą szybko wydać język Java, aby wypełnić nową szansę rynkową oferowaną przez przeglądarki internetowe. James Gosling stwierdził, że wolałby włączyć leki generyczne, gdyby mieli czas. Zgadłby ktoś, jak wyglądałby język Java, gdyby tak się stało.
W java generyczne są implementowane przy użyciu „Kasowania typu” dla kompatybilności wstecznej. Wszystkie typy ogólne są konwertowane na Object w czasie wykonywania. na przykład,
publicclassContainer<T>{private T data;public T getData(){return data;}}
Myślę, że pytanie brzmi „dlaczego”. Dlaczego leki generyczne wymagają obiektów? Konsensus wydaje się być taki, że jest to mniej wybór projektowy, a bardziej sprzyja zgodności wstecznej. Moim zdaniem, jeśli leki generyczne nie są w stanie poradzić sobie z prymitywami, oznacza to deficyt funkcjonalności. Na obecnym etapie wszystko dotyczące prymitywów musi być napisane dla każdego prymitywu: zamiast Komparatora <t, t> mamy Integer.compare (int a, int b), Byte.compare (bajt a, bajt b) itp. To nie jest rozwiązanie!
John P
1
Tak, generyczne w porównaniu z prymitywnymi typami byłoby koniecznością. Oto link do propozycji dotyczącej tego openjdk.java.net/jeps/218
crow
5
Zgodnie z Dokumentacją Java , zmienne typu ogólnego mogą być tworzone tylko z typami referencyjnymi, a nie pierwotnymi.
Obecna wymazana implementacja Java, która produkuje jedną klasę dla wszystkich instancji referencyjnych i nie obsługuje prymitywnych instancji. (Jest to tłumaczenie homogeniczne, a ograniczenie, że ogólne elementy języka Java mogą wykraczać poza typy referencyjne, wynika z ograniczeń tłumaczenia jednorodnego w odniesieniu do zestawu kodów bajtowych JVM, który używa różnych kodów bajtowych dla operacji na typach referencyjnych w porównaniu z typami pierwotnymi.) Jednak skasowane rodzaje ogólne w Javie zapewniają zarówno parametryczność behawioralną (metody ogólne), jak i parametryczność danych (instancje typu raw i symboli zastępczych typów ogólnych).
...
wybrano jednorodną strategię translacji, w której zmienne typu ogólnego są usuwane do granic możliwości, gdy są włączane do kodu bajtowego. Oznacza to, że niezależnie od tego, czy klasa jest ogólna, czy nie, nadal kompiluje się do pojedynczej klasy o tej samej nazwie i której podpisy są takie same. Bezpieczeństwo typu jest weryfikowane podczas kompilacji, a środowisko wykonawcze jest ograniczone przez ogólny system typów. To z kolei narzuciło ograniczenie, że generyczne mogą działać tylko nad typami referencyjnymi, ponieważ Object jest najbardziej ogólnym dostępnym typem i nie obejmuje typów pierwotnych.
Podczas tworzenia obiektu nie można podstawić typu pierwotnego parametrem typu. Z powodu tego ograniczenia jest to problem z implementacją kompilatora. Typy pierwotne mają własne instrukcje kodu bajtowego do ładowania i przechowywania na stosie maszyny wirtualnej. Dlatego nie jest niemożliwe skompilowanie prymitywnych rodzajów ogólnych w tych oddzielnych ścieżkach kodu bajtowego, ale komplikowałoby to kompilator.
Odpowiedzi:
Generics w Javie jest konstrukcją całkowicie kompilującą się w czasie kompilacji - kompilator zamienia wszystkie ogólne zastosowania w rzutowania na odpowiedni typ. Ma to na celu zachowanie zgodności z poprzednimi wersjami środowiska wykonawczego JVM.
To:
zamienia się w (z grubsza):
Zatem wszystko, co jest używane jako ogólne, musi być konwertowane na Object (w tym przykładzie
get(0)
zwraca anObject
), a typy pierwotne nie są. Dlatego nie można ich używać w ogólnych.źródło
W Javie, generyczne działają w taki sposób, w jaki działają ... przynajmniej częściowo ... ponieważ zostały dodane do języka wiele lat po zaprojektowaniu języka 1 . Projektanci języków mieli ograniczone opcje generyczne, ponieważ musieli wymyślić projekt, który byłby wstecznie zgodny z istniejącym językiem i biblioteką klas Java .
Inne języki programowania (np. C ++, C #, Ada) pozwalają na stosowanie typów prymitywnych jako typów parametrów w rodzajach ogólnych. Ale drugą stroną tego procesu jest to, że implementacje generycznych (lub typów szablonów) takich języków zazwyczaj pociągają za sobą generowanie odrębnej kopii typu ogólnego dla każdej parametryzacji typu.
1 - Powodem, dla którego generycy nie zostali uwzględnieni w Javie 1.0, była presja czasu. Uważali, że muszą szybko wydać język Java, aby wypełnić nową szansę rynkową oferowaną przez przeglądarki internetowe. James Gosling stwierdził, że wolałby włączyć leki generyczne, gdyby mieli czas. Zgadłby ktoś, jak wyglądałby język Java, gdyby tak się stało.
źródło
W java generyczne są implementowane przy użyciu „Kasowania typu” dla kompatybilności wstecznej. Wszystkie typy ogólne są konwertowane na Object w czasie wykonywania. na przykład,
będą widoczne w czasie wykonywania jako,
Kompilator jest odpowiedzialny za zapewnienie odpowiedniej obsady, aby zapewnić bezpieczeństwo typu.
stanie się
Teraz pytanie brzmi: dlaczego „Obiekt” jest wybierany jako typ w czasie wykonywania?
FYI: Projekt Valhalla próbuje rozwiązać powyższy problem.
źródło
Kolekcje są zdefiniowane tak, aby wymagały typu, który pochodzi
java.lang.Object
. Typy podstawowe po prostu tego nie robią.źródło
Zgodnie z Dokumentacją Java , zmienne typu ogólnego mogą być tworzone tylko z typami referencyjnymi, a nie pierwotnymi.
Ma to nastąpić w Javie 10 w ramach projektu Valhalla .
W artykule Briana Goetza o stanie specjalizacji
Istnieje doskonałe wyjaśnienie przyczyny, dla której rodzajowe nie były obsługiwane dla prymitywnych. I w jaki sposób zostanie zaimplementowany w przyszłych wydaniach Java.
...
źródło
Podczas tworzenia obiektu nie można podstawić typu pierwotnego parametrem typu. Z powodu tego ograniczenia jest to problem z implementacją kompilatora. Typy pierwotne mają własne instrukcje kodu bajtowego do ładowania i przechowywania na stosie maszyny wirtualnej. Dlatego nie jest niemożliwe skompilowanie prymitywnych rodzajów ogólnych w tych oddzielnych ścieżkach kodu bajtowego, ale komplikowałoby to kompilator.
źródło