Přednáška 5 - řídicí struktury, datové typy

Obsah

Datové typy v Javě
Primitivní vs. objektové datové typy - opakování
Přiřazení proměnné primitivního typu - opakování
Přiřazení objektové proměnné - opakování
Primitivní datové typy
Integrální typy - celočíselné
Integrální typy - "char"
Typ char - kódování
Čísla s pohyblivou řádovou čárkou
Vestavěné konstanty s pohyblivou řádovou čárkou
Typ logických hodnot - boolean
Typ void
Pole v Javě
Pole (2)
Pole - co když deklarujeme, ale nevytvoříme?
Pole - co když deklarujeme, vytvoříme, ale nenaplníme?
Kopírování polí

Datové typy v Javě

  • Primitivní vs. objektové typy

  • 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í

  • Příklad:

    float a = 1.23456; 
    float b = a; 
    a += 2;
    

Přiřazení objektové proměnné - opakování

  • Příklad, deklarujeme třídu

    Cislo

    takto:

    public class Cislo { 
       private float hodnota; 
       public Cislo(float h) { 
          hodnota = h; 
       } 
       public void zvysO(float kolik) { 
          hodnota += kolik; 
       }
       public void vypis() { 
          System.out.println(hodnota); 
       }
    }    
    
  • nyní ji použijeme:

    Cislo c1 = new Cislo(1.23456); 
    Cislo c2 = c1; 
    c1.zvysO(2); 
    c1.vypis(); 
    c2.vypis();    
    

    dostaneme:

    3.23456 
    3.23456
    

Primitivní datové typy

Proměnné těchto typů nesou elementární, z hlediska Javy atomické, dále nestrukturované hodnoty.

Deklarace takové proměnné (kdekoli) způsobí:

  1. rezervování příslušného paměťového prostoru (např. pro hodnotu int čtyři bajty)

  2. zpřístupnění (pojmenování) tohoto prostoru identifikátorem proměnné

V Javě existují tyto skupiny primitivních typů:

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

  2. typy čísel s pohyblivou řádovou čárkou (float a double)

  3. typ logických hodnot (boolean).

Integrální typy - celočíselné

V Javě jsou celá čísla vždy interpretována jako znaménková

"Základním" celočíselným typem je 32bitový int s rozsahem -2 147 483 6482147483647

větší rozsah (64 bitů) má long, cca +/- 9*10^18

menší rozsah mají

  • short (16 bitů), tj. -32768..32767

  • byte (8 bitů), tj. -128..127

Pro celočíselné typy existují (stejně jako pro floating-point typy) konstanty - minimální a maximální hodnoty příslušného typu. Tyto konstanty mají název vždy Typ.MIN_VALUE , analogicky MAX... Viz např. Minmální a maximální hodnoty

Integrální typy - "char"

char představuje jeden 16bitový znak v kódování UNICODE

Konstanty typu char zapisujeme

  • v 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.

Problém může nastat při interpretaci kódování znaků národních abeced přímo ve zdrojovém textu programu.

Ve zdroj. textu správně napsaného javového vícejazyčného programu by žádné národní znaky VŮBEC neměly vyskytovat.

Je vhodné umístit je 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ů

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

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

double: tentýž zápis, ovšem bez "f" za konstantou!, s větší povolenou přesností a rozsahem

Vestavěné konstanty s pohyblivou řádovou čárkou

Kladné a záporné nekonečno:

  • Float.POSITIVE_INFINITY , totéž s NEGATIVE...

  • totéž pro Double

  • obdobně existují pro oba typy konstanty uvádějící rozlišení daného typu - MIN_VALUE , podobně s MAX...

Konstanta NaN - Not A Number

Viz také Minimální a maximální hodnoty

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

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.

Pole v Javě

Pole v Javě je speciálním objektem

Můžeme mít pole jak primitivních, tak objektových hodnot

  • pole primitivních hodnot tyto hodnoty obsahuje

  • pole objektů obsahuje odkazy na objekty

Kromě pole v Javě existují i jiné objekty na ukládání více hodnot - tzn. kontejnery, viz dále

