Nauka programowania Java #1: Typy danych

Typy proste

Każdy język programowania posiada zestaw różnych, wbudowanych typów danych. 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 wystepują 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. proste (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 zawietać 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).

  • typy zmiennoprzecinkowe (floating point)

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 zmiennegoprzecinka niż w przypadku stałopozycyjnym. Dlaczego więc istnieją liczby zmiennoprzecinkowe? 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ą cął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 : " + floatNumber + ", double float: " + doubleFloatNumber
        + ", double float with 'd' suffix: " + doubleFloatNumberWihSuffix);
  }
}

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 (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.

Np:

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 pojedyńczych apostrofach. Nie możesz wpisać więcej niż jeden znak do jednej zmiennej typu char.

 

  • typ logiczny (boolean)

Przyjmuje tylko dwie wartości: prawdę lub fałsz.

 

Przykład typów 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

Artykuł o typach prostych w Javie: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

 

Dodaj komentarz