Základy jazyka
2. Základy jazyka Napíšeme si první jednoduchý program v Javě, na kterém si vysvětlíme základy jazyka. Bude to program, který sečte dvě celá čísla a výsledek zobrazí na konzoli. public class PrvniProgram { public static void main(String[] args) { int scitanec1 = 5; int scitanec2 = 2; int soucet = scitanec1 + scitanec2; System.out.println("Muj prvni program "); System.out.println("Soucet je: " + soucet); } } Programovací jazyk Java rozlišuje malá a velká písmena. Hned od počátku je třeba si uvědomit, že je rozdíl, jestli napíšeme soucet nebo Soucet, v Javě se jedná o dva různé identifikátory. Java jako objektový jazyk používá téměř vždy objekty. Každý program je třídou a proto je v našem prográmku uvedeno public class PrvniProgram. Class je klíčové slovo Javy pro deklaraci třídy, PrvniProgram je jméno této třídy (identifikátor) a public modifikátor třídy, který označuje třídu jako veřejně dostupnou. Dále musíme dodržet pravidlo, že soubor, ve kterém bude zdrojový text uložen, se musí jmenovat stejně jako třída a mít koncovku .java. V našem případě se soubor jmenuje PrvniProgram.java. Pozor, je třeba rozlišovat velká a malá písmena i u jmen souborů, i když např. ve Windows se to zdá být zbytečné. Překladač kontroluje shodu názvu třídy s názvem souboru včetně malých a velkých písmen. Pokud má být program spustitelný, musí v něm definovaná třída obsahovat metodu main deklarovanou se všemi modifikátory uvedenými v programu (tj. public static). Jejich význam bude vysvětlen v následujících kapitolách. Dále náš program obsahuje blok příkazů, ve kterém je deklarace a použití proměnných (scitanec1, scitanec2, soucet) a spuštění metod.
Proměnné Při své činnosti si program ukládá data do proměnných či skupin proměnných. Popis proměnné se skládají ze tří částí: jména proměnné (identifikátoru), datového typu (např. celé číslo) a vlastního obsahu (hodnot, v případě tříd a rozhraní jsou součástí obsahu i metody). Jméno proměnné (identifikátor) musí začínat písmenem, po něm mohou následovat další písmena nebo číslice, délka není omezena. Ve jméně proměnné může být i podtržítko “_” a znak “$”1.
1
4
Znak $ není vhodné používat, neboť ho překladač používá při vytváření interních proměnných.
Základy jazyka Java je přísně typový jazyk, proto je vždy nutno uvést datový typ proměnné. Datové typy v Javě lze rozdělit do těchto skupin: •
•
primitivní typy: •
čísla (byte, short, int, long, float, double)
•
znaky (char)
•
logické hodnoty (boolean)
referenční typy: •
třídy (class)
•
rozhraní (interface)
•
pole (array)
Referenčním typům jsou věnovány samostatné kapitoly.
Primitivní datové typy Java používá pro celočíselné proměnné čtyři datové typy: long, int, short a byte, pro reálná čísla dva typy: double a float, pro znaky typ char a pro logické proměnné typ boolean. Velikost, jakou zabírají v paměti, a rozsah, který jsou schopny obsáhnout, vidíme v následující tabulce. Název typu long
Velikost (v bytech) 8
int
4
short byte double
2 1 8
float char boolean
4 2 1 bit
Rozsah -9 223 372 036 854 775 808 až +9 223 372 036 854 775 807 -2 147 483 648 až +2 147 483 647 -32 768 až +32 767 -128 až +127 ±1.797 693 134 862 315 70 E+308 ±3.402 823 47 E+38 65 536 různých znaků true nebo false
Implicitní hodnota2 0 0 0 0 0.0 0.0 \u0000 false
tabulka 1 Primitivní datové typy
Deklarace proměnné promitivního typu Při zavedení nové proměnné je nutné deklarovat identifikátor a datový typ, volitelně lze zadat i počáteční hodnotu. Deklaraci primitivního datového typu lze obecně zapsat takto: datový_typ jméno_proměnné;3 datový_typ jméno_proměnné = počáteční_hodnota;
2
Pouze pro proměnné třídy a instancí, neplatí v případě proměnných metod. Součástí deklarace proměnných mohou být modifikátory (public, static, final atd.) jejichž význam bude popsán později. 3
5
Základy jazyka Pokud tedy v našem programu sčítáme celá čísla, musíme pro ně nejdříve deklarovat proměnné: int scitanec1; int scitanec2 = 10; Počáteční hodnota proměnné může být uvedena nejen hodnotou, ale i výrazem, např.: long delka_dne=24 * 60 * 60; Výraz, kterým se přiřazuje hodnota, se musí dát vyhodnotit v době překladu popř. v okamžiku spuštění programu. Pokud proměnné při deklaraci nepřiřadíme počáteční hodnotu, kompilátor ji sám přiřadí (viz tabulka č.1) – bohužel se implicitní hodnota nepřiřazuje proměnným deklarovaným v rámci metod. Pokud počáteční hodnota bude mimo rozsah proměnné (např. byte b = 200), některé překladače přiřadí nesmyslnou hodnotu, některé ohlásí chybu.
Konstanty Konstanty se používají nejen při deklaraci proměnných, ale i v rámci výrazů. Celá čísla se zapisují obdobným způsobem jako v běžném životě, např. 9876; zápis nesmí obsahovat mezery či jiné oddělovače (např. tisíců). Je-li prvním znakem nula, znamená to, že číslo zapisujeme v osmičkové soustavě, začíná-li zápis čísla prefixem 0x, jedná se o číslo v hexadecimální (šestnáctkové) soustavě. Následující tři proměnné obsahují stejnou počáteční hodnotu: int i = 10; int j = 012; int k = 0xa; Celočíselná konstanta je vždy typu int, pokud potřebujeme konstantu jiného celočíselného typu, je třeba uvést přetypování (viz dále). Reálná čísla se zapisují buď s desetinnou tečkou (např. 0.25, 0.00002) nebo se používá tzv. semilogaritmický zápis, kdy číslo 1.54 * 106 se zapíše ve tvaru 1.54e6. Reálné konstanty jsou vždy typu double. Každý znak je v jazyce Java uložen v kódování Unicode ve dvou bytech. Znaky se píší v jednoduchých uvozovkách, a to buď v defaultním kódu operačního systému (v českých Windows 9x/NT je to kódová stránka CP1250), kdy překladač sám zajistí převod na příslušný znak Unicode, nebo použijeme zápis \uXXXX, ve kterém místo XXXX uvedeme hexadecimální kód příslušného znaku. char c = ’č’; char d = ’\u12ab’; Logické hodnoty – proměnné typu boolean mohou nabývat pouze dvou hodnot, true nebo false. V Javě lze vytvářet i pojmenované konstanty primitivních datových typů – definují se stejně jako proměnné s počáteční hodnotou s tím, že se na začátku uvede klíčové slovo final: final long DELKA_DNE=24 * 60 * 60;
6
Základy jazyka Takto definovanou proměnnou nelze již dále změnit, hodnota se přiřazuje v okamžiku definice. Zda se hodnota přiřadí při překladu či až při běhu programu záleží na výrazu, který přiřazuje hodnotu a na schopnosti optimalizace překladačem. Následující konstanta (náhodné číslo) se přiřadí až při běhu: final int NAHODNE_CISLO = (int) (Math.random() * 20); Je dobrým zvykem ve jménech konstant používat velká písmena.
Přetypování U celočíselné konstanty zapsané v programu se předpokládá datový typ int, u reálných konstant datový typ double. Například ve výrazu long vysledek = 10000*10000 se provede násobení konstant typu int a výsledek typu int se převede do proměnné typu long. Pokud chceme, aby byla konstanta jiného datového typu, je třeba zapsat ji s literálem. Literál pro long je L, pro float f a pro double d (lze používat malá i velká písmena). Tedy zapíšeme-li konstantu 100000L4 bude uložena jako long, zápis 10000f znamená, že číslo je uloženo jako reálné. Pokud se hodnota proměnné kratšího typu ukládá do proměnné delšího typu, provede Java převod automaticky (neexistuje nebezpečí ztráty informace). Například: int cislo1 = 12; long cislo2; cislo2 = cislo1; Pokud bychom ale potřebovali opačné přiřazení, je třeba provést explicitní přetypování a oznámit tak překladači, že případná ztráta informace nevadí, např.: float desetinneCislo1; double desetinneCislo2 = 0.123456789; desetinneCislo1 = (float) desetinnCislo2; Při operacích s číselnými proměnnými typu byte a short se tyto proměnné automaticky převádějí na typ int, tj. výsledek operace s dvěma těmito proměnnými je typu int. Při operaci s proměnnými/konstantami různě dlouhých typů je výsledek delšího typu, tj. výsledkem operace proměnných typu int a long je proměnná typu long, výsledkem operace typu int a double je proměnná typu double atd. Proměnná kratšího typu se převede na delší typ před provedením operace. Pokud trváme na uložení do kratšího typu, je nutné přetypovat výsledek operace: long cislo1 = 10000; int cislo2 = 100; int vysledek = (int) (cislo1 – cislo2);
Přetečení Pokud nastane situace, že informace, kterou do proměnné ukládáme, má větší hodnotu než je maximální hodnota typu, pak mluvíme o tzv. přetečení. Java neohlásí žádnou chybu, ale usekne přesahující část a program tak vyprodukuje špatný výsledek. Např. výsledkem operace 100000 * 100000 je číslo 4
U literálu je výjimečně jedno zda je písmeno malé nebo velké. Pro long je lepší používat velké L, malé l si lze splést s číslicí 1. 7
Základy jazyka 1 410 065 408 typu int místo správného 10 000 000 000, neboť tento výsledek je mimo rozsah typu int. K získání správného výsledku je potřeba aspoň jeden z operátorů označit jako long, tj. operace by měla vypadat následovně: 100000L * 100000. Doporučujeme používat proměnné typu long místo typu int a typ double místo typu float.
Výrazy a operátory Aritmetické operátory a příkaz přiřazení Se základními matematickými operátory jsme se už seznámili. Java používá pro sčítání +, pro odčítání -, pro násobení *, pro dělení / a pro zbytek po celočíselném dělení %. U přetypování a přetečení jsme už hovořili o problémech, které mohou nastat při těchto operacích. S dalším problémem se setkáváme u dělení celých čísel. Pokud v programu použijeme tento výraz double vysledek = 9/2 bude v proměnné vysledek hodnota 4. Výsledkem dělení dvou celých čísel je opět celé číslo bez ohledu na typ proměnné, do které výsledek ukládáme. Proto je i zde třeba použít přetypování nebo literál u jednoho z operandů, např.: double vysledek = 9d/2 V případě proměnných je potřeba jeden z operandů přetypovat, např. pokud cislo1 a cislo2 jsou typu int, double vysledek = ((double) cislo1) / cislo2 5. Java používá řadu zkrácených zápisů některých operací, jsou uvedeny v následující tabulce. Operátor
Příklad
+= -= /= *= %= ++
x += y x -= y x /= y x *= y x %= y x++ ++x x---x
--
Význam operátoru x=x+y x=x-y x=x/y x=x*y x=x%y x=x+1 x=x-1
tabulka 2 Význam některých aritmetických operátorů
Pro často se vyskytující operace - zvyšování nebo snižování hodnoty proměnné o jedničku – lze v Javě použít i zkrácený zápis x++, ++x, x--, --x. Tyto operátory lze (bohužel6) použít i na pravé straně 5
Výraz lze zapsat i ve tvaru double vysledek = (double) cislo1 / cislo2, ale zde je nejasné, zda se přetypování týká prvního operandu či výsledku (nutno znát, zda má větší prioritu přetypování či dělení). Zápis double vysledek = (double) (cislo1 / cislo2) je určitě chybně, neboť ten přetypovává až vlastní výsledek operace, která proběhne jako celočíselná. 6 U výrazů se obvykle předpokládá, že se při výpočtu nemění hodnoty proměnných použitých na pravé straně výrazu – operátory ++ a -- toto pravidlo porušují, což může vést k obtížně odhalitelným chybám. 8
Základy jazyka výrazu, kdy se rozlišuje, zda použijeme ++ jako předponu nebo příponu. Pokud se operátor ++ zapíše jako předpona, nejprve se zvýší hodnota proměnné a pak se použije, pokud je ++ zapsán jako přípona, pracuje se ve výrazu s původní hodnotou a teprve poté je zvýšena. Vysvětlíme si to v následujících příkladech. int puvodni = 10; int nova = puvodni++; Proměnná puvodni je nyní rovna 11 a proměnná nova je rovna 10. int puvodni = 10; int nova = ++puvodni; Proměnná puvodni je nyní rovna 11 a proměnná nova je rovna také 11. Pro operátor - - platí stejná pravidla.
Relační operátory Relační operátory se používají pro porovnání hodnot dvou číselných proměnných (pokud nejsou stejného typu, tak se převedou na delší typ), proměnných typu char a boolean. Výsledkem je vždy hodnota typu boolean, tj. buď pravda (true) nebo nepravda (false). Obvykle se používají v příkazu if a v příkazech cyklu jako podmínky7. Přehled relačních operátorů je v následující tabulce (pozor, nelze zaměnit pořadí znaků v operátorech):
relační operátor == != < > <= >=
význam rovná se nerovná se menší než větší než menší nebo rovno větší nebo rovno
tabulka 3 Relační operátory
Logické operátory Logické operátory slouží pro vyjádření vztahu mezi dvěmi proměnnými/výrazy typu boolean, tj. obvykle k vytváření složených podmínek. V Javě se používají operátory && (logická spojka AND) a || (logická spojka OR). Dále lze použít unární operátor !, který označuje negaci NOT následujícího výrazu. Chceme-li například otestovat, jestli je proměnná i větší nebo rovna 10 a současně menší než 50 zapíšeme podmínku takto: (i >= 10) && (i < 50) Výsledkem je hodnota true nebo false.
7
V textu se používá pojem podmínka místo správnějšího pojmu „výraz s výslednou hodnotou typu boolean“. Pojem podmínka je sice méně přesný, avšak často v kontextu lépe pochopitelný. 9
Základy jazyka Bitové operátory Java umožňuje pracovat i s jednotlivými bity celočíselných hodnot. Vzhledem k jejich výjimečnému použití zde nejsou popsány, v případě potřeby je nastudujte z on-line dokumentace.
Podmíněný výraz V Javě existuje ternární operátor ?:, který slouží k vytvoření tzv. podmíněného výrazu, syntaxe je: podmínka ? výraz1 : výraz2 Zapíšeme-li například tento podmíněný výraz: cislo1 < 5 ? cislo2++ : cislo2-Hodnota proměnné cislo2 se zvýší o jedničku (provede se výraz1) pokud je hodnota proměnné cislo1 menší než 5 (podmínka je splněna). Pokud je hodnota proměnné cislo1 větší nebo rovna 5 (tedy podmínka není splněna), hodnota proměnné cislo2 se sníží (provede se vyraz2). Pokud se na zápis podmíněného výrazu podíváme, pochopíme, že z důvodu přehlednosti je výhodnější používat příkaz if (viz dále).
Základní konstrukce programu Při popisu algoritmu používáme v podstatě tři základní struktury a to: •
posloupnost příkazů,
•
rozhodování na základě nějaké podmínky (větvení),
•
opakování činnosti na základě podmínky (cyklus).
S cykly souvisí příkazy pro změnu průběhu cyklu.
Posloupnost Posloupnost příkazů v Javě zapíšeme tak, že jednotlivé příkazy a deklarace oddělíme středníkem. int scitanec1 = 5; int scitanec2 = 2; int soucet = scitanec1 + scitanec2; Příkazy lze napsat i takto: int scitanec1 = 5; int scitanec2 = 2; int soucet = scitanec1 + scitanec2; ale vzhledem k nepřehlednosti doporučuji zapisovat na každý řádek jeden příkaz či deklaraci. Řadu po sobě jdoucích příkazů a deklarací můžeme (a v mnoha případech musíme) spojit do bloku pomocí složených závorek. { int scitanec1 =5; int scitanec2 = 2; int soucet = scitanec1 + scitanec2; } Po složené závorce už neuvádíme středník.
10
Základy jazyka Větvení Pro větvení má Java dva příkazy: if a switch. Příkaz if má podmínku a jednu nebo dvě větve. Syntaxe příkazu if s jednou větví je následující: if (podmínka) příkaz; Příkaz se provede pouze v případě, že podmínka platí tj. byla vyhodnocena jako true. Pokud podmínka byla vyhodnocena jako false, neprovede se nic a příkaz if končí. Syntaxe příkazu if se dvěma větvemi: if (podmínka) příkaz1; else příkaz2; Pokud je podmínka vyhodnocena jako true provede se příkaz1, pokud jako false provede se příkaz2. Místo jednoho příkazu je možno uvést blok příkazů uzavřený do složených závorek. Následující program vygeneruje dvě náhodná celá čísla v rozsahu 1 až 10 a poté zjistí jejich rozdíl (všimněme si též, jak se zapisují komentáře v Javě). public class IfElse { public static void main (String [] args) { /* * * * */
Generovní náhodného čísla. Metoda random() třídy Math vrací číslo typu double z intervalu 0 až 1. Pokud tedy chceme celé číslo od 1 do 10, musíme ho násobit 10 přičíst 1 a pomocí přetypování na int "odseknout" desetinnou část. int cislo1 = (int) (Math.random() * 10 + 1); System.out.println ("Cislo1=" + cislo1); int cislo2 = (int) (Math.random() * 10 + 1); System.out.println ("Cislo2=" + cislo2); if (cislo1 > cislo2) { int rozdil = cislo1 - cislo2; System.out.println ("Cislo1 je vetsi o:" + rozdil); } else { int rozdil = cislo2 - cislo1; System.out.println("Cislo2 je vetsi o:" + rozdil); }; //konec záporné větve i celého if }
} Promyslete si, co se stane v případě, že se vygenerují dvě stejná čísla.
11
Základy jazyka Málo používaný příkaz switch na základě hodnoty výrazu provádí příslušnou větev příkazu (větví obvykle bývá několik). Výraz musí být typu char, byte, short nebo int. Syntaxe je následující: switch (výraz) { case konstanta1: příkaz1; break; case konstanta2: příkaz2; break; case konstanta3: příkaz3; break; case konstanta4: příkaz4; break; // ... default: příkaz; }; V bloku může být několik příkazů začínajících klíčovým slovem case následovaným konstantou (tj. nelze zde uvést např. i > 5) a dvojtečkou. Jeden příkaz může začínat klíčovým slovem default následovaným dvojtečkou. Při provádění příkazu switch se nejprve vyhodnotí výraz a program přejde na větev case s odpovídající hodnotou nebo tuto hodnotu nenajde a přejde na větev default. Obvykle se každá větev ukončuje příkazem break, pokud jím však není větev ukončena, pokračuje se v provádění všech následujících větví, i když je u nich uvedena jiná hodnota než jakou má výraz (záleží na pořadí uvedení větví!). Postup provádění následujících dvou příkladů je tedy různý. Příklad1 switch ( i ) { case 1 :
Příklad2 switch ( i ) { case 1 : prikaz1; break;
prikaz1; case 2 :
case 2 :
prikaz2; default : prikaz3;
prikaz2; break; default : prikaz3;
}
} tabulka 4 Porovnání příkazu switch s break a bez něj
Hodnota proměnné i
Provedené příkazy příklad1
Provedené příkazy příklad2
1
prikaz1
2
prikaz2
jiná hodnota
prikaz3
prikaz1 prikaz2 prikaz3 prikaz2 prikaz3 prikaz3
tabulka 5 Výsledky porovnání dvou variant příkazu switch
Cykly V Javě jsou definovány tři druhy cyklů. První z nich je cyklus while s následující syntaxí: while ( podmínka ) příkaz;
12
Základy jazyka Provádění příkazu začíná vždy testem podmínky. Pokud je podmínka splněna (má hodnotu true), provede se příkaz a znovu se přejde na test podmínky. Při nesplnění podmínky provádění cyklu končí. Pokud podmínka není na začátku splněna, neprovede se příkaz v cyklu while ani jednou. int i=1; while (i <= 10) { // příkazy i++; } Nekonečný cyklus lze zapsat následovně: while (true) { // příkazy } Druhým a nejméně používaným typem cyklu je cyklus do-while s následující syntaxí: do příkaz while ( podmínka ); Tento cyklus začíná provedením příkazu a až poté se testuje podmínka. Dle výsledku se provádí znovu příkaz (hodnota true podmínky) nebo se končí (hodnota false). V cyklu do while se příkaz provede vždy alespoň jednou. Posledním typem cyklu je cyklus for, který používáme tam, kde známe počet iterací. Syntaxe: for ( inicializace; podmínka; krok) příkaz; Inicializací určujeme tzv. řídící proměnnou cyklu a její vstupní hodnotu. Pokud je splněna podmínka, provede se příkaz a poté se provede operace s řídící proměnnou cyklu uvedená v části krok. Poté se opět přejde na vyhodnocení podmínky. V následujícím příkladě se provede cyklus 10x (příklad odpovídá příkladu u cyklu while): for (int i = 1; i <= 10; i++) { // příkazy } Následující cyklus se provede 50x s tím, že řídící proměnná cyklu bude nabývat pouze sudých hodnot: for (int i = 2; i <= 100; i += 2) { // příkazy } Příkaz for lze přepsat do příkazu while následujícím způsobem: inicializace; while ( podmínka ) { příkaz; krok; }
13
Základy jazyka Příkazy break a continue Jazyk Java zná příkazy break a continue, které ovlivňují průběh zpracování příkazů v rámci cyklu (příkaz break se používá i v příkazu switch). Jestliže v těle cyklu použijeme break, výsledkem bude skok za konec tohoto cyklu. for (int i = 0; i <= 5; i++) { if (i == 3) break; System.out.println(i); } System.out.println("Konec programu"); Tato část programu bude mít tento výstup: 0 1 2 Konec programu Příkaz continue způsobí, že je přeskočen zbytek těla cyklu a znovu se testuje podmínka cyklu (v případě cyklu for se provede ještě krok řídící proměnné cyklu). Pokud ve výše uvedeném příkladu použijeme místo break příkaz continue, bude výstup vypadat takto: 0 1 2 4 5 Konec programu Break i continue lze uvést s návěstím a pak dojde ke skoku na toto návěstí, tj. lze opustit i několik do sebe vnořených cyklů. Návěstí ukončené dvojtečkou se uvádí v programu před začátkem vnějšího cyklu. /* CyklusSNavestim.java * ukazkovy priklad na pouziti navesti v cyklu while */ public class CyklusSNavestim { public static void main (String args[ ]) { int i = 0; vnejsicyklus: //definice návěstí "vnejsi cyklus" while (true) { //nekonečný cyklus while i++; int j = 0; while (true) { // vnořený nekonečný while j++; System.out.println("i: " + i + " j: "+j); if (j > i) { System.out.println("continue na vnejsicyklus (j > i)"); continue vnejsicyklus; }; if (j > 2) { System.out.println("break z vnitrniho cyklu (j > 2)"); break;
14
Základy jazyka }; }; System.out.println ("konec vnitrniho cyklu"); if (i > 3) { System.out.println("break z vnejsiho cyklu (i >3)"); break; }; }; System.out.println("konec vnejsiho cyklu"); }; } má následující výstup: i: 1 j: 1 i: 1 j: 2 continue na vnejsicyklus (j > i) i: 2 j: 1 i: 2 j: 2 i: 2 j: 3 continue na vnejsicyklus (j > i) i: 3 j: 1 i: 3 j: 2 i: 3 j: 3 break z vnitrniho cyklu (j > 2) konec vnitrniho cyklu i: 4 j: 1 i: 4 j: 2 i: 4 j: 3 break z vnitrniho cyklu (j > 2) konec vnitrniho cyklu break z vnejsiho cyklu cyklu (i > 3) konec vnejsiho cyklu
Volání metod V textu jsme se již mnohokrát setkali s voláním metod. Jak zjistíme později, rozlišují se metody třídy (statické) a metody instance. Jestliže potřebujeme použít metodu třídy, voláme ji uvedením jména třídy, tečky, jména metody a v kulatých závorkách parametry (nebo prázdné závorky pokud je metoda bez parametrů). V dokumentaci poznáte metody třídy dle toho, že ve specifikaci mají uvedeno klíčové slovo static. Například třída java.lang.Math poskytuje celou řadu metod třídy pro provádění různých matematických operací, některé z nich spolu s příklady jsou uvedeny v tabulce č.6 (podrobnější popis a přehled dalších je v on-line dokumentaci):
15
Základy jazyka Metoda static int abs (int a); static long abs (long a); static float abs (float a); static double abs (double a); static long round (double a); static int round (float a); static double sqrt (double a); static double cos (double a); static double sin (double a); static double tan (double a); static double pow (double a, double b); static double min (double a, double b); static float min (float a, float b); static int min (int a, int b); static long min (long a, long b); static double max (double a, double b); static float max (float a, float b); static int max (int a, int b); static long max (long a, long b);
Popis vrátí absolutní hodnotu parametru
Přiklad cislo2 = Math.abs(cislo1)
vrací nejbližší celé číslo výpočet druhé odmocniny trigonometrické funkce
cislo2 = Math.sqrt(cislo1)
umocňování, ab vrací menší z obou hodnot vrací větší z obou hodnot
tabulka 6 Metody třídy Math
Jak je v tabulce vidět (např. na metodě min), je možné v jedné třídě definovat více metod stejného jména s různým počtem, pořadím nebo typem parametrů. Tomuto říkáme přetěžování (overloading) metod. O tom, která z nich bude v programu použita, rozhodne překladač podle použitých parametrů. Pokud je některá metoda definována jen pro typ double (jako např. sqrt) není nutno přetypovávat hodnoty kratších typů na double, toto přetypování proběhne automaticky (tj. pokud proměnná cislo je typu int mohu napsat přímo Math.sqrt (cislo)). Jinak je tomu u typů návratových hodnot. Když metoda vrací hodnotu typu double, mohu ji uložit buď do proměnné typu double nebo ji mohu přetypovat do kratších typů (např. float či long). Lze tedy napsat: double odmocnina = Math.sqrt(cislo); float odmocnina = (float) Math.sqrt(cislo); následující zápis je chybný: float odmocnina = Math.sqrt(cislo);
// SPATNE
Druhým typem metod jsou metody instance, jediný rozdíl při volání těchto metod je, že uvádíme jméno instance a ne jméno třídy. Pro nejjednodušší programy a pro ladění se velmi často používají metody System.out.print(String s) nebo System.out.println(String s), které jsou určené pro výpis textového řetězce na konzoli. V tomto volání je tečka použita dvakrát, protože třída System obsahuje proměnnou out, která odkazuje na instanci třídy PrintStream, a pro tuto instanci vyvoláváme metodu print případně println, která je metodou třídy PrintStream.
16
Základy jazyka Ve volání metod se můžeme setkat i s více tečkami. S výjimkou metod z tříd (či třídy) z balíku (package) java.lang, je nutné uvádět úplné jméno balíku ve volání metod či odkazu na třídu (např. java.util.Date) nebo použít klauzuli import (viz následující kapitola).
Řetězce (třída String) Pro práci se řetězci (tj. s posloupností znaků jako je v našem příkladě "Muj prvni program") se v jazyce Java používá třída String. Třída String slouží k ukládání konstantních řetězců, jejichž hodnota se během činnosti programu nezmění (jedná se o příklad tzv. read-only třídy) – toto však neznamená, že stejný identifikátor nemůže v průběhu programu ukazovat na různé hodnoty (různé instance). Instanci třídy String lze definovat třemi způsoby. •
explicitně následující definicí: String s = new String("abcd");
•
implicitně, kdy překladač automaticky doplní potřebný kód pro vytvoření instance typu String: String s = "abcd";
•
implicitně, kdy se nedefinuje ani identifikátor (odpovídá konstantě primitivních datových typů): "abcd";
Pro práci s řetězci jsou definovány operátory + a += pro spojení dvou řetězců (instancí třídy String) do nové instance třídy String (do nového řetězce)8. Při použití operátoru += (např. retezec1 += retezec2) se odkaz na novou instanci přiřadí k identifikátoru uvedenému na levé straně výrazu. Různé způsoby deklarace a použití řetězců si ukážeme v následujícím příkladě. public class Retezce { public static void main (String args[ ]) { int cislo = 10; String retezec1 = "Vysledek je"; String retezec2 = new String ("korun"); System.out.println(retezec1 + " " + cislo + " " + retezec2); } } Příklad vypíše následující řádek: Vysledek je 10 korun Pokud se k řetězci připojuje operátorem + jednoduchá proměnná (int, long, ...), překladač automaticky zajistí převod proměnné na typ String (viz předchozí příklad, parametr příkazu println). Pokud se k řetězci připojuje instance objektu, překladač automaticky doplní volání metody toString(), která převede objekt na řetězec. Stejný způsob vyjádření objektu se používá i v některých metodách, např. v často používaných metodách print a println. Následující řádek: System.out.println (new Date()); který vypíše aktuální datum a čas, překladač interpretuje, jako kdyby vypadal následovně:
17
Základy jazyka Date datum = new Date(); System.out.println(datum.toString()); Při práci s řetězci v programu je třeba si uvědomit, že řetězce nejsou jednoduché proměnné, ale instance třídy String. Když potřebujeme porovnat obsah dvou řetězců, nelze použít následující porovnání retezec1 == retezec2
// SPATNE
protože tato podmínka porovnává, jestli oba identifikátory odkazují na stejnou instanci (na stejné místo v paměti). Pro porovnání obsahu dvou řetězců musíme použít metodu equals třídy String. Syntaxe porovnání řetězců retezec1 a retezec2 je následující: retezec1.equals(retezec2)
// DOBRE
a výsledek je typu boolean. Následující příkaz retezec1 = retezec2 nevytvoří kopii řetězce, ale přiřadí identifikátoru retezec2 odkaz na instanci, na kterou odkazuje identifikátor retezec1. Vytvořit kopii (tj. novou instanci se stejným obsahem) lze následujícím příkazem String retezec2 = new String(retezec1)9 Pro převody primitivních datových typů na řetězce je ve třídě String definována metoda třídy valueOf(). Například String retezec1 = String.valueOf(3.7629) uloží do objektu retezec1 hodnotu 3.7629 jako řetězec10. Stejného výsledku lze dosáhnout i následujícím výrazem String retezec1 = "" + 3.7629 kdy se využije vlastnosti automatické konverze proměnných na řetězec. Tato druhá varianta je však náročnější na rychlost zpracování, neboť zde se vedle konverze musí vytvořit objekt typu String s prázdným řetězcem a oba řetězce se musí spojit. Metoda String.valueOf s parametrem typu objekt vrací na výstupu výsledek metody toString() příslušného objektu. Ke třídě String existuje alternativní třída StringBuffer, která na rozdíl od třídy String není read-only při změnách nevytváří nové instance, čímž lze dosáhnout větší efektivity programu. Má obdobné metody jako třída String.
8
Jedná se o jediné případy přetížení (overloading) operátorů v Javě. Pro vytváření kopií objektů se doporučuje používat metodu clone(), třída String tuto metodu však nemá implementovánu. 10 Při prohlížení tohoto výrazu mohou u některých čtenářů vzniknout pochybnosti, proč zde není operátor new pro vytvoření nového objektu. Metoda String.valueOf sama uvnitř vytvoří novou instanci třídy String a na výstupu vrací pouze odkaz na tuto instanci, který se přiřadí k příslušnému identifikátoru. 9
18
Základy jazyka
Komentáře Pokud tvoříme program, je nezbytné uvádět v něm komentáře pro objasnění činnosti programu. Tyto komentáře poslouží jednak jiným programátorům pro pochopení vašeho programu, jednak i nám samotným, pokud se k programu vrátíme po delší době. Navíc firma Sun kromě překladače poskytuje i nástroj na automatické generování dokumentace z komentářů ve zdrojovém textu programu (javadoc). Krátký komentář je možno uvést přímo za příkaz, který chceme okomentovat. Komentář uvedeme se dvěma lomítky na začátku. Při překladu bude text od tohoto označení do konce řádku ignorován. Komentář delší než řádek začneme takto /* a ukončíme */, text mezi značkami je při překladu ignorován. Pokud chceme, aby byl komentář součástí automaticky generované dokumentace použijeme na začátku značku /** a ukončíme ho */.
19