Specializovan² t²denφk o v²poΦetnφ technice
o Internetu (CW 48/97)
Programovßnφ v jazyce Java
5. dφl
David ètrupl
StatickΘ prom∞nnΘ a metody
VÜechny prom∞nnΘ a metody, o kter²ch jsme doposud mluvili, byly tzv. instanΦnφ prom∞nnΘ a metody. Znamenalo to, ₧e s ka₧d²m vytvo°enφm novΘho objektu danΘ t°φdy se naalokovalo mφsto a vytvo°ily se novΘ kopie deklarovan²ch prom∞nn²ch. To mß logick² smysl, proto₧e instanΦnφ prom∞nnß je souΦßstφ definice objektu -- vytvo°φme-li nov² objekt, musφ se mu vytvo°it i novΘ vlastnosti.
V Jav∞ m∙₧eme pou₧φt jeÜt∞ jeden druh prom∞nn²ch -- tzv. statickΘ (t°φdovΘ) prom∞nnΘ. Tyto prom∞nnΘ jsou takΘ souΦßstφ definice t°φdy, ale jsou oznaΦeny klφΦov²m slovem static. Rozdφl oproti "normßlnφm" prom∞nn²m je ten, ₧e statickß prom∞nnß existuje pouze jednou pro celou t°φdu (proto se jφ takΘ n∞kdy °φkß t°φdovß prom∞nnß). Tyto prom∞nnΘ jsou dobrΘ pro udr₧ovßnφ globßlnφch informacφ o danΘ t°φd∞, nap°. m∙₧eme sledovat, kolik objekt∙ danΘ t°φdy mßme vytvo°eno. S existencφ statick²ch prom∞nn²ch je ·zce svßzßna i existence statick²ch metod. Tyto metody se podobn∞ jako statickΘ prom∞nnΘ vztahujφ k celΘ t°φd∞, a mohou tedy pou₧φvat pouze statickΘ prom∞nnΘ danΘ t°φdy (a samoz°ejm∞ i lokßlnφ prom∞nnΘ deklarovanΘ ve svΘm t∞le). Ukßzkou statickΘ metody je definice metody main. P°i volßnφ statick²ch metod nemusφ (a v∞tÜinou ani nenφ) vytvo°en objekt danΘ t°φdy (p°i volßnφ metody main nemusφ b²t vytvo°en objekt t°φdy, ve kterΘ se metoda main nachßzφ).
Specißlnφm druhem statick²ch prom∞nn²ch jsou konstanty, kterΘ jsou uvedeny klφΦov²m slovem final. Pokud se p°ed deklaracφ prom∞nnΘ objevφ slovo final, znamenß to, ₧e hodnota tΘto prom∞nnΘ nesmφ b²t v pr∙b∞hu v²poΦtu zm∞n∞na. Typickß kombinace klφΦov²ch slov je tedy public static final:
public class MojeTrida {
public static final int MAX_PO╚ET = 100;
static final float PI = 3.14;
public static void main(String args[]) {
System.out.println("Pi je : " + PI);
}
}
Pokud jsou prom∞nnΘ (konstanty) deklarovßny s modifikßtorem public, m∙₧eme jejich hodnotu pou₧φt i vn∞ definice danΘ t°φdy. V tomto p°φpad∞ je mo₧nΘ pou₧φt p°ed jmΘnem prom∞nnΘ jmΘno t°φdy, ve kterΘ je tato prom∞nnß (statickß) deklarovßna:
...
int k = MojeTrida.PI;
Konstanty v∞tÜinou oznaΦujeme identifikßtorem, kter² je cel² napsßn velk²mi pφsmeny -- pro snazÜφ orientaci v programu.
Pole a °et∞zce
Nynφ se zam∞°φme na pou₧φvßnφ dvou pravd∞podobn∞ nejΦast∞jÜφch datov²ch struktur. Pole i °et∞zce majφ podobnou syntaxi jako v jazyce C, ale jsou zde rovn∞₧ pom∞rn∞ podstatnΘ rozdφly. Nejprve se zmφnφme o konstruktorech a potom budeme pokraΦovat Φßstφ o polφch a °et∞zcφch.
Konstruktory
P°i vytvß°enφ objekt∙ p°φkazem new se v₧dy volß specißlnφ metoda -- konstruktor. Konstruktor je metoda, kterß nevracφ ₧ßdnou nßvratovou hodnotu (p°i pou₧itφ new by to nem∞lo smysl). Konstruktor pφÜeme podobn∞ jako metodu, jedin² rozdφl je v tom, ₧e mß v₧dy stejnΘ jmΘno jako t°φda, ke kterΘ pat°φ. Lze napsat n∞kolik konstruktor∙ pro jednu t°φdu, kterΘ se mohou liÜit poΦtem a druhem parametr∙. Konstruktory v∞tÜinou deklarujeme jako public -- ve°ejnΘ:
class Trida {
int velikost;
public Trida() {
...
}
public Trida(int jaka) {
velikost = jaka;
}
..
}
Prvnφ konstruktor nemß ₧ßdnΘ parametry, bude tedy vyvolßn, pokud p°i vytvß°enφ nezadßme ₧ßdn² parametr. Pokud p°i volßnφ new zadßme jeden parametr typu int, bude zavolßn druh² konstruktor. O tom, kter² konstruktor se zavolß, rozhodneme p°i vytvß°enφ objektu nßsledujφcφm zp∙sobem:
...
NovaTrida x = new NovaTrida(10); // zavolß konstruktor s parametrem int
Krom∞ vyvolßvßnφ majφ konstruktory jeÜt∞ n∞kolik zvlßÜtnφch vlastnostφ. D∙le₧itou vlastnostφ odliÜujφcφ konstruktory od normßlnφch metod je to, ₧e se ned∞dφ. Mφsto toho vÜak je na zaΦßtku konstruktoru zavolßn zd∞d∞n² konstruktor. Pokud chceme zavolat zd∞d∞n² konstruktor s parametry, musφme jako prvnφ p°φkaz konstruktoru uvΘst specißlnφ p°φkaz super s p°φsluÜn²mi parametry:
class NovaTrida extends Trida{
public NovaTrida() {
super(10);
}
P°φkaz super volß zd∞d∞n² konstruktor s uveden²m parametrem. Druhou mo₧nostφ je dalÜφ specißlnφ klφΦovΘ slovo this:
public NovaTrida(float x) {
this();
// zavolß konstruktor bez parametr∙
...// provedenφ vlastnφch inicializacφ
}
P°φkaz this volß jin² konstruktor ze stejnΘ t°φdy (s p°φsluÜn²mi parametry). Pokud jako prvnφ p°φkaz konstruktoru neuvedeme ani jedno z t∞chto klφΦov²ch slov, konstruktor se chovß, jakoby jeho prvnφ p°φkaz byl super(). Kdy₧ domyslφme tento systΘm volßnφ konstruktor∙, dojdeme k zßv∞ru, ₧e p°i konstrukci ka₧dΘho objektu je nejprve zavolßn konstruktor ve t°φd∞ Object, pak nßsledujφ vÜechny konstruktory na p°φsluÜnΘ v∞tvi v hierarchii d∞d∞nφ a nakonec se zavolß konstruktor napsan² ve vytvß°enΘ t°φd∞.
Pokud u svΘ t°φdy neuvedeme ₧ßdn² konstruktor, p°ekladaΦ vytvo°φ implicitnφ prßzdn² konstruktor bez parametr∙. To, ₧e je prßzdn², se projevφ zavolßnφm implicitnφho super() jako prvnφho a poslednφho p°φkazu, tj. provede se zd∞d∞n² konstruktor.
This a super
KlφΦovß slova this a super mohou b²t pou₧ita krom∞ konstruktor∙ takΘ pro p°φstup k prom∞nn²m a metodßm danΘho objektu. P°i tomto druhΘm pou₧itφ se vÜak s nimi vß₧e jinß syntaxe.
KlφΦovΘ slovo this pou₧ijeme v p°φpad∞, ₧e chceme p°istoupit k prom∞nnΘ nebo metod∞ aktußlnφho objektu. Proto₧e vÜak k aktußlnφmu objektu se p°istupuje implicitn∞, tj. v₧dy, pokud nestanovφme jinak, mß pou₧itφ klφΦovΘho slova this smysl asi pouze v p°φpad∞, p°ekryjeme-li si n∞jakou prom∞nnou lokßlnφ prom∞nnou:
class T {
int x;
void nastavX(int x) {
this.x = x;
}
}
Prom∞nnß x p°φsluÜejφcφ instanci objektu byla v uvedenΘ metod∞ zastφn∞na parametrem x -- hodilo se nßm tedy pou₧φt klφΦovΘ slovo this pro p°φstup k prom∞nnΘ objektu.
KlφΦovΘ slovo super se, podobn∞ jako u konstruktor∙, odkazuje na zd∞d∞nou metodu nebo vlastnost. Jeho nejΦast∞jÜφ pou₧itφ je u metod. Pokud ji₧ n∞jakß metoda obsahuje k≤d a my chceme v potomkovi jejφ chovßnφ rozÜφ°it, m∙₧eme zavolat zd∞d∞n² k≤d pomocφ super s nßsledujφcφ syntaxφ:
class U extends T {
void nastavX(int x) {
super.nastavX(x);
// prove∩ dalÜφ akce
}
}
P°i pou₧itφ this a super je t°eba si v₧dy uv∞domit, zda jsme v konstruktoru nebo v obyΦejnΘ metod∞ -- v ka₧dΘm z uveden²ch p°φpad∙ se toti₧ pou₧φvajφ trochu jin²m zp∙sobem. Pokud se zamyslφme nad ·Φelem volßnφ zd∞d∞n²ch metod, zjistφme, ₧e p°i volßnφ super.metoda() musφ b²t rozhodnuto o tom, kterß metoda se zavolß, ji₧ p°i p°ekladu. Pou₧ijeme-li terminologii C++, klφΦovΘ slovo super v tomto p°φpad∞ vypφnß mechanismus volßnφ virtußlnφch metod, kter² je jinak p°φtomen vÜude p°i normßlnφm volßnφ metod v Jav∞.
Pole
Pole je datovß struktura umo₧≥ujφcφ uklßdat posloupnosti hodnot stejnΘho typu. Prom∞nnou typu pole deklarujeme nßsledujφcφm zp∙sobem:
int pole1[];
float [] pole2;
Po jmΘnu typu uklßdan²ch element∙ nßsleduje deklarace jmΘna prom∞nnΘ. Äe se jednß o pole, to signalizuje pßr hranat²ch zßvorek umφst∞n²ch p°ed nebo za deklarovanou prom∞nnou. Tyto deklarace pouze uvßd∞jφ p°φsluÜnou prom∞nnou -- jeÜt∞ je vÜak t°eba vytvo°it vlastnφ pole. To se provede p°φkazem new -- pole je v Jav∞ v podstat∞ objekt specißlnφho typu.
Vytvo°enφ vlastnφho pole m∙₧eme uvΘst nap°. ji₧ v deklaraci prom∞nnΘ:
int pole3[] = new int[50];
Po vytvo°enφ pole se m∙₧eme na jednotlivΘ prvky odkazovat indexovßnφm -- index uvßdφme v hranat²ch zßvorkßch za jmΘnem prom∞nnΘ -- rozsah je od 0 do velikost-1.
POZOR: Velikost pole nelze uvΘst p°φmo v deklaraci (jako v jazyce C)! Je nutnΘ vytvo°it pole p°φkazem new tak, jak je uvedeno v naÜem p°φkladu. To, ₧e je pole vlastn∞ obyΦejn² objekt, poznßme podle toho, ₧e na prom∞nnou typu pole lze volat vÜechny metody deklarovanΘ ve t°φd∞ Object. Ka₧dß prom∞nnß typu pole mß navφc jednu specißlnφ prom∞nnou -- length. Tato prom∞nnß urΦuje dΘlku pole -- jejφ hodnota je stanovena p°i volßnφ new pro vytvo°enφ danΘho pole a b∞hem v²poΦtu ji nelze m∞nit. Chceme-li tedy vypsat obsah vytvo°enΘho pole3, m∙₧eme pou₧φt nßsledujφcφ cyklus:
for (int i=0; i < pole3.length; i++) {
System.out.println(pole3[i]);
}
Podobn∞ jako jednodimenzionßlnφ pole m∙₧eme vytvo°it i jeho vφcedimenzionßlnφ variantu:
int pole4[][] = new int[10][10];
Vφcedimenzionßlnφ pole je pole polφ, tj. ka₧dß dalÜφ dimenze je samostatnΘ pole. M∙₧eme toho vyu₧φt, pokud nap°. chceme vytvo°it troj·helnφkovou matici (p°i volßnφ new je mo₧nΘ uvΘst rozm∞r pouze u n∞kolika prvnφch dimenzφ):
float tMatice[][] = new float[10][];
for (int i=0; i < tMatice.length; i++) {
tMatice[i] = new float[i];
}
Tuto matici vÜak m∙₧eme prochßzet stejn²m cyklem jako ka₧dou jinou dvojdimenzionßlnφ matici, pokud pou₧ijeme sprßvn²m zp∙sobem prom∞nnou length:
for (int i=0; i < tMatice.length; i++) {
for (int j=0; j < tMatice[i].length; j++){
System.out.print(tMatice[i][j]);
}
System.out.println();
}
Pokud vytvß°φme pole objekt∙, je t°eba si uv∞domit, ₧e po vytvo°enφ pole volßnφm new mßme vytvo°en p°φsluÜn² poΦet prom∞nn²ch danΘho typu, ale nebyly jeÜt∞ vytvo°eny p°φsluÜnΘ objekty. V prom∞nn²ch pole budou tedy hodnoty null, dokud do nich nedosadφme odkazy na vytvo°enΘ objekty:
MojeTrida x[] = new MojeTrida[100];
//v prom∞nn²ch x[0] .. x[99] je hodnota null
x[0] = new MojeTrida();
// teprve nynφ je hodnota x[0]
// odkaz na p°φsluÜn² objekt
Mφsto vytvo°enφ pole pomocφ new lze pou₧φt tzv. konstantnφ inicializßtor pole. Tento zßpis je podobn² jazyku C a umo₧≥uje nßm rovnou zadat hodnoty jednotliv²m prom∞nn²m v poli:
int p[] = { 15, 7, 17, 2 };
MojeTrida y[] = { new MojeTrida(),
new MojeTrida() };
V prvnφm p°φpad∞ jsme vytvo°ili pole velikosti 4 typu int a ve druhΘm pole s velikostφ 2 typu MojeTrida.
╪et∞zce
╪et∞zce se pou₧φvajφ k uklßdßnφ textov²ch konstant. Syntaxe pou₧itφ °et∞zc∙ je podobnß jazyku C, ale stejn∞ jako u polφ (a mo₧nß jeÜt∞ vφce) jsou i zde rozdφly. Vypl²vajφ z toho, ₧e °et∞zce jsou v Jav∞ objekty. Tedy na rozdφl od jazyka C °et∞zce v Jav∞ nejsou pole znak∙.
Pro prßci s °et∞zci jsou v balφku java.lang dv∞ t°φdy: String a StringBuffer. Prvnφ z nich slou₧φ k uklßdßnφ konstantnφch °et∞zc∙ a jsou s nφ spojeny novΘ syntaktickΘ konstrukce. T°φda StringBuffer je obyΦejnß pomocnß t°φda slou₧φcφ k manipulaci s jednotliv²mi znaky °et∞zce.
Do prom∞nn²ch typu String lze p°i°azovat textovΘ (String) konstanty:
String s = "Ja jsem String";
Zßpis s uvozovkami vlastn∞ vytvß°φ nov² objekt t°φdy String. Na tento objekt lze vyvolßvat vÜechny metody definovanΘ ve t°φd∞ String stejn∞ jako na p°φsluÜnou prom∞nnou:
String t = s.toUpperCase();
String u = "hele".toUpperCase(); // povolen² zßpis
Objekty t°φdy String majφ konstantnφ hodnotu, tj. °et∞zec jednou ulo₧en² do prom∞nnΘ t°φdy String u₧ nelze m∞nit. Metody, kterΘ zdßnliv∞ m∞nφ hodnoty jednotliv²ch znak∙, v₧dy vytvß°ejφ nov² objekt t°φdy String s p°φsluÜn²mi zm∞nami. D∙vodem pro toto (na prvnφ pohled nepochopitelnΘ) chovßnφ °et∞zc∙ je to, ₧e konstantnφ °et∞zce jsou pou₧φvßny ve virtußlnφm stroji k uklßdßnφ jmen, a jsou tedy v class souborech uklßdßny zvlßÜtnφm zp∙sobem. B∞₧nΘmu programßtorovi nemusφ konstantnost °et∞zc∙ vadit, proto₧e jejich pou₧itφ v programu je relativn∞ jednoduchΘ a pochopitelnΘ.
JedinΘ, na co musφme dßvat p°i pou₧itφ objekt∙ t°φdy String pozor, je porovnßvßnφ °et∞zc∙. Pou₧itφ operßtoru == toti₧ v∞tÜinou nep°inese k²₧en² efekt, proto₧e tento operßtor u typu reference na objekt (jφm₧ typ String bezesporu je) porovnßvß odkazy a nikoliv obsahy p°φsluÜn²ch objekt∙. Chceme-li porovnat dva °et∞zce, pou₧ijeme nejpravd∞podobn∞ji metodu equals nebo equalsIgnoreCase:
String s = "ahoj";
if (s.equals("ahoj"))
//b∞₧n² test na stejnost °et∞zc∙
...
if ("ahoj".equals(s))
// i toto je sprßvn² zßpis
...
Krom∞ pou₧itφ textov²ch konstant je s typem String spojena jeÜt∞ jedna zvlßÜtnost -- lze na n∞j pou₧φt operßtor +. P°i sΦφtßnφ °et∞zc∙ dojde k jejich z°et∞zenφ. V²sledkem souΦtu je nov² °et∞zec s p°φsluÜn²m obsahem. Operßtor + lze pou₧φt bu∩ samostatn∞, nebo v kombinaci s p°i°azenφm:
String t = "Ja jsem" + "retez";
t += "ec"; // p°ipojenφ na konec °et∞zce
Ani p°i jednom ze zp∙sob∙ zßpisu vÜak nedochßzφ k modifikaci ₧ßdnΘho ze sΦφtan²ch °et∞zc∙, proto₧e, jak ji₧ bylo °eΦeno, typ String reprezentuje konstantnφ °et∞zce. V₧dy je naalokovßn nov² objekt a vrßcen odkaz na n∞j. Pokud chceme sami m∞nit hodnoty jednotliv²ch znak∙, pou₧ijeme t°φdu StringBuffer. Objekty t°φdy String m∙₧eme p°evΘst na objekty t°φdy StringBuffer pomocφ konstruktoru t°φdy StringBuffer, kter² mß jako parametr String:
String s = "retez";
StringBuffer sb = new StringBuffer(s);
S prom∞nnou t°φdy StringBuffer m∙₧eme potom pracovat pomocφ jejφch metod, kterΘ p°istupujφ k jednotliv²m znak∙m nebo n∞jak²m jin²m zp∙sobem modifikujφ obsah °et∞zce. P°evod zp∞t do podoby °et∞zce je mo₧n² nap°. pou₧itφm metody toString().
|