Java Language
Prymitywne typy danych
Szukaj…
Wprowadzenie
byte
, short
, int
, long
, char
, boolean
, float
i double
to typy, które przechowują najbardziej surowe dane liczbowe w programach Java.
Składnia
int aInt = 8; // Część definiująca (liczbowa) tej deklaracji int nazywana jest literałem.
int hexInt = 0x1a; // = 26; Możesz zdefiniować literały z wartościami szesnastkowymi poprzedzonymi 0x .
int binInt = 0b11010; // = 26; Możesz także zdefiniować literały binarne; z prefiksem 0b .
długi goodLong = 10000000000L; // Domyślnie literały całkowite są typu int. Dodając literę L na końcu literału, informujesz kompilator, że literał jest długi. Bez tego kompilator wygenerowałby błąd „Zbyt duża liczba całkowita”.
double aDouble = 3,14; // Literały zmiennoprzecinkowe są domyślnie typu double.
float aFloat = 3.14F; // Domyślnie ten literał byłby podwójny (i spowodowałby błąd „Niezgodne typy”), ale dodając F mówimy kompilatorowi, że jest zmiennoprzecinkowy.
Uwagi
Java ma 8 pierwotnych typów danych , a mianowicie boolean
, byte
, short
, char
, int
, long
, float
i double
. (Wszystkie pozostałe typy są typami referencyjnymi . Obejmuje to wszystkie typy tablic oraz wbudowane typy obiektów / klasy, które mają szczególne znaczenie w języku Java; np. String
, Class
and Throwable
i jego podklasy.)
W wyniku wszystkich operacji (dodawanie, odejmowanie, mnożenie, etc.) na pierwotnym typu jest przynajmniej int
, co dodanie short
do short
wytwarza int
, podobnie jak dodanie byte
do byte
, lub char
do char
. Jeśli chcesz przypisać wynik z powrotem do wartości tego samego typu, musisz go rzutować. na przykład
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
Brak rzutowania spowoduje błąd kompilacji.
Wynika to z następującej części specyfikacji języka Java, §2.11.1 :
Kompilator koduje mnóstwo literalnych wartości typów
byte
ishort
za pomocą instrukcji wirtualnej maszyny Java, które rozszerzają te wartości na wartości typuint
w czasie kompilacji lub w czasie wykonywania. Mnóstwo wartości literałów typuboolean
ichar
są kodowane za pomocą instrukcji, które zerują literał do wartości typuint
w czasie kompilacji lub w czasie wykonywania. [..]. Dlatego większość operacji na wartościach rzeczywistych typów typuboolean
,byte
,char
ishort
są poprawnie wykonywane przez instrukcje działające na wartościach typu obliczeniowegoint
.
Powód tego jest również określony w tej sekcji:
Biorąc pod uwagę jednobajtowy rozmiar kodu operacyjnego maszyny wirtualnej Java, kodowanie typów w opcodes wywiera presję na projekt zestawu instrukcji. Jeśli każda wpisana instrukcja obsługiwałaby wszystkie typy danych w czasie wykonywania wirtualnej maszyny Java, byłoby więcej instrukcji niż można by przedstawić w
byte
. [...] W razie potrzeby można użyć osobnych instrukcji do konwersji między nieobsługiwanymi i obsługiwanymi typami danych.
Int pierwotny
Prymitywny typ danych, taki jak int
przechowuje wartości bezpośrednio do zmiennej, która go używa, tymczasem zmienna zadeklarowana za pomocą Integer
przechowuje odwołanie do wartości.
Według java API : „Klasa Integer otacza wartość pierwotnego typu int obiektem. Obiekt typu Integer zawiera pojedyncze pole, którego typem jest int.”
Domyślnie int
jest 32-bitową liczbą całkowitą ze znakiem. Może przechowywać minimalną wartość -2 31 i maksymalną wartość 2 31-1 .
int example = -42;
int myInt = 284;
int anotherInt = 73;
int addedInts = myInt + anotherInt; // 284 + 73 = 357
int subtractedInts = myInt - anotherInt; // 284 - 73 = 211
Jeśli chcesz zapisać liczbę spoza tego zakresu, zamiast tego należy użyć wartości long
. Przekroczenie zakresu wartości int
prowadzi do przepełnienia liczby całkowitej, powodując dodanie wartości przekraczającej zakres do przeciwnego miejsca zakresu (dodatnia staje się ujemna i odwrotnie). Wartość wynosi ((value - MIN_VALUE) % RANGE) + MIN_VALUE
lub ((value + 2147483648) % 4294967296) - 2147483648
int demo = 2147483647; //maximum positive integer
System.out.println(demo); //prints 2147483647
demo = demo + 1; //leads to an integer overflow
System.out.println(demo); // prints -2147483648
Maksymalne i minimalne wartości int
można znaleźć na:
int high = Integer.MAX_VALUE; // high == 2147483647
int low = Integer.MIN_VALUE; // low == -2147483648
Domyślna wartość int
to 0
int defaultInt; // defaultInt == 0
Krótki prymityw
short
to 16-bitowa liczba całkowita ze znakiem. Ma minimalną wartość -2 15 (-32 768) i maksymalną wartość 2 15 ‑1 (32 767)
short example = -48;
short myShort = 987;
short anotherShort = 17;
short addedShorts = (short) (myShort + anotherShort); // 1,004
short subtractedShorts = (short) (myShort - anotherShort); // 970
Maksymalne i minimalne wartości short
można znaleźć na:
short high = Short.MAX_VALUE; // high == 32767
short low = Short.MIN_VALUE; // low == -32768
Domyślna wartość short
to 0
short defaultShort; // defaultShort == 0
Długi prymityw
Domyślnie long
jest 64-bitową liczbą całkowitą ze znakiem (w Javie 8 może być podpisany lub niepodpisany). Podpisany, może przechowywać minimalną wartość -2 63 , a maksymalną wartość 2 63-1 , a bez znaku może przechowywać minimalną wartość 0 i maksymalną wartość 2 64-1
long example = -42;
long myLong = 284;
long anotherLong = 73;
//an "L" must be appended to the end of the number, because by default,
//numbers are assumed to be the int type. Appending an "L" makes it a long
//as 549755813888 (2 ^ 39) is larger than the maximum value of an int (2^31 - 1),
//"L" must be appended
long bigNumber = 549755813888L;
long addedLongs = myLong + anotherLong; // 284 + 73 = 357
long subtractedLongs = myLong - anotherLong; // 284 - 73 = 211
Maksymalne i minimalne wartości long
można znaleźć na:
long high = Long.MAX_VALUE; // high == 9223372036854775807L
long low = Long.MIN_VALUE; // low == -9223372036854775808L
Domyślną wartością long
jest 0L
long defaultLong; // defaultLong == 0L
Uwaga: litera „L” dołączona na końcu long
literału nie uwzględnia wielkości liter, jednak dobrą praktyką jest stosowanie kapitału, ponieważ łatwiej jest odróżnić go od cyfry:
2L == 2l; // true
Ostrzeżenie: Java buforuje instancje obiektów liczb całkowitych z zakresu od -128 do 127. Rozumowanie wyjaśniono tutaj: https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof
Można znaleźć następujące wyniki:
Long val1 = 127L;
Long val2 = 127L;
System.out.println(val1 == val2); // true
Long val3 = 128L;
Long val4 = 128L;
System.out.println(val3 == val4); // false
Aby poprawnie porównać 2 wartości Długości obiektu, użyj następującego kodu (od Java 1.7 i nowszych):
Long val3 = 128L;
Long val4 = 128L;
System.out.println(Objects.equal(val3, val4)); // true
Porównanie długiej prymitywnej z długością obiektu nie da fałszywego negatywu, jak w przypadku porównania 2 obiektów z ==.
Prymityw boolowski
boolean
może przechowywać jedną z dwóch wartości, true
lub false
boolean foo = true;
System.out.println("foo = " + foo); // foo = true
boolean bar = false;
System.out.println("bar = " + bar); // bar = false
boolean notFoo = !foo;
System.out.println("notFoo = " + notFoo); // notFoo = false
boolean fooAndBar = foo && bar;
System.out.println("fooAndBar = " + fooAndBar); // fooAndBar = false
boolean fooOrBar = foo || bar;
System.out.println("fooOrBar = " + fooOrBar); // fooOrBar = true
boolean fooXorBar = foo ^ bar;
System.out.println("fooXorBar = " + fooXorBar); // fooXorBar = true
Domyślna wartość boolean
to false
boolean defaultBoolean; // defaultBoolean == false
Prymityw bajtów
byte
to 8-bitowa liczba całkowita ze znakiem. Może przechowywać minimalną wartość -2 7 (-128) i maksymalną wartość 2 7-1 (127)
byte example = -36;
byte myByte = 96;
byte anotherByte = 7;
byte addedBytes = (byte) (myByte + anotherByte); // 103
byte subtractedBytes = (byte) (myBytes - anotherByte); // 89
Maksymalne i minimalne wartości byte
można znaleźć na:
byte high = Byte.MAX_VALUE; // high == 127
byte low = Byte.MIN_VALUE; // low == -128
Domyślna wartość byte
to 0
byte defaultByte; // defaultByte == 0
Prymityw pływaka
Liczba float
to 32-bitowa liczba float
z pojedynczą precyzją IEEE 754. Domyślnie dziesiętne są interpretowane jako liczby podwójne. Aby utworzyć liczbę float
, po prostu dodaj f
do literału dziesiętnego.
double doubleExample = 0.5; // without 'f' after digits = double
float floatExample = 0.5f; // with 'f' after digits = float
float myFloat = 92.7f; // this is a float...
float positiveFloat = 89.3f; // it can be positive,
float negativeFloat = -89.3f; // or negative
float integerFloat = 43.0f; // it can be a whole number (not an int)
float underZeroFloat = 0.0549f; // it can be a fractional value less than 0
Pływaki obsługują pięć typowych operacji arytmetycznych: dodawanie, odejmowanie, mnożenie, dzielenie i moduł.
Uwaga: Poniższe informacje mogą się nieznacznie różnić w wyniku błędów zmiennoprzecinkowych. Niektóre wyniki zostały zaokrąglone w celu zachowania przejrzystości i czytelności (tzn. Wydrukowany wynik z przykładu dodania wynosił w rzeczywistości 34.600002).
// addition
float result = 37.2f + -2.6f; // result: 34.6
// subtraction
float result = 45.1f - 10.3f; // result: 34.8
// multiplication
float result = 26.3f * 1.7f; // result: 44.71
// division
float result = 37.1f / 4.8f; // result: 7.729166
// modulus
float result = 37.1f % 4.8f; // result: 3.4999971
Ze względu na sposób przechowywania liczb zmiennoprzecinkowych (tj. W postaci binarnej) wiele liczb nie ma dokładnej reprezentacji.
float notExact = 3.1415926f;
System.out.println(notExact); // 3.1415925
Podczas korzystania float
jest w porządku dla większości zastosowań, ani float
ani double
powinien być używany do przechowywania dokładnych reprezentacji liczb dziesiętnych (np kwot pieniężnych) lub numery, gdzie wymagana jest większa precyzja. Zamiast tego należy użyć klasy BigDecimal
.
Domyślna wartość liczb float
to 0,0f .
float defaultFloat; // defaultFloat == 0.0f
Liczba float
jest dokładna do błędu około 1 na 10 milionów.
Uwaga: Float.POSITIVE_INFINITY
, Float.NEGATIVE_INFINITY
, Float.NaN
są wartościami float
. NaN
oznacza wyniki operacji, których nie można ustalić, takich jak podzielenie 2 wartości nieskończonych. Ponadto 0f
i -0f
są różne, ale ==
daje true:
float f1 = 0f;
float f2 = -0f;
System.out.println(f1 == f2); // true
System.out.println(1f / f1); // Infinity
System.out.println(1f / f2); // -Infinity
System.out.println(Float.POSITIVE_INFINITY / Float.POSITIVE_INFINITY); // NaN
Podwójny prymityw
double
to 64-bitowa liczba zmiennoprzecinkowa IEEE 754 o podwójnej precyzji.
double example = -7162.37;
double myDouble = 974.21;
double anotherDouble = 658.7;
double addedDoubles = myDouble + anotherDouble; // 315.51
double subtractedDoubles = myDouble - anotherDouble; // 1632.91
double scientificNotationDouble = 1.2e-3; // 0.0012
Ze względu na sposób przechowywania liczb zmiennoprzecinkowych wiele liczb nie ma dokładnej reprezentacji.
double notExact = 1.32 - 0.42; // result should be 0.9
System.out.println(notExact); // 0.9000000000000001
Podczas gdy używanie double
jest dobre dla większości aplikacji, nie należy używać liczb float
ani double
do przechowywania dokładnych liczb, takich jak waluta. Zamiast tego należy użyć klasy BigDecimal
Domyślna wartość double
to 0.0d
public double defaultDouble; // defaultDouble == 0.0
Uwaga: Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, Double.NaN
są double
wartościami. NaN
oznacza wyniki operacji, których nie można ustalić, takich jak podzielenie 2 wartości nieskończonych. Ponadto 0d
i -0d
są różne, ale ==
daje true:
double d1 = 0d;
double d2 = -0d;
System.out.println(d1 == d2); // true
System.out.println(1d / d1); // Infinity
System.out.println(1d / d2); // -Infinity
System.out.println(Double.POSITIVE_INFINITY / Double.POSITIVE_INFINITY); // NaN
Prymityw char
char
może przechowywać jeden 16-bitowy znak Unicode. Dosłowny znak jest ujęty w pojedyncze cudzysłowy
char myChar = 'u';
char myChar2 = '5';
char myChar3 = 65; // myChar3 == 'A'
Ma minimalną wartość \u0000
(0 w postaci dziesiętnej, zwanej także znakiem pustym ) i maksymalną wartość \uffff
(65 535).
Domyślna wartość char
to \u0000
.
char defaultChar; // defaultChar == \u0000
W celu zdefiniowania wartości znaku '
char '
użyć sekwencji specjalnej (znak poprzedzony odwrotnym ukośnikiem):
char singleQuote = '\'';
Istnieją również inne sekwencje specjalne:
char tab = '\t';
char backspace = '\b';
char newline = '\n';
char carriageReturn = '\r';
char formfeed = '\f';
char singleQuote = '\'';
char doubleQuote = '\"'; // escaping redundant here; '"' would be the same; however still allowed
char backslash = '\\';
char unicodeChar = '\uXXXX' // XXXX represents the Unicode-value of the character you want to display
Możesz zadeklarować char
dowolnego znaku Unicode.
char heart = '\u2764';
System.out.println(Character.toString(heart)); // Prints a line containing "❤".
Możliwe jest również dodanie do char
. np. aby iterować każdą małą literę, możesz wykonać następujące czynności:
for (int i = 0; i <= 26; i++) {
char letter = (char) ('a' + i);
System.out.println(letter);
}
Reprezentacja wartości ujemnej
Java i większość innych języków przechowują ujemne liczby całkowite w reprezentacji zwanej notacją dopełniacza 2 .
Dla unikalnej reprezentacji binarnej typu danych przy użyciu n
bitów wartości są kodowane w następujący sposób:
Najmniej znaczące n-1
bity przechowują dodatnią liczbę całkowitą x
w reprezentacji całkowej. Większość sklepów znacznej wartości nieco wartość vith s
. Wartość powtarzana przez te bity to
x - s * 2 n-1
tzn. jeśli najbardziej znaczącym bitem jest 1, to wartość jest tylko o 1 większa niż liczba, którą możesz reprezentować za pomocą innych bitów ( 2 n-2 + 2 n-3 + ... + 2 1 + 2 0 = 2 n-1 - 1
) jest odejmowane, umożliwiając unikalną reprezentację binarną dla każdej wartości od - 2 n-1 (s = 1; x = 0) do 2 n-1 - 1 (s = 0; x = 2 n-1 - 1).
Ma to również ładny efekt uboczny, polegający na tym, że można dodawać reprezentacje binarne tak, jakby były dodatnimi liczbami binarnymi:
v1 = x1 - s1 * 2n-1 v2 = x2 - s2 * 2n-1
s1 | s2 | Przepełnienie x1 + x2 | wynik dodania |
---|---|---|---|
0 | 0 | Nie | x1 + x2 = v1 + v2 |
0 | 0 | tak | za duży, aby można go było przedstawić za pomocą typu danych (przepełnienie) |
0 | 1 | Nie | x1 + x2 - 2n-1 = x1 + x2 - s2 * 2n-1 |
0 | 1 | tak | (x1 + x2) mod 2n-1 = x1 + x2 - 2n-1 |
1 | 0 | * | patrz wyżej (wymiany swapów) |
1 | 1 | Nie | za mały, aby można go było przedstawić za pomocą typu danych (x1 + x2 - 2 n <-2 n-1 ; niedomiar) |
1 | 1 | tak | (x1 + x2) mod 2n-1 - 2n-1 = (x1 + x2 - 2n-1) - 2n-1 |
Zauważ, że ten fakt ułatwia znalezienie binarnej reprezentacji odwrotności dodatku (tj. Wartości ujemnej):
Zauważ, że dodanie bitowego uzupełnienia do liczby powoduje, że wszystkie bity są 1. Teraz dodaj 1, aby przelać wartość i otrzymasz neutralny element 0 (wszystkie bity 0).
Tak więc wartość ujemną liczby i
można obliczyć za pomocą (ignorując możliwą promocję do int
tutaj)
(~i) + 1
Przykład: przyjmowanie wartości ujemnej 0 ( byte
):
Wynik zanegowania 0
wynosi 11111111
. Dodanie 1 daje wartość 100000000
(9 bitów). Ponieważ byte
może przechowywać tylko 8 bitów, lewa wartość jest obcinana, a wynik to 00000000
Oryginalny | Proces | Wynik |
---|---|---|
0 (00000000) | Negować | -0 (11111111) |
11111111 | Dodaj 1 do pliku binarnego | 100000000 |
100000000 | Obetnij do 8 bitów | 00000000 (-0 równa się 0) |
Zużycie pamięci przez operacje podstawowe a operacje podstawowe w pudełkach
Prymitywny | Rodzaj pudełka | Rozmiar pamięci pierwotnej / zapakowanej |
---|---|---|
boolean | Boolean | 1 bajt / 16 bajtów |
bajt | Bajt | 1 bajt / 16 bajtów |
krótki | Krótki | 2 bajty / 16 bajtów |
zwęglać | Zwęglać | 2 bajty / 16 bajtów |
int | Liczba całkowita | 4 bajty / 16 bajtów |
długo | Długo | 8 bajtów / 16 bajtów |
pływak | Pływak | 4 bajty / 16 bajtów |
podwójnie | Podwójnie | 8 bajtów / 16 bajtów |
Obiekty w pudełkach zawsze wymagają 8 bajtów do zarządzania typami i pamięcią, a ponieważ rozmiar obiektów jest zawsze wielokrotnością 8, wszystkie typy w pudełkach wymagają łącznie 16 bajtów . Ponadto każde użycie obiektu w pudełku pociąga za sobą przechowywanie odwołania, które stanowi kolejne 4 lub 8 bajtów, w zależności od opcji JVM i JVM.
W operacjach intensywnie wykorzystujących dane zużycie pamięci może mieć duży wpływ na wydajność. Zużycie pamięci rośnie jeszcze bardziej przy użyciu tablic: tablica float[5]
będzie wymagała tylko 32 bajtów; podczas gdy Float[5]
przechowujący 5 różnych wartości innych niż null będzie wymagał łącznie 112 bajtów (w 64 bitach bez skompresowanych wskaźników, zwiększa się to do 152 bajtów).
Buforowane wartości pudełkowe
Narzuty przestrzenne typów pudełkowych można do pewnego stopnia ograniczyć dzięki pamięci podręcznej wartości pudełkowej. Niektóre typy pudełkowe implementują pamięć podręczną instancji. Na przykład domyślnie klasa Integer
będzie buforować instancje w celu reprezentowania liczb z zakresu od -128
do +127
. Nie zmniejsza to jednak dodatkowych kosztów wynikających z pośredniej pamięci dodatkowej.
Jeśli utworzysz wystąpienie typu pudełkowego albo przez autoboxing, albo przez wywołanie metody static valueOf(primitive)
, system wykonawczy spróbuje użyć wartości buforowanej. Jeśli aplikacja używa wielu wartości w zakresie buforowanym, może to znacznie zmniejszyć karę pamięci związaną z używaniem typów pudełkowych. Oczywiście, jeśli tworzysz instancje wartości w pudełku „ręcznie”, lepiej jest użyć valueOf
niż new
. ( new
operacja zawsze tworzy nową instancję). Jeśli jednak większość twoich wartości nie znajduje się w zbuforowanym zakresie, szybsze może być wywołanie new
i zapisanie wyszukiwania w pamięci podręcznej.
Konwertowanie prymitywów
W Javie możemy konwertować między wartościami całkowitymi a wartościami zmiennoprzecinkowymi. Ponadto, ponieważ każdy odpowiada postaci do liczby w kodowaniu Unicode char
typy mogą być przekształcone do i od liczby całkowite i zmiennoprzecinkowych. boolean
jest jedynym pierwotnym typem danych, którego nie można przekonwertować na ani z żadnego innego pierwotnego typu danych.
Istnieją dwa rodzaje konwersji: konwersja poszerzająca i konwersja zawężająca .
Konwersja rozszerzająca ma miejsce, gdy wartość jednego typu danych jest konwertowana na wartość innego typu danych, który zajmuje więcej bitów niż poprzedni. W tym przypadku nie ma problemu utraty danych.
Odpowiednio, zawężenie konwersji następuje, gdy wartość jednego typu danych jest konwertowana na wartość innego typu danych, który zajmuje mniej bitów niż poprzedni. W takim przypadku może wystąpić utrata danych.
Java automatycznie wykonuje konwersje rozszerzające . Ale jeśli chcesz wykonać zwężającą się konwersję (jeśli masz pewność, że nie nastąpi utrata danych), możesz zmusić Javę do wykonania konwersji za pomocą konstrukcji języka znanej jako cast
.
Poszerzenie konwersji:
int a = 1;
double d = a; // valid conversion to double, no cast needed (widening)
Zawężenie konwersji:
double d = 18.96
int b = d; // invalid conversion to int, will throw a compile-time error
int b = (int) d; // valid conversion to int, but result is truncated (gets rounded down)
// This is type-casting
// Now, b = 18
Cheatheet typów pierwotnych
Tabela przedstawiająca zakres wielkości i wartości wszystkich typów pierwotnych:
typ danych | reprezentacja numeryczna | Zakres wartości | domyślna wartość |
---|---|---|---|
boolean | nie dotyczy | fałszywe i prawdziwe | fałszywy |
bajt | 8-bitowy podpis | -2 7 do 2 7-1 | 0 |
-128 do +127 | |||
krótki | 16-bitowy podpisany | -2 15 do 2 15-1 | 0 |
-32 768 do +32 767 | |||
int | 32-bitowy podpisany | -2 31 do 2 31-1 | 0 |
-2 147 483 648 do +14 147 483 647 | |||
długo | 64-bitowy podpisany | -2 63 do 2 63-1 | 0L |
-9,223,372,036,854,775,808 do 9,223,372,036,854,775,807 | |||
pływak | 32-bitowy zmiennoprzecinkowy | 1.401298464e-45 do 3.402823466e + 38 (dodatnie lub ujemne) | 0,0 F. |
podwójnie | 64-bitowy zmiennoprzecinkowy | 4,94065645841246544e-324d do 1.79769313486231570e + 308d (dodatnie lub ujemne) | 0,0D |
zwęglać | 16-bit bez znaku | 0–2 16–1 | 0 |
Od 0 do 65 535 |
Uwagi:
- Specyfikacja języka Java nakazuje, aby podpisywać typy całkowite (
byte
dolong
) używają binarnej reprezentacji dwójkowej dopełniacza, a typy zmiennoprzecinkowe używają standardowych reprezentacji binarnych zmiennoprzecinkowych IEE 754. - Java 8 i nowsze wersje zapewniają metody wykonywania niepodpisanych operacji arytmetycznych na
int
ilong
. Chociaż metody te pozwalają programowi traktować wartości odpowiednich typów jako niepodpisane, typy pozostają typami podpisanymi. - Najmniejszy zmiennoprzecinkowy pokazany powyżej jest nienormalny ; tzn. mają mniejszą dokładność niż normalna wartość. Najmniejsze liczby normalne to 1,175494351e-38 i 2,2250738585072014e-308
-
char
zwykle oznacza Unicode / UTF-16 jednostki kodu. - Chociaż wartość
boolean
zawiera tylko jeden bit informacji, jej rozmiar w pamięci różni się w zależności od implementacji wirtualnej maszyny Java (patrz typ logiczny ).