Preamble

Lasaris

Úvod k datovým typům v Javě

  • Naučit se pracovat s primitivními a objektovými datovými typy v Javě, vymezit to vůči obecně známým principům (např. z Pascalu)
  • Předpoklady: znát základní datové typy (číselné, logické, znakové) — např. z Pascalu, C či odjinud
  • Kategorie primitivních typů: integrální, boolean, čísla s pohyblivou řádovou čárkou
  • Pole: deklarace, vytvoření, naplnění, přístup k prvkům, rozsah indexů

Primitivní vs. objektové datové typy - opakování

Java striktně rozlišuje mezi hodnotami:

primitivních datových typů

(čísla, logické hodnoty, znaky) a

objektových typů

(řetězce a všechny uživatelem definované [tj. vlastní] typy-třídy)

Základní rozdíl je v práci s proměnnými:

proměnné primitivních typů

přímo obsahují danou hodnotu, zatímco

proměnné objektových typů

obsahují pouze odkaz na příslušný objekt

  • Důsledek → dvě objektové proměnné mohou nést odkaz na tentýž objekt

Přiřazení proměnné primitivního typu — opakování

double a = 1.23456;
double b = a;
a += 2;
// poté bude v a hodnota 3.23456 (tj. přičteno),
// v b stále hodnota 1.23456

Předávání parametru primitivního typu

  • Při volání metod s parametry primitivního typu (čísla, boolean, char) postupuje Java vždy takto:
    1. vyhodnotí výraz předávaný jako skutečný parametr, získá tím jeho hodnotu příslušného typu, který musí odpovídat typu uvedenému v deklaraci (hlavičce) metody
    2. zavolá metodu, vytvoří v ní (tzn. na zásobníku daného vlákna/procesu) lokální proměnnou
    3. do ní zkopíruje předanou hodnotu
    4. počítá s touto hodnotou (ale neměla by ji měnit, i když to fyzicky je možné - neuvedeme-li final před deklarací parametru!)
    5. po ukončení metody lokální proměnná mizí i s případnými změnami

Vracení výsledku

Chceme-li předat výsledek "nahoru" (volajícímu kódu), pak buďto:

  • návratovou hodnotou (přes return ⇒ běžné a bezproblémové)
  • modifikací atributu objektu, na němž byla metoda zavolána (nebezpečné, protože metoda má pak tzv. vedlejší efekt, t.j. mění objekt, na němž je zavolána) nebo
  • modifikací obsahu objektu, který byl předán jako jiný parametr (s podobnými či ještě horšími riziky!, oba poslední případy musí být popsány v dokumentaci metody)

Předávání parametru primitivního typu: příklad

public class IntParamDemo {
   // tato metoda při zavolání navenek nic neprovede,
   // modifikace i je jen modifikací lokální proměnné,
   // která se při opuštění zapomene
   private static void addTwo(int i) {
      i += 2;
      // přičteme k i dvojku
   }
   public static void main(String[] args) {
      int value = 50;
      addTwo(value);
      System.out.println(value); // vypíše 50!!!
   }
}

Předávání parametru objektové typu

  • Při volání metod s parametry objektového typu (objekty předdefinovaných, cizích i vlastních tříd) postupuje Java vždy takto:
    1. vezme odkaz na objekt předávaný do metody;
    2. zavolá metodu , vytvoří v ní (tzn. na zásobníku daného vlákna/procesu) lokální odkazovou (objektovou) proměnnou;
    3. do ní zkopíruje předaný odkaz (NEDUPLIKUJE OBJEKT, jen ODKAZ, objekt zůstává, jak byl);
    4. počítá s předaným objektem;
    5. po ukončení metody lokální odkazová proměnná mizí, ale objekt metodou mohl být změněn a změny se pak navenek projeví.

Odlišnosti Javy

  • V Javě tedy nelze to, co např. v Pascalu, tzn. předat do metody (tedy pascalsky procedury či funkce) skutečně hodnotu objektu, tedy tak, aby se obsah objektu zduplikoval a uvnitř metody pracovalo s tímto duplikátem.
  • Když tu kopii (zřídka) potřebujeme, lze ji vyrobit ručně, např. pomocí metody clone().

Přiřazení objektové proměnné — deklarace

public class Counter {
   private double value;
   public Counter(double v) {
      value = v;
   }
   public void add(double v) {
      value += v;
   }
   public void show() {
      System.out.println(value);
   }
}

Přiřazení objektové proměnné — použití

  1. Napíšeme-li kód:
    Counter c1 = new Counter(1.23456);
    Counter c2 = c1;
    c1.add(2);
    c1.show();
    c2.show();
  2. Vypíše se:
    3.23456
    3.23456

