Jason. Cała informatyka w jednym miejscu!

Nie tak dawno wyszedł artykuł o tym, jak w języku Java należy rozumieć zmienne, czym one są i z jakich elementów musi się składać każda z nich. Powiedzieliśmy sobie, że dysponuje nazwą i typem danych. Teraz opiszemy sobie w szerszym znaczeniu ten drugi element. Typy danych w języku Java też muszą zostać opisane szczegółowo, tak samo jak to było przy zmiennej. Do dzieła!

TYPY DANYCH W JĘZYKU JAVA TO PODZIAŁ NA DWIE KATEGORIE

Czytelniku, skoro tutaj wszedłeś, najpierw uraczę Cię definicją co to jest typ danych, bo zwykle tłumaczenie jakiegoś zagadnienia zaczynam od definicji. Typ danych jest informacją dla kompilatora identyfikującą rodzaj wartości (danej) jaka ma się znaleźć w zmiennej, a także zakres dopuszczalnych wartości jakie może w sobie przechowywać. Java to język z silną typizacją, zatem nie dopuści do przypisania liczby zmiennoprzecinkowej (z ułamkiem) do zmiennej typu liczba całkowita (w przeciwieństwie choćby do języka JavaScript), chyba że zastosujemy jawne rzutowanie typu "informując" kompilator, że wiemy co robimy (szczegóły wkrótce).

Występowanie poszczególnych typów danych zależy od samego języka. Nie piszemy tu o C i C++ czyli o językach wysokiego poziomu dysponujących ogromną paletą typów danych, w skład których na to samo przeznaczenie przypada nawet kilkanaście różnych typów danych. Na przykład poza domyślnym "int" który miałeś(-aś) okazję poznać w artykule o zmiennych, jest jeszcze podział na typy "ze znakiem" ("signed") oraz "bez znaku" ("unsigned"). Różnica między nimi jest taka, że typy bez znaku mają (w przybliżeniu) dwukrotnie większy zakres maksymalny wartości jaka może się tam znaleźć, natomiast nie ma szans wstawić wewnątrz takiej zmiennej dowolnej wartości ujemnej.

Typy danych w języku Java zostały znacznie uproszczone. Nie ma tutaj podziału na typy ze znakiem i bez znaku, a ponadto liczba typów danych przechowujących wartości tego samego typu została mocno skrócona. To wynika "z dewizy" twórców języka Java, którzy postawili na stworzenie języka podobnego składniowo do C++'a, tylko dużo prostszego. Wszystko się wyjaśni z biegiem artykułu.

Zaczniemy sobie teraz wyróżniać poszczególne rodzaje jakie mogą przyjmować typy danych w języku Java.

TYPY PROSTE (PRYMITYWNE)

Wspomniałem o dwóch kategoriach typów danych. Język Java posługuje się typami prostymi i referencyjnymi. Różnica między nimi "obnaża się" w momencie przekazywania ich jako parametr funkcji. Typy proste są przekazywane jako kopie, co oznacza że modyfikacje ich wartości zostaną unieważnione w momencie zakończenia wywoływania funkcji. Przyjrzyjmy się im z bliska.

CAŁKOWITOLICZBOWE

Całkowitoliczbowe typy są zdolne składować tylko liczby całkowite. W 99% przypadków skorzystasz z typu "int", jednak nie jest on jedynym przedstawicielem 🙂. Jest jeszcze parę innych typów, które najlepiej przedstawić w tabelce:

NAZWA MINIMALNY ZAKRES MAKSYMALNY ZAKRES PRZYKŁAD
byte -27 27 - 1 250
short -215 215 - 1 -34000
int -231 231 - 1 2500600
long -263 263 - 1 178549087653L

Jak można zauważyć, każdy typ wyróżnia się tym, jak "duże" wartości może w sobie zmieścić. Do bajta będziemy w stanie włożyć liczby od -128 do 127. Kompilator odprawi Cię z kwitkiem, gdy spróbujesz tam przypisać liczbę większą bądź mniejszą od tego zakresu. Nie wierzysz? Spróbuj 😄!

