Site icon Java blog

Java #1: Typy proste (typy prymitywne)

typy proste

Typy proste

Każdy język programowania posiada zestaw różnych, wbudowanych typów danych. Nazywa się je często typami prostymi. Typy proste (ang. Primitive Data Types)  służą one do przechowywania informacji. W językach niższego poziomu, takich jak Assembler, istnieje możliwość odwołania się do konkretnej komórki pamięci, w celu przechowywania informacji. Pamiętaj, że każda informacja w komputerze musi na samym końcu zostać zapisana w postaci binarnej (czyli w systemie liczbowym, w którym występują tylko zera i jedynki). Można powiedzieć, że komputer nie robi nic innego jak przetwarza liczby zero-jedynkowe za pomocą kilkunastu wbudowanych operacji i zachowuje wynik w pamięci lub rejestrach procesora.

Brzmi skomplikowanie? I tak jest w rzeczywistości, bowiem obsługa komputera za pomocą Assemblera nie należy do najprostszych. Aby ułatwić sobie życie, programiści wymyślili języki wysokiego poziomu (takie jak Java), które samodzielnie zarządzają pamięcią i dokonują odpowiedniej konwersji na system binarny. Dlatego też nie musisz się martwić, gdzie trafia wartość, którą zapisujesz w zmiennej. Wystarczy, że będziesz pamiętał, że każda zmienna to jedynie etykieta, pod którą kryje się faktyczna wartość w komórce pamięci.

W Javie istnieją dwa rodzaje typów danych:

  1. Typy proste (ang. primitives)
  2. oraz referencyjne

W ramach typów prostych wyróżniamy:

Typy całkowite

  1. byte
  2. short (dwa bajty)
  3. int (cztery bajty), skrót od Integer (liczba całkowita)
  4. long (osiem bajtów)

Przykład:

public class IntegerNumbers {

  public static void main(String[] args) {
    byte byteNumber = 10;
    short shortNumber = 123;
    int intNumber = 9999;
    long longNumber = 256;

    System.out.println("byte: " + byteNumber + ", short integer: " + shortNumber + ", integer: " + intNumber
        + ", long integer " + longNumber);
  }
}

Te cztery rodzaje typów całkowitych różnią się między sobą jedynie zakresem, czyli pojemnością jaką masz do wykorzystania przy przypisywaniu odpowiedniej wartości. W nawiasach wypisałem je dla Twojej informacji. W przypadku typu byte nic nie wpisałem, bo byte to po prostu jeden bajt. 🙂 Co to jest ten bajt?

Na pewno spotkałeś/aś się z określeniem megabajt (MB), gigabajt (GB), itp. Jeden bajt zawiera osiem bitów. Dlaczego akurat osiem? Dlatego, że dwa do potęgi trzeciej daje właśnie osiem, a przecież komputer operuje na liczbach binarnych (jest informacja, albo jej nie ma, przepływa prąd lub nie. Proste, prawda?). W taki sam sposób możesz policzyć ile bitów może zawierać short, int i long. Teraz jeszcze wypadałoby wytłumaczyć czym jest ów bit. To po prostu jedna wartość systemu  binarnego (czyli liczba, która może zawierać tylko cyfrę zero lub jeden).

Zapis stałopozycyjny i zmiennopozycyjny

W przypadku systemów liczbowych w komputerze wyznaczamy ich dwa rodzaje: stałopozycyjny i zmiennopozycyjny. Oznacza to, że przecinek w zapisie liczby binarnej w przypadku pierwszym jest na określonej pozycji, a w drugim obliczany specjalnym algorytmem (liczba dzieli się się na bit znaku, bity wykładnika i mantysy). Nie chcę wchodzić w szczegóły dlaczego tak jest. W każdym razie, chciałbym żebyś uwierzył/ła mi na słowo, że obliczenia w systemie binarnym (dodawanie, odejmowanie, mnożenie, dzielenie) jest dużo trudniejsze w przypadku zmiennego przecinka niż w przypadku stałopozycyjnym.

Liczby zmiennoprzecinkowe