Primitivní datové typy — deklarace

  • Proměnné těchto typů nesou elementární, z hlediska Javy atomické, dále nestrukturované hodnoty.
  • Deklarace takové proměnné (kdekoli) způsobí:
    • rezervování příslušného paměťového prostoru (např. pro hodnotu int čtyři bajty)
    • zpřístupnění (pojmenování) tohoto prostoru identifikátorem proměnné
    • Místo, kde je paměťový prostor pro proměnnou rezervován, závisí na tom, zda se jedná o proměnnou lokální (tzn. buď parametr metody nebo proměnná v metodě deklarovaná), pak se vyhradí na zásobníku, nebo zda jde o proměnnou objektu či třídy — pak má místo v rámci paměťového prostoru objektu.

Primitivní datové typy — kategorie

  • V Javě existují tyto skupiny primitivních typů:
    integrální typy

    zahrnují typy celočíselné (byte , short , int a long) a typ char. Jsou obdoba ordinálních typů v Pascalu.

    čísel s pohyblivou řádovou čárkou

    float a double

    logických hodnot

    boolean

Integrální typy — celočíselné

  • V Javě jsou celá čísla vždy interpretována jako znaménková (tj. nelze změnit modifikátory jako v C++)
  • "Základním" celočíselným typem je 32bitový int s rozsahem -2147483648 .. 2147483647, dobrá volba, když dopředu neznáme přesně požadovaný rozsah celých čísel

Alternativy:

  • větší rozsah (64 bitů) má long, cca 9*10^18
  • menší rozsah mají short (16 bitů), tj. -32768 .. 32767 a
  • byte (8 bitů), tj. -128 .. 127

Celočíselné typy — použití

  • Nejpoužívanějším celočíselným typem je 32bitový int s rozsahem -2147483648 .. 2147483647, dobrá volba, když dopředu neznáme přesně požadovaný rozsah celých čísel.
  • Jelikož Java je od počátku jazyk pro 32bitové (a "širší") architektury, nevede volba "uzšího" typu (short, byte) ve většině případů ke zrychlení běhu kódu, spíše naopak.
  • Užší typy mají výhody nižší paměťové náročnosti v případě jejich struktur, tzn. polí těchto hodnot. Pak se může evt. projevit i zrychlení dané nutností číst méně bajtů dat.
  • Tento faktor má ale smysl uvažovat až při počtu hodnot nejméně řádově milióny.

Zápis hodnot celočíselných typů od Javy 7

Počínaje Java 7 lze použít notaci s podtržítkem k oddělení řádů dlouhých čísel (většinou po tisících).

private static final int INHABITANTS = 10_538_275;

Typ char

char

jeden 16bitový znak v kódování UNICODE

  • Konstanty typu char zapisujeme buď:
    • v (rovných) apostrofech — 'a', 'Ř'
    • pomocí escape-sekvencí — \n (konec řádku) \t (tabulátor)
    • hexadecimálně — \u0040 (totéž, co 'a')
    • oktalově - \127

Typ char — kódování

  • Java vnitřně kóduje znaky a řetězce v UNICODE, pro vstup a výstup je třeba použít některou za serializací (převodu) UNICODE na sekvence bajtů:
    • např. vícebajtová kódování UNICODE: UTF-8 a UTF-16
    • osmibitová kódování ISO-8859-x, Windows-125x a pod.

Co se znaky národních abeced?

  • Problém může nastat při interpretaci kódování znaků národních abeced uvedených přímo ve zdrojovém textu programu.
  • Ve zdrojovém textu správně napsaného javového vícejazyčného programu by žádné národní znaky VŮBEC neměly vyskytovat.
  • Běžně se umisťují do speciálních souborů tzv. zdrojů (v Javě objekty třídy java.util.ResourceBundle).

Čísla s pohyblivou řádovou čárkou

  • Kódována podle ANSI/IEEE 754-1985:
    float

    32 bitů

    double

    64 bitů

Zápis čísel float a double

  • Možné zápisy literálů typu float (klasický i semilogaritmický tvar) — povšimněte si f nebo F za číslem — je u float nutné!:
    float

    float f = -.777f, g = 0.123f, h = -4e6F, 1.2E-15f;

    double

    double d = -.777, e = -4e6; — tentýž zápis, ovšem bez f za konstantou a s větší povolenou přesností a rozsahem

Vestavěné konstanty float a double

  • Kladné "nekonečno": Float.POSITIVE_INFINITY,
  • podobně záporné: Float.NEGATIVE
  • totéž pro Double
  • Obdobně existují pro oba typy konstanty uvádějící rozlišení (nejmenší uložitelnou absolutní hodnotu různou od 0) daného typu: MIN_VALUE, podobně pro MAX_VALUE
  • Konstanta NaN = Not A Number

Typ logických hodnot boolean

  • Přípustné hodnoty jsou false a true.
  • Na rozdíl od Pascalu na nich není definováno uspořádání, nelze je porovnávat pomocí <, <=, >=, >

Typ void

  • Význam podobný jako v C/C++.
  • Není v pravém slova smyslu datovým typem, nemá žádné hodnoty.
  • Označuje "prázdný" typ pro sdělení, že určitá metoda nevrací žádný výsledek.
  • U konstruktorů, ač také nevracejí žádný výsledek, se ale void nepíše.

Všechno, co jste chtěli vědět o primitivních datových typech