Co ciekawe, dostrzeżemy inne zachowanie w sytuacji, gdy wartość wyjdzie poza zakres typu danych w wyniku modyfikacji PODCZAS działania programu! Rozważmy poniższy ciąg instrukcji:

byte b = 127;

System.out.println(b);

++b;

System.out.println(b);

W momencie zdefiniowania zmiennej, przypisujemy maksymalną wartość jaką może przyjąć typ danych "byte" i kompilator nie będzie miał nic przeciwko temu. Czy to oznacza, że właśnie udało nam się wykiwać zakresy? Otóż nie! Po zastosowaniu inkrementacji dojdzie do zjawiska przekroczenia zakresu liczb całkowitych! Więcej informacji jest w osobnym materiale, aczkolwiek tłumacząc jednym zdaniem dochodzi do "zapętlenia" wartości i po przekroczeniu zakresu w jedną albo w drugą stronę, następuje "wyskoczenie" tejże wartości z drugiej strony. Napisane bardzo abstrakcyjnie - zachęcam do analizy osobnego artykułu! Wniosek jest następujący: w momencie wstawienia wartości początkowej wykraczającej poza zakres jaki posiadają typy danych w języku Java, nie dojdzie do skompilowania programu! Za to kiedy dojdzie do wyjścia poza zakres w trakcie działania programu, jest już zupełnie inną historią.

Mały komentarz na temat typu "long". Zwróć koniecznie uwagę na dużą literę 'L', zaraz po ostatniej cyfrze. Ten sufiks jest potrzebny tylko wówczas, gdy przypiszemy zmiennej typu "long" wartość wykraczającą poza zakres typu "int":

long x = 1500000000;
long y = 150000000000L;

Miejcie to na uwadze. Wielkość literki nie ma znaczenia, jednak zdaniem wielu osób duża litera jest o wiele bardziej czytelna.

ZMIENNOPRZECINKOWE

Gdy widzicie "floating-point" oznacza to zmiennoprzecinkowy typ danych. Typy zmiennoprzecinkowe są zdolne do przechowywania liczb z ułamkiem np. 15,7. Pierwsza cenna informacja dla Was - oddzielacie część ułamkową nie przecinkiem, a kropką! Wyróżniamy tylko dwa typy danych w języku Java zdolne do przechowywania liczb zmiennoprzecinkowych:

NAZWA MINIMALNY ZAKRES MAKSYMALNY ZAKRES PRECYZJA PRZYKŁAD
float ±3.4*10-38 3.4*1038 7 cyfr 645.457f
double ±1.79*10-308 1.79*10308 16 cyfr 35874.346737

Zwykle "float" wystarcza nam w zupełności, aczkolwiek są przypadki konieczności posiadania większej liczby miejsc po przecinku (precyzja). Wtedy mamy prawo sięgnąć po "double", które tak naprawdę jest domyślnym typem danych zmiennoprzecinkowym. Dowodem jest to, iż w momencie przypisywania liczby zmiennoprzecinkowej, "double" nie wymaga żadnego sufiksu, ale "float" już tak:

float f = 645.457f;
double d = 35874.346737;
ZNAKOWY

Typ znakowy legitymujący się nazwą "char" 😆 służy do przechowywania pojedynczego znaku, a konkretniej pisząc, symbolu. Umieszczamy go zawsze w apostrofach:

char c = 'T';

Nawet jeśli będziemy chcieli umieścić sekwencję sterującą składającą się de facto z dwóch znaków:

char c = '\n';

i tak umieszczamy ją w apostrofach! Sekwencja sterująca jest znakiem specjalnym "transformującym się" na jakieś działanie. Najbardziej podstawowym jest kombinacja "backslash" + mała litera 'n', i to spowoduje przejście do nowego wiersza jakbyśmy nacisnęli klawisz Enter w edytorze kodu.

