Cześć! W miarę postępów w CodeGym wielokrotnie napotykałeś prymitywne typy. Oto krótka lista tego, co o nich wiemy:
- Nie są obiektami i reprezentują wartość przechowywaną w pamięci
- Istnieje kilka rodzajów
- Liczby całkowite: byte , short , int , long
- Liczby zmiennoprzecinkowe (ułamkowe): float i double
- Wartości logiczne: logiczne
- Wartości symboliczne (do reprezentacji liter i cyfr): char
-
Każdy typ ma swój własny zakres wartości:
Typ pierwotny |
Rozmiar w pamięci |
Zakres wartości |
bajt |
8 bitów |
-128 do 127 |
krótki |
16 bitów |
-32768 do 32767 |
zwęglać |
16 bitów |
od 0 do 65536 |
int |
32 bity |
-2147483648 do 2147483647 |
długi |
64 bity |
-9223372036854775808 do 9223372036854775807 |
platforma |
32 bity |
(2 do potęgi -149) do ((2 - (2 do potęgi -23)) * 2 do potęgi 127) |
podwójnie |
64 bity |
(-2 do potęgi 63) do ((2 do potęgi 63) - 1) |
logiczna |
8 (gdy jest używany w tablicach), 32 (jeśli nie jest używany w tablicach) |
prawda czy fałsz |
Ale oprócz tego, że mają różne wartości, różnią się także tym, ile miejsca zajmują w pamięci. Int zajmuje więcej niż bajt
. A
długi jest większy niż krótki. Ilość pamięci zajmowanej przez prymitywy można porównać do rosyjskich lalek lęgowych:
![Poszerzanie i zawężanie typów pierwotnych - 2]()
każda lalka lęgowa ma wolne miejsce w środku. Im większa lalka gniazdująca, tym więcej miejsca. Duża lalka gniazdująca (
długa ) z łatwością pomieści mniejszą
int . Łatwo się dopasowuje i nie musisz robić nic więcej. W Javie podczas pracy z prymitywami nazywa się to konwersją niejawną. Inaczej mówiąc, nazywa się to poszerzeniem.
Poszerzenie w Javie
Oto prosty przykład konwersji rozszerzającej:
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
byte littleNumber = 16;
bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
Tutaj przypisujemy wartość bajtu do zmiennej
int . Przypisanie powiodło się bez żadnych problemów: wartość przechowywana w bajcie zajmuje mniej pamięci niż to, co może pomieścić
int . Mała lalka zagnieżdżona (wartość bajtu) z łatwością mieści się w dużej lalce zagnieżdżonej ( zmienna
int ). Inna sprawa, jeśli spróbujesz zrobić coś przeciwnego, tj. umieścić dużą wartość w zmiennej, której zakres nie może pomieścić tak dużego typu danych. W przypadku prawdziwych lalek gniazdujących liczba po prostu nie pasowałaby. W Javie jest to możliwe, ale z pewnymi niuansami. Spróbujmy umieścić
int w
krótkiej zmiennej:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = bigNumber;
System.out.println(bigNumber);
}
Błąd! Kompilator rozumie, że próbujesz zrobić coś nienormalnego, wpychając dużą lalkę zagnieżdżoną (
int ) do małej (
short ). W tym przypadku błąd kompilacji jest ostrzeżeniem kompilatora: „Hej, czy jesteś
absolutnie pewien , że chcesz to zrobić?” Jeśli jesteś pewien, powiedz kompilatorowi:
„Wszystko jest w porządku. Wiem, co robię!” Proces ten nazywany jest jawną konwersją typu lub zawężaniem.
Zawężanie w Javie
Aby wykonać konwersję zawężającą, musisz wyraźnie wskazać typ, na który chcesz przekonwertować swoją wartość. Innymi słowy, musisz odpowiedzieć na pytanie kompilatora:
„Do której z tych małych lalek do gniazdowania chcesz włożyć tę dużą lalkę do gniazdowania?” W naszym przypadku wygląda to tak:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = (short) bigNumber;
System.out.println(littleNumber);
}
Wyraźnie wskazujemy, że chcemy umieścić
int w zmiennej
short i że weźmiemy na siebie odpowiedzialność. Widząc, że wyraźnie wskazano węższy typ, kompilator dokonuje konwersji. Jaki jest wynik? Wyjście konsoli:
-27008 To było trochę nieoczekiwane. Dlaczego dokładnie to otrzymaliśmy? W rzeczywistości wszystko jest bardzo proste. Oryginalnie wartość wynosiła 10000000. Była przechowywana w zmiennej
int , która zajmuje 32 bity. To jest jego binarna reprezentacja:
Zapisujemy tę wartość w
krótkiej zmiennej, która może przechowywać tylko 16 bitów! W związku z tym zostanie tam przeniesionych tylko pierwszych 16 bitów naszego numeru. Reszta zostanie odrzucona. W rezultacie krótka zmienna otrzymuje następującą wartość
co w postaci dziesiętnej jest równe -27008 Dlatego kompilator prosi o „potwierdzenie” poprzez wskazanie jawnej konwersji zawężającej do określonego typu. Po pierwsze, pokazuje to, że bierzesz odpowiedzialność za wynik. Po drugie, mówi kompilatorowi, ile miejsca ma przydzielić podczas konwersji. W końcu, w ostatnim przykładzie, gdybyśmy przypisali wartość int zmiennej bajtowej zamiast short
, to mielibyśmy do dyspozycji tylko 8 bitów, a nie 16, a wynik byłby inny. Typy ułamkowe (
float i
double ) mają własny proces zawężania konwersji. Jeśli spróbujesz rzucić liczbę ułamkową na typ całkowity, część ułamkowa zostanie odrzucona.
public static void main(String[] args) {
double d = 2.7;
long x = (int) d;
System.out.println(x);
}
Wyjście konsoli:
2
zwęglać
Wiesz już, że
char służy do wyświetlania pojedynczych znaków.
public static void main(String[] args) {
char c = '!';
char z = 'z';
char i = '8';
}
Ale ten typ danych ma kilka funkcji, które są ważne do zrozumienia. Spójrzmy jeszcze raz na tabelę zakresów wartości:
Typ pierwotny |
Rozmiar w pamięci |
Zakres wartości |
bajt |
8 bitów |
-128 do 127 |
krótki |
16 bitów |
-32768 do 32767 |
zwęglać |
16 bitów |
od 0 do 65536 |
int |
32 bity |
-2147483648 do 2147483647 |
długi |
64 bity |
-9223372036854775808 do 9223372036854775807 |
platforma |
32 bity |
(2 do potęgi -149) do ((2 - (2 do potęgi -23)) * 2 do potęgi 127) |
podwójnie |
64 bity |
(-2 do potęgi 63) do ((2 do potęgi 63) - 1) |
logiczna |
8 (gdy jest używany w tablicach), 32 (jeśli nie jest używany w tablicach) |
prawda czy fałsz |
Dla typu char wskazany jest zakres od 0 do 65536 . Ale co to oznacza? W końcu
znak to nie tylko cyfry, ale także litery, znaki interpunkcyjne… Rzecz w tym, że w Javie wartości
char są zapisywane w formacie Unicode. Unicode napotkaliśmy już na jednej z poprzednich lekcji. Prawdopodobnie pamiętasz, że Unicode to standard kodowania znaków, który obejmuje symbole prawie wszystkich języków pisanych na świecie. Innymi słowy, jest to lista specjalnych kodów, które reprezentują prawie każdy znak w dowolnym języku. Cała tabela Unicode jest bardzo duża i oczywiście nie ma potrzeby uczenia się jej na pamięć. Oto mała jego część:
![Poszerzanie i zawężanie typów pierwotnych - 5]()
Najważniejszą rzeczą jest zrozumienie sposobu przechowywania znaków i pamiętanie, że jeśli znasz kod konkretnego znaku, zawsze możesz go utworzyć w swoim programie. Spróbujmy z jakąś losową liczbą:
public static void main(String[] args) {
int x = 32816;
char c = (char) x ;
System.out.println(c);
}
Dane wyjściowe konsoli: 耰 Jest to format używany do przechowywania znaków
char s w Javie. Każdy symbol odpowiada liczbie: 16-bitowemu (dwubajtowemu) kodowi numerycznemu. W Unicode 32816 odpowiada chińskiemu znakowi 耰. Zwróć uwagę na następujący punkt. W tym przykładzie użyliśmy zmiennej
int . Zajmuje 32 bity w pamięci, podczas gdy
char zajmuje 16. Tutaj wybraliśmy
int , ponieważ nasza liczba (32816) nie zmieści się w
short . Chociaż rozmiar znaku
( podobnie jak
short ) wynosi 16 bitów, w zakresie znaków nie ma liczb ujemnych , więc „dodatnia” część
znakuzasięg jest dwa razy większy (65536 zamiast 32767 dla typu
krótkiego ). Możemy użyć
int , o ile nasz kod pozostaje poniżej 65536. Ale jeśli utworzysz wartość
int większą niż 65536, zajmie ona więcej niż 16 bitów. A to spowoduje zawężenie konwersji
char c = (char) x;
dodatkowe bity zostaną odrzucone (jak omówiono powyżej), a wynik będzie dość nieoczekiwany.
Cechy szczególne dodawania znaków i liczb całkowitych
Spójrzmy na nietypowy przykład:
public class Main {
public static void main(String[] args) {
char c = '1';
int i = 1;
System.out.println(i + c);
}
}
Wyjście konsoli:
50 O_О Jaki to ma sens? 1+1. Skąd się wzięło 50?! Wiesz już, że
char
wartości są przechowywane w pamięci jako liczby z zakresu od 0 do 65536 i że te liczby są reprezentacją znaku w Unicode.
![Poszerzanie i zawężanie typów pierwotnych - 6]()
Kiedy dodamy
znak i jakiś typ liczby całkowitej,
znak jest konwertowany na odpowiedni numer Unicode. W naszym kodzie, kiedy dodaliśmy 1 i „1”, symbol „1” został zamieniony na własny kod, czyli 49 (możesz to sprawdzić w powyższej tabeli). Zatem wynikiem jest 50. Ponownie weźmy jako przykład naszego starego znajomego 耰 i spróbujmy dodać go do jakiejś liczby.
public static void main(String[] args) {
char c = '耰';
int x = 200;
System.out.println(c + x);
}
Wyjście konsoli:
33016 Odkryliśmy już, że 耰 odpowiada 32816. A kiedy dodamy tę liczbę do 200, otrzymamy wynik: 33016. :) Jak widać, algorytm tutaj jest dość prosty, ale nie należy o tym zapominać .