Dlaczego Java API używa int
, kiedy short
lub w ogóle byte
byłoby wystarczające?
Przykład: DAY_OF_WEEK
pole w klasie Calendar
używa int
.
Jeśli różnica jest zbyt minimalna, to dlaczego te typy danych ( short
, int
) w ogóle istnieją?
źródło
Dlaczego Java API używa int
, kiedy short
lub w ogóle byte
byłoby wystarczające?
Przykład: DAY_OF_WEEK
pole w klasie Calendar
używa int
.
Jeśli różnica jest zbyt minimalna, to dlaczego te typy danych ( short
, int
) w ogóle istnieją?
Niektóre z powodów zostały już wskazane. Na przykład fakt, że „... (prawie) wszystkie operacje na bajcie, short będą promować te prymitywy do int” . Jednak oczywiste następne pytanie brzmiałoby : DLACZEGO te typy są promowane int
?
A więc, aby przejść o jeden poziom głębiej: odpowiedź może być po prostu związana z zestawem instrukcji wirtualnej maszyny języka Java. Jak podsumowano w tabeli w specyfikacji wirtualnej maszyny języka Java , wszystkie integralne operacje arytmetyczne, takie jak dodawanie, dzielenie i inne, są dostępne tylko dla typu int
i typu long
, a nie dla mniejszych typów.
(Na marginesie: mniejsze typy ( byte
i short
) są w zasadzie przeznaczone tylko dla tablic . Tablica taka new byte[1000]
zajmie 1000 bajtów, a tablica taka new int[1000]
zajmie 4000 bajtów)
Teraz, oczywiście, można by powiedzieć, że „... oczywistym następnym pytaniem byłoby: DLACZEGO te instrukcje są oferowane tylko dla int
(i long
)?” .
Jeden powód jest wymieniony w specyfikacji JVM wspomnianej powyżej:
Gdyby każda wpisana instrukcja obsługiwała wszystkie typy danych czasu wykonywania wirtualnej maszyny języka Java, byłoby więcej instrukcji niż można by przedstawić w bajcie
Ponadto wirtualną maszynę Javy można uznać za abstrakcję prawdziwego procesora. Wprowadzenie dedykowanej arytmetycznej jednostki logicznej dla mniejszych typów nie byłoby warte wysiłku: wymagałoby to dodatkowych tranzystorów, ale nadal mogłoby wykonać tylko jeden dodatek w jednym cyklu zegara. Dominującą architekturą podczas projektowania maszyny JVM była architektura 32-bitowa, w sam raz dla wersji 32-bitowej int
. (Operacje wymagające long
wartości 64-bitowej są realizowane jako przypadek specjalny).
(Uwaga: ostatni akapit jest nieco uproszczony, biorąc pod uwagę możliwą wektoryzację itp., Ale powinien dać podstawowy pomysł bez zagłębiania się w tematy dotyczące projektowania procesorów)
EDYCJA: Krótki dodatek, skupiający się na przykładzie z pytania, ale w bardziej ogólnym sensie: można również zapytać, czy nie byłoby korzystne przechowywanie pól przy użyciu mniejszych typów. Na przykład można pomyśleć, że pamięć można zapisać, przechowując Calendar.DAY_OF_WEEK
jako plik byte
. Ale tutaj pojawia się format pliku klasy Java: wszystkie pola w pliku klasy zajmują co najmniej jeden „slot”, który ma rozmiar jeden int
(32 bity). („Szerokie” pola double
i long
zajmują dwa pola ). Tak jawne zadeklarowanie pola jako short
lub też byte
nie zapisałoby żadnej pamięci.
int
. Jeśli masz odniesienie do innej implementacji, zaktualizuję odpowiedź i odpowiednio wstawię link.(Prawie) Wszystkie operacje na
byte
,short
będą promować jeint
, np. Nie możesz napisać:Arytmetyka jest łatwiejsza i prosta w użyciu
int
, nie ma potrzeby rzucania.Pod względem przestrzeni robi to bardzo małą różnicę.
byte
ishort
skomplikowałoby sprawę, nie sądzę, aby ta mikro optymalizacja była tego warta, ponieważ mówimy o stałej liczbie zmiennych.byte
jest przydatna i przydatna podczas programowania urządzeń wbudowanych lub korzystania z plików / sieci. Również te prymitywy są ograniczone, a co, jeśli obliczenia mogą przekroczyć ich granice w przyszłości? Spróbuj pomyśleć o rozszerzeniuCalendar
klasy, które mogłoby spowodować powstanie większej liczby.Należy również pamiętać, że w ciągu 64-bitowych procesorów, mieszkańcy zostaną zapisane w rejestrach i nie będzie wykorzystywać żadnych zasobów, więc przy użyciu
int
,short
a inne prymitywy nie będzie żadnej różnicy w ogóle. Co więcej, wiele implementacji Java dopasowuje zmienne * (i obiekty).*
byte
ishort
zajmują taką samą przestrzeń, jakint
gdyby były zmiennymi lokalnymi, zmiennymi klas , a nawet zmiennymi instancji . Czemu? Ponieważ w (większości) systemach komputerowych adresy zmiennych są wyrównane , więc na przykład jeśli używasz jednego bajtu, w rzeczywistości otrzymasz dwa bajty - jeden na samą zmienną, a drugi na wypełnienie.Z drugiej strony, w tablicach
byte
weź 1 bajt,short
weź 2 bajty iint
weź 4 bajty, ponieważ w tablicach tylko początek i być może koniec muszą być wyrównane. Będzie to miało znaczenie, jeśli chcesz na przykład użyćSystem.arraycopy()
, wtedy naprawdę zauważysz różnicę w wydajności.źródło
Ponieważ operacje arytmetyczne są łatwiejsze w przypadku używania liczb całkowitych w porównaniu do krótkich. Załóżmy, że stałe były rzeczywiście modelowane przez
short
wartości. Wtedy musiałbyś użyć API w ten sposób:Zwróć uwagę na jawne odlewanie. Krótkie wartości są niejawnie promowane do
int
wartości, gdy są używane w operacjach arytmetycznych. (Na stosie operandów krótkie są nawet wyrażane jako liczby całkowite). Byłoby to dość kłopotliwe w użyciu, dlategoint
często preferowane są wartości dla stałych.W porównaniu z tym wzrost wydajności pamięci jest minimalny, ponieważ istnieje tylko ustalona liczba takich stałych. Mówimy o 40 stałych. Zmiana ich przechowywania z
int
nashort
byłaby bezpieczna40 * 16 bit = 80 byte
. Zobacz tę odpowiedź w celu uzyskania dalszych informacji.źródło
Gdybyś zastosował filozofię, w której stałe całkowe są przechowywane w najmniejszym typie, do którego pasują, Java miałby poważny problem: ilekroć programiści piszą kod przy użyciu stałych całkowitych, muszą zwracać szczególną uwagę na swój kod, aby sprawdzić, czy typ Stałe mają znaczenie, a jeśli tak, wyszukaj typ w dokumentacji i / lub wykonaj dowolne konwersje typów.
Więc teraz, kiedy nakreśliliśmy poważny problem, jakie korzyści możesz osiągnąć dzięki tej filozofii? Nie zdziwiłbym się, gdyby jedynym efektem tej zmiany, który można było zaobserwować w czasie wykonywania, byłby typ, jaki uzyskuje się, patrząc na stałą poprzez refleksję. (i oczywiście wszelkie błędy wprowadzane przez leniwych / nieświadomych programistów niepoprawnie uwzględniających typy stałych)
Ważenie za i przeciw jest bardzo łatwe: to zła filozofia.
źródło
Złożoność projektu maszyny wirtualnej jest funkcją tego, ile rodzajów operacji może ona wykonywać. Łatwiej jest mieć cztery implementacje instrukcji, takich jak „mnożenie” - po jednej dla 32-bitowej liczby całkowitej, 64-bitowej liczby całkowitej, 32-bitowej liczby zmiennoprzecinkowej i 64-bitowej liczby zmiennoprzecinkowej - niż dodatkowo do powyższego, wersje dla mniejszych typów numerycznych. Bardziej interesującym pytaniem projektowym jest, dlaczego powinny istnieć cztery typy, a nie mniej (wykonywanie wszystkich obliczeń całkowitych z 64-bitowymi liczbami całkowitymi i / lub wykonywanie wszystkich obliczeń zmiennoprzecinkowych z 64-bitowymi wartościami zmiennoprzecinkowymi). Powodem używania 32-bitowych liczb całkowitych jest to, że oczekiwano, że Java będzie działać na wielu platformach, na których 32-bitowe typy mogą być obsługiwane równie szybko jak 16-bitowe lub 8-bitowe, ale operacje na typach 64-bitowych byłyby zauważalne wolniej.tylko z typami 32-bitowymi.
Jeśli chodzi o wykonywanie obliczeń zmiennoprzecinkowych na wartościach 32-bitowych, zalety są nieco mniej oczywiste. Istnieje kilka platform, na których obliczenia takie jak
float a=b+c+d;
można wykonać najszybciej, konwertując wszystkie operandy na typ o większej precyzji, dodając je, a następnie konwertując wynik z powrotem na 32-bitową liczbę zmiennoprzecinkową w celu przechowywania. Istnieją inne platformy, na których wykonywanie wszystkich obliczeń przy użyciu 32-bitowych wartości zmiennoprzecinkowych byłoby bardziej wydajne. Twórcy Javy zdecydowali, że wszystkie platformy powinny działać w ten sam sposób i że powinni faworyzować platformy sprzętowe, dla których 32-bitowe obliczenia zmiennoprzecinkowe są szybsze niż dłuższe, mimo że ten poważnie zdegradowany komputer PC zarówno pod względem szybkości oraz precyzja obliczeń zmiennoprzecinkowych na typowym komputerze PC, a także na wielu komputerach bez jednostek zmiennoprzecinkowych. Zwróć uwagę, że w zależności od wartości b, c i d, używając obliczeń pośrednich o wyższej precyzji podczas obliczania wyrażeń, takich jak wyżej wymienionefloat a=b+c+d;
czasami daje wyniki, które są znacznie dokładniejsze niż w przypadku wszystkich pośrednich operandów obliczonych zfloat
precyzją, ale czasami daje wartość, która jest odrobinę mniej dokładna. W każdym razie Sun zdecydował, że wszystko należy zrobić w ten sam sposób i zdecydował się na użyciefloat
wartości o minimalnej precyzji .Zwróć uwagę, że podstawowe zalety mniejszych typów danych stają się widoczne, gdy duża ich liczba jest przechowywana razem w tablicy; nawet jeśli indywidualne zmienne o typach mniejszych niż 64-bitowe nie przynosiłyby korzyści, warto mieć tablice, które mogą przechowywać mniejsze wartości w bardziej zwarty sposób; posiadanie zmiennej lokalnej jako a
byte
zamiast anlong
oszczędza siedem bajtów; posiadanie tablicy 1 000 000 liczb oznacza każdą liczbę jakobyte
zamiast along
fale 7 000 000 bajtów. Ponieważ każdy typ tablicy musi obsługiwać tylko kilka operacji (w szczególności odczytywanie jednego elementu, przechowywanie jednego elementu, kopiowanie zakresu elementów w tablicy lub kopiowanie zakresu elementów z jednej tablicy do drugiej), dodatkowa złożoność posiadania więcej typy tablic nie są tak poważne, jak złożoność posiadania większej liczby typów dyskretnych wartości liczbowych, które można bezpośrednio wykorzystać.źródło
Właściwie byłaby niewielka przewaga. Jeśli masz
wtedy w typowej maszynie JVM zajmuje tyle samo miejsca, co klasa zawierająca pojedynczy plik
int
. Zużycie pamięci jest zaokrąglane do kolejnej wielokrotności 8 lub 16 bajtów (IIRC, to konfigurowalne), więc przypadki, w których są rzeczywiste oszczędności, są raczej rzadkie.Ta klasa byłaby nieco łatwiejsza w użyciu, gdyby odpowiednie
Calendar
metody zwracały plikbyte
. Ale nie ma takichCalendar
metod,get(int)
które tylko muszą zwrócić zint
powodu innych pól. Każda operacja na mniejszych typach awansuje doint
, więc potrzebujesz dużo rzucania.Najprawdopodobniej zrezygnujesz i przełączysz się na
int
setery, takie jakWtedy i tak
DAY_OF_WEEK
nie ma znaczenia.źródło