LOGICZNY

Ostatnim typem podstawowym jest "boolean", czyli typ logiczny. On może reprezentować jedynie wartości "true" i "false" (prawda i fałsz). Używamy go do przypisywania wartości wynikowej jakiegoś wyrażenia, choć zdarza się przypisywanie słowa kluczowego bezpośrednio:

boolean b1 = false;
boolean b2 = 7 < 5;

zatem obie formy są dozwolone i stosowane zależnie od konstrukcji kodu.

TYPY REFERENCYJNE

A teraz mamy typy referencyjne. Nazwa pochodzi od pojęcia "referencja" - bardzo ważnym hasłem związanym ze wskaźnikami znanymi z języka C, które lądują na strukturze danych zwaną stertą. Nie piszę Ci o tym, żeby komplikować, tylko chcę nawiązać do wspomnianego przekazywania przez kopię przy typach prostych. W momencie, gdy funkcja reprezentuje parametr typu referencyjnego, to po zakończeniu wszystkich jej instrukcji każda modyfikacja tej wartości zostanie utrwalona! Tym się różnią proste typy danych w języku Java od referencyjnych!

Podaję przykłady.

ŁAŃCUCH ZNAKÓW

"String" to typ, który został już wspomniany w artykule o pierwszym kompilowanym programie. Napisałem wtedy w dużym uproszczeniu, że to jest tekst, jednak wcale nie musi nim być. Poprawna nazwa to łańcuch znaków i może zawierać dowolny ciąg symboli! Charakterystyczne są znaki cudzysłowów, które umieszczamy ZAWSZE kiedy piszemy treść naszego łańcucha:

String s = "Łańcuch znaków";

Uważajcie na wielką literę słowa "String" - to stanowi jeden z subtelnych wyjątków pomiędzy Javą, a językiem C# (tak apropos, napisałem już wcześniej o typach danych w tym języku 😊)!

Czy nie dziwi Cię, że traktuję łańcuch znaków jako typ referencyjny, który na pierwszy rzut oka nie różni się niczym szczególnym w budowie od wyżej wymienionych? To nie pomyłka, to fakt! JEST to typ referencyjny i to wynika z cechy niezmienności ("immutability"). Łańcuch znaków nie powinien być modyfikowany bezpośrednio po pierwszym przypisaniu. Jeśli Cię interesuje dalszy ciąg, zapraszam do innego artykułu, bo tam opisałem tajemnicę jaką typ "String" skrywa przed nami...

INSTANCJA KLASY

Obiekt klasy także jest typem referencyjnym. To nic innego jak kopia pochodząca z niestandardowego szablonu. Dalsze szczegóły zostawię na osobny materiał, natomiast wiedzcie tyle, że jak widzicie słowo kluczowe "new":

Point point = new Point(19, 95);

to mamy do czynienia z tworzeniem obiektu na podstawie wskazanej klasy.

TYP WYLICZENIOWY

Wyliczenie definiujemy hasłem "enum", a następnie możemy utworzyć zmienną o podobnej roli co instancja klasy, jednak w tym przypadku przypisujemy jedną ze zdefiniowanych wartości:

public enum Directions {
	NORTH, SOUTH, EAST, WEST
}

Directions direction = Directions.NORTH;

Po więcej informacji na temat typu wyliczeniowego, skieruję Cię do odrębnego artykułu z cyklu o Javie.

Typy danych w języku Java

Typy danych w języku Java dzielą się na proste ("prymitywne") i referencyjne.


Tak się prezentują typy danych w języku Java. Wiem, że ilość informacji może budzić grozę, jednak zawsze próbuję napisać to, co najpotrzebniejsze, przy jednoczesnym wskazaniu na wszystkie najważniejsze szczegóły 🙂.

NASTĘPNY ARTYKUŁ: Pętla for w języku Java. Charakterystyka i zastosowania

PODOBNE ARTYKUŁY