Dlaczego więc istnieją liczby zmiennoprzecinkowe (ang. floating point)? Po pierwsze typy całkowite, jak sama nazwa wskazuje, uniemożliwiają napisania liczby z ułamkiem. Oczywiście możesz zapisać taką liczbą pod dwiema zmiennymi (częścią całkowitą i ułamkową). Jednak algorytmy obliczania takiej liczby będą bardziej skomplikowane od użycia jedynie operatora dodawania czy odejmowania. W przypadku liczby zmiennoprzecinkowej jest to bardzo wygodne. Spójrzmy na przykład poniżej.

public class FloatNumbers {

  public static void main(String[] args) {
    float singlePrecisionNumber = 10.5f;
    double doublePrecisionNumber = 10.25;
    double doublePrecisionNumberWihSuffix = 109.25d;

    System.out.println("floating point number : " + singlePrecisionNumber + ", double float: " + doublePrecisionNumber + ", double float with 'd' suffix: " + doublePrecisionNumberWihSuffix);
  }
}

Float i double

Widać, że mamy dwa rodzaje typów zmiennoprzecinkowych a Javie:

  1. float (o pojemności czterech bajtów, odpowiednik int w przypadku liczby całkowitych)
  2. oraz double (może zawierać do ośmiu bajtów)

Jak widzisz na przykładzie, pisanie liczb ułamkowych za pomocą float i double jest bardzo proste. Należy jedynie pamiętać, że w przypadku typu float na koniec liczby należy dodać literę ‘f’ (od float). W przypadku double można dodać suffix ‘d’ do liczby, jednak nie jest to obligatoryjne. Niestety są jednak wady tego rozwiązania. Przede wszystkim liczby zmiennoprzecinkowe są liczbami niewymiernymi (trochę jak liczba PI), oznacza to, że zawsze można dodać kolejne bity po przecinku, a ich wartość dziesiętna jest przybliżana. Np. w systemie zmiennoprzecinkowym nie ma czegoś takiego jak liczba 0.15 (po konwersji na system dziesiętny). W praktyce jest to np. 0.150212..

Każda liczba jest zaokrąglana w ramach zakresu swojej precyzji. Może to doprowadzić, że przy zaprojektowaniu funkcji używającej typy zmiennoprzecinkowe, da ona różne wyniki (przy takich samym argumentach) na dwóch różnych komputerach! Jest to istotne niebezpieczeństwo, które zawsze miej na uwadze.

Typ znakowy (ang. char, od ‘character’, po polsku po prostu znak)

Skoro wszystko w komputerze jest liczbą binarną to w jaki sposób zapisać litery alfabetu w programie? Programiści zaprojektowali bardzo prosty sposób obsługi wszystkich znaków, które nie są liczbą naturalną. Aby dokonać takiej konwersji komputer ma zaprojektowaną odpowiednią tablicę (nazywaną tablicą ASCII), która po prostu zawiera przypisany do znaku numer.

Przykład:

Pod liczbą 65 zapisana dziesiętnie kryje się znak ‘A’, 66 to ‘B’, 67 to ‘C’, itp.

Warto wiedzieć, że cyfry ‘0’, ‘1’, 2’, ..  też mogą być zapisane jako znak.

W Javie typ znakowy deklaruje się słowem kluczowym char. Każdą wartość należy zapisać w pojedynczych apostrofach. Nie możesz wpisać więcej niż jeden znak do jednej zmiennej typu char.

Typ logiczny (ang. boolean)

Przyjmuje on tylko dwie wartości: prawdę (true) lub fałsz (false).

Typy proste boolean i char:

public class CharBooleanTypes {

  public static void main(String[] args) {
    char characterA = 'A';
    char characterB = 'B';
    char character0 = '0';
    boolean trueBool = true;
    boolean falseBool = false;

    System.out.println("Char for 'A': " + characterA + ", char for 'B': " + characterB + ", char for '0': "
        + character0 + ", boolean true value" + trueBool + ", boolean true value" + falseBool);
  }
}

W następnej lekcji omówię typy referencyjne.

Linki:

Tablica ascii: http://www.asciitable.com

Artykuł na stronie Oracle o zmiennym przecinku: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Wszystkie typy proste w Javie: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Link do lekcji na githubie: https://github.com/developeronthego/java-basics/tree/main/src/main/java/basics/lesson1

Lind do lekcji jak stworzyć pierwszy projekt w środowisku Eclipse: https://developeronthego.pl/eclipse-srodowiska-programistyczne/

Exit mobile version