Podstawowe typy danych w Javie, rodzaje zmiennych
Poprzedni wpis Java – wstęp i instalacja
W Javie każda zmienna jest ściśle określonego typu, który może być:
- numeryczny,
- znakowy,
- logiczny,
- wyliczeniowy,
- własny (obiekty klas).
Java jest językiem przenośnym zatem na każdej maszynie zmienne zapisywane są w ten sam sposób. Z góry znane są rozmiary każdego typu prostego i nie istnieje sytuacja znana np. z języka C, w którym zachodzi następująca relacja:
short int <= int <= long.
Każdy kompilator może luźno podejść do ustalenia rozmiarów zatem jest to zależne wyłącznie od człowieka, który uznał, że określona wartość najlepiej spełnia swoje zadanie na konkretnej maszynie. Podejście ukazane w Javie eliminuje te problemy z uruchamianiem programów na innych komputerach lub systemach.
Typy proste w Javie
Przygodę z danymi rozpoczniemy od najprostszych elementów jakimi są typy proste. W tej części przedstawimy wszystkie zmienne jakie są dostępne w Javie oraz podamy podstawowe informacje o nich.
Typy numeryczne – liczby całkowite
Zakres liczb całkowitych w Javie jest następujący dla podanych typów zmiennych.
- long 8 bajtów (-9 223 372 036 854 775 808 do 9 223 372 036 854 775 807).
- int 4 bajty (-2 147 483 648 do 2 147 483 647).
- short 2 bajty (-32 768 do 32 767).
- byte 1 bajt (-128, 127).
1 2 |
int liczbaPlanet = 8; //obecnie znana liczba planet w Układzie Słonecznym long liczbaGwiazd = 400000000000L; //szacowana liczba gwiazd w Drodze Mlecznej |
Java nie posiada typu unsigned, w związku z tym nie można rozszerzyć zakresu zmiennej przez interpretację bitu znakowego jako część wartości zmiennej. Jeśli chcemy zapisać liczbę 3 miliardy musimy użyć typu long. Najczęściej wykorzystywanym typem całkowitoliczbowym jest int
i w większości zastosowań jego wartości są wystarczające – jeśli nie jest to podyktowane innymi uwarunkowaniami zalecamy korzystać z tego typu.
Typy numeryczne – liczby zmiennoprzecinkowe
Te typy danych Przechowują dodatkowo część ułamkową. Zakres liczb zmiennoprzecinkowych w Javie jest następujący dla podanych typów zmiennych.
- float 4 bajty 6-7 cyfr po przecinku (liczby pojedynczej precyzji) przyrostek f lub F,
- double 8 bajtów 15 cyfr po przecinku (liczby podwójnej precyzji) przyrostek d lub D.
1 2 |
float pojemnoscSilnika = 4.0F; double pi = 3.141592653589D; |
Typ logiczny
Każda zmienna logiczna posiada tylko dwie wartości – true i false. Zapisuje się ją jako boolean. Wartość logiczną może zwrócić także wyrażenie porównujące zmienne operatorami (==, <, >). Ten typ jest podstawą przepływu sterowania w programie.
1 2 |
boolean isNull = true; System.out.print(a == b); //zostanie wypisana wartość tego wyrażenia |
Typ znakowy
Zmienna znakowa char reprezentuje pojedyncze znaki przy pomocy kodowania Unicode (więcej szczegółów o różnych sposobach kodowania znaków).
Znaki, takie jak cudzysłów zapisuje się jako \”, a ukośnik jako \\. Jest to spowodowane tym, że te znaki mają też inne zastosowanie. Dlatego należy poinformować kompilator, że chcemy umieścić znak nie jako część składni języka, a jako wartość zmiennej. Szczególnie należy zwrócić uwagę na cudzysłowy oraz ukośniki, gdyż częstym błędem jest umieszczenie ich po prostu np. w łańcuchu znakowym, który wskazuje lokalizację na dysku. Poniżej znajduje się pełna lista takich symboli.
\b \t \n \f \r \” \’ \
1 2 |
char = 'a'; char = '\"'; |
Typ wyliczeniowy
Zmienna wyliczeniowa przydaje się w przypadku, gdy zbiór wartości jest dyskretny np. rozmiary pizzy w menu restauracji.
1 |
enum RozmiarPizzy {MALA, SREDNIA, DUZA}; |
zmienna wyliczeniowa RozmiarPizzy może przyjmować tylko zadeklarowane wartości lub wartość null.
Zmienne i stałe
Zmienne i stałe mają określony typ, mają nazwę oraz wartość. Z punktu widzenia komputera ważne jest wiedzieć, gdzie znajduje się zmienna (jaki posiada adres w pamięci). Dlaczego typ jest taki ważny? Każdy typ zajmuje określoną przestrzeń w pamięci, więc komputer, aby prawidłowo odczytać wartość musi wiedzieć czy będzie to wartość o rozmiarze 4 bajtów jak int, czy też 1 bajt na znak. Na szczęście nas nie interesuje adres komórki w pamięci, a nazwa zmiennej, którą dużo łatwiej operować. Nazwę traktujemy jako etykietę, która po wpisaniu wskaże odpowiednie miejsce w pamięci komputera.
Aby użyć zmiennej należy ją zadeklarować i zainicjować, można to zrobić oddzielnie.
1 2 |
int zmienna; zmienna = 10; |
Lub w jednym wierszu
1 |
int zmienna = 10; |
Podobnie używamy innych typów nadając im odpowiednie wartości. pokazuje to poniższy listing.
1 2 3 |
int dni = 10; float cena = 2.45f boolean isNull = true; |
Słowo kluczowe final oznacza deklarację stałej. Ich nazwy zalecamy pisać wielkimi literami, a w przypadku wieloczłonowej nazwy oddzielać je znakami podkreślenia.
1 2 |
final double PI = 3.1415d; final int MIESIACE_W_ROKU = 12; |
Nazwy zmiennych i stałych
W Javie zmienne, stałe i klasy możemy nazywać w zasadzie dowolnie pamiętając o kilku wyjątkach:
- dopuszczane są litery, cyfry oraz znak podkreślenia (_),
- zmienna nie może być słowem kluczowym Javy,
- pierwszy znak nie może być cyfrą,
- nie używamy znaków diakrytycznych.
Długość zmiennej może być dowolna, natomiast z dobrej praktyki należy dobierać nazwy zmiennych zgodnie z ich zastosowaniem. Czasami trzeba zastosować dłuższą nazwę, dlatego zalecamy używanie notacji camelCase – czyli pierwsze słowo zaczynamy małą literą, a każde następne – wielką. Poniżej znajdują się przykłady poprawnych nazw zmiennych.
1 2 3 |
int dni = 10; float dlugoscBoku = 2.4f; double objetosc = 1,5634d; |
W Javie miejsce inicjacji zmiennej jest dowolne (byle było przed jej użyciem), w związku z tym zaleca się, aby inicjować je jak najbliżej pierwszego użycia.
1 2 3 4 5 |
{ ... int dni = 10; System.Out.Println(dni); } |
Widoczność zmiennych
Zmienne widoczne są po ich zainicjowaniu. Na tym etapie nie będziemy wchodzić w widoczność zmiennych z użyciem modyfikatorów dostępu (o tym napiszemy dokładnie w następnym artykule poświęconym klasom w Javie – wstęp do programowania obiektowego). Ważne aby pamiętać, że zmienna, która została zainicjowana wewnątrz bloku nie jest widoczna poza nim.
1 2 3 4 5 |
... { int zmienna; } System.Out.Println(zmienna); //błąd, zmienna nie jest widoczna poza blokiem! |
Natomiast sytuacja odwrotna jest jak najbardziej prawidłowa.
1 2 3 4 |
int zmienna; { System.Out.Println(zmienna); //poprawnie, zmienna jest widoczna wewnątrz bloku } |
Komentarze w Javie
Zapewne Twojej uwadze nie umknęła treść po dwóch znakach //. Jest to komentarz czyli fragment, który kompilator całkowicie pomija. Komentarze mogą być pomocne przy opisie zmiennych np. co robią, opisywać co robi dana metoda lub wskazywać dany fragment kodu źródłowego, aby łatwiej było go później modyfikować. Występują dwa typy komentarzy:
- krótkie po znaku // – muszą się skończyć w jednej linii,
- blokowe po znaku /* i zakończone */ mogą zajmować wiele linii.
1 2 3 4 5 |
//to jest komentarz krótki /* to jest komentarz blokowy kończy się dopiero specjalnym znakiem */ |
Konwersje i rzutowanie typów
Konwersje typów są konieczne w przypadku, gdy np w działaniu arytmetycznym operandy są różnego typu (np. int i float). Część z nich może odbywać się niejawnie (automatycznie), a część musi być przeprowadzona przez rzutowania (ang. cast). Podstawową cechą Javy jest zapobieganie częstym błędom programistów zatem gdy konwersja może spowodować utratę danych, wymagane jest jawne rzutowanie typów.
Najważniejsze problemy jakie mogą wyniknąć to:
- utrata danych, jeżeli mniejszy typ jest zbyt mały, aby przechować rzutowaną wartość.
- konwersja z typu zmiennoprzecinkowego na całkowitoliczbowy – utrata mantysy (części ułamkowej liczby).
Automatyczne rzutowanie przebiega wg. poniższych zasad zasad:
- jeśli jeden z operandów jest typu, który potrzebuje więcej pamięci, to drugi zostanie przekonwertowany na jego typ,
- w przypadku, gdy jeden z operandów jest typu double, to drugi zostanie przekonwertowany na niego.
Konwersje następują w taki sposób, aby nie utracić danych. W przypadku typów całkowitych występuje następująca konwersja.

Liczby zmiennoprzecinkowe konwertują się na double.

W przypadku działania na typach zmiennoprzecinkowych i całkowitoliczbowych zawsze nastąpi konwersja na ten pierwszy typ float lub double.
1 2 |
int a = 1; float f = a; //niejawna konwersja na 1.0f |
Jeżeli potrzebujemy konwersji typu zmiennoprzecinkowego na typ całkowity, to należy jawnie rzutować.
1 2 |
float f = 1.99f; int a = (int) f; //wartość f wynosi 1 |
Aby zaokrąglić wartości należy skorzystać z metod klasy Math
(np. Math.round()
, Math.floor()
).
Uwaga! W przeciwieństwie do języka C++ w Javie nie istnieje rzutowanie typu liczbowego na logiczny!
1 2 |
int a = 1; boolean b = (boolean) a //błąd! |
Operatory i operandy
Operatory posiadają priorytet działania (podobnie jak kolejność wykonywania działań). Jeśli kolejne operatory mają ten sam priorytet działania, to działanie wykonywane jest od lewej strony. Jeśli nie mamy pewności najlepiej zastosować nawiasy.
- Najwyższy priorytet
- [] – operator tablicowy
- . – dostęp do metody lub pola obiektu
- () – nawiasy i wywołanie metody
- Manipulowanie danymi
- ! operator negacji
- ++ post/pre inkrementacja
- — post/pre dekrementacja
- – ustalenie znaku operandu
- (rzutowanie).
- * – mnożenie.
- / – dzielenie.
- % – dzielenie modulo (reszta z dzielenia)
- Arytmetyka
- + dodawanie.
- – odejmowanie.
- Relacje
- < (mniejszy)
- <= (mniejszy lub równy)
- > (większy)
- >= (większy lub równy)
- ==
- !=
- Operacje na bitach
- & iloczyn
- ^ różnica symetryczna
- | suma bitowa
- Funktory logiczne
- && iloczyn logiczny
- || suma logiczna
- ? operator warunkowy
- Operatory
- przypisania: =
- sumy: += (i = i + x)
- różnicy: -= (i = i – x)
- iloczynu: *= (i = i * x)
- ilorazu: /= (i = i / x)
- , rozdzielenie wyrażeń
W następnej części przyjrzymy się bliżej łańcuchom znakowym, klasie String oraz tablicom.