Syntaxe deklarace

typhodnoty [] jménopole

[Poznámka]Poznámka

na rozdíl od C/C++ nikdy neuvádíme při deklaraci počet prvků pole - ten je podstatný až při vytvoření objektu pole

Syntaxe přístupu k prvkůmjménopole[indexprvku]Používáme

  • jak pro přiřazení prvku do pole: jménopole[indexprvku] = hodnota;

  • tak pro čtení hodnoty z pole proměnná = jménopole[indexprvku];

Syntaxe vytvoření objektu pole: jako u jiného objektu - voláním konstruktoru:

jménopole = new typhodnoty[ početprvků ]; nebo vzniklé pole rovnou naplníme hodnotami/odkazy

jménopole = new typhodnoty[] {prvek1, prvek2, ...};

Pole (2)

Pole je objekt, je třeba ho před použitím nejen deklarovat, ale i vytvořit:

Clovek[] lidi; 
lidi = new Clovek[5];    

Clovek

Nyní můžeme pole naplnit:

lidi[0] = new Clovek("Václav Klaus", Clovek.MUZ); 
lidi[1] = new Clovek("Libuše Benešová", Clovek.ZENA); 
lidi[0].vypisInfo(); lidi[1].vypisInfo();
    
  • Nyní jsou v poli lidi naplněny první dva prvky odkazy na objekty.

  • Zbylé prvky zůstaly naplněny prázdnými odkazy null.

Pole - co když deklarujeme, ale nevytvoříme?

Co kdybychom pole pouze deklarovali a nevytvořili:

Clovek[] lidi; 
lidi[0] = new Clovek("Václav Klaus", Clovek.MUZ);    

Toto by skončilo s běhovou chybou "NullPointerException", pole neexistuje, nelze do něj tudíž vkládat prvky!

Pokud tuto chybu uděláme v rámci metody:

public class Pokus { 
   public static void main(String args[]) { 
      String[] pole; 
      pole[0] = "Neco"; 
   }
}    

překladač nás varuje:

Pokus.java:4: variable pole might not have been
    initialized pole[0] = "Neco"; ^ 1 error 

Pokud ovšem

pole

bude proměnnou objektu/třídy:

public class Pokus {
   static String[] pole; 
   public static void main(String args[]) { 
      pole[0] = "Neco"; 
   }
} 

Překladač chybu neodhalí a po spuštění se objeví:

Exception in thread "main"
    java.lang.NullPointerException at Pokus.main(Pokus.java:4)    

Pole - co když deklarujeme, vytvoříme, ale nenaplníme?

Co kdybychom pole deklarovali, vytvořili, ale nenaplnili příslušnými prvky:

Clovek[] lidi; 
lidi = new Clovek[5]; 
lidi[0].vypisInfo();

Toto by skončilo také s běhovou chybouNullPointerException:

  • pole existuje, má pět prvků, ale první z nich je prázdný, nelze tudíž volat jeho metody (resp. vůbec používat jeho vlastnosti)!

Kopírování polí

V Javě obecně přiřazení proměnné objektového typu vede pouze k duplikaci odkazu, nikoli celého odkazovaného objektu.

Nejinak je tomu u polí, tj.:

Clovek[] lidi2; 
lidi2 = lidi1;

V proměnnélidi2je nyní odkaz na stejné pole jako je vlidi1.

Zatímco, provedeme-li vytvoření nového pole + arraycopy, pak lidi2 obsahuje duplikát/klon/kopii původního pole.

Clovek[] lidi2 = new Clovek[5]; 
System.arraycopy(lidi, 0, lidi2, 0, lidi.length);

viz též Dokumentace API třídy "System"

[Poznámka]Poznámka

Samozřejmě bychom mohli kopírovat prvky ručně, např. pomocí for cyklu, ale volání System.arraycopy je zaručeně nejrychlejší a přitom stále platformově nezávislou metodou, jak kopírovat pole.

Také arraycopy však do cílového pole zduplikuje jen odkazy na objekty, nevytvoří kopie objektů!