11. Implementace OOP v Javě
11.1. Objekt
Program v Javě je staticky strukturován na třídy, jejichž instance (objekty)
za běhu dynamicky programu vznikají a zanikají. Objekt je nejprve vytvořen
(instanciován), následně může být používán a nakonec je zrušen.
11.1.1. Vytvoření objektu
K vytvoření objektu slouží operátor new, jehož základní
syntaxe je (viz též 11):
new voláníKonstruktoru
Operátor alokuje paměť pro objekt a zavolá konstruktor (viz
11.2.3.), což je speciální metoda, která provádí inicializaci
objektu. Jméno konstruktoru je vždy shodné se jménem třídy objektu.
| Priklad 11.1. |
new String("ahoj");
vytvoří objekt třídy String a inicializuje ho konstruktorem
s parametrem "ahoj".
|
|
Operátor new vrací referenci, odkazující na vytvořený
objekt. Tato reference se při vytvoření objektu obvykle zároveň
ukládá (1) do referenční
proměnné (viz 7.2.):
| Priklad 11.2. |
String retezec; // deklarace proměnné
retezec = new String("ahoj"); // přiřazení reference
nebo zkráceně:
String retezec = new String("ahoj");
|
|
11.1.2. Používání objektu
Používání objektu spočívá ve volání metod a přímé manipulaci se
členskými proměnnými. Pro přístup k proměnné nebo metodě se používá tečková
notace:
reference.jménoProměnné
reference.voláníMetody
| Priklad 11.3. |
String retezec = new String("ahoj"); // vytvoření objektu
retezec = retezec.concat("!"); // volání metody
Metoda concat() vrací nový řetězec, který vznikne
připojením parametru na konec řetězce. Výsledek se přiřadí do proměnné
retezec.
|
|
Je možné použít i vícenásobnou přístupovou konstrukci:
| Priklad 11.4. |
int delka = retezec.trim().length();
Metoda trim() vrací referenci na nový řetězec (instanci třídy
String), který vznikl z původního oříznutím prázdných znaků. Metoda
length() vrací délku řetězce (typ int). Proměnné delka se
tedy přiřadí délka řetězce retezec po oříznutí metodou trim().
Předchozí zápis lze přepsat jako:
String orezanyRetezec = retezec.trim();
int delka = orezanyRetezec.length();
|
|
11.1.3. Zrušení objektu
Java neumožňuje přímé rušení (dealokaci) objektu. Objekt je zrušen automaticky
až tehdy, neexistuje-li na něj reference. Jsou například rušeny
všechny objekty lokálních proměnných při ukončení metody. "Ruční"
zneplatnění reference se provede přiřazením hodnoty null příslušné
referenční proměnné.
| Priklad 11.5. |
String retezec = new String("ahoj");
retezec = null; // zneplatnění reference -- objekt bude zrušen
|
|
Tento automatický mechanismus rušení objektů je znám pod názvem garbage
collection ("úklid smetí"). Jeho výhoda spočívá v nemožnosti
dealokovat již dealokovaný prostor nebo do něj zapisovat, což bývá v jiných
jazycích zdrojem mnoha nepříjemných chyb. Úklid se provádí buďto synchronně, tzn. až při nedostatku paměti pro
další alokace, nebo asynchronně na pozadí, pokud to daná platforma
umožňuje (Unix, Windows 95/NT). V programu lze o spuštění úklidu požádat
voláním metody System.gc(), například v době, kdy program neprovádí
výpočty.
Ještě před vlastním zrušením objektu se zavolá metoda finalize() (2) (je-li definována), kde může programátor uložit obsah proměnných
do souboru apod. Deklarace této metody vypadá následovně:
protected void finalize() throws Throwable
Při rušení objektu nedochází ke zřetězení volání metod finalize() jako
je tomu u konstruktorů při vytváření objektu (viz 11.2.3.).
11.2. Třída
Pro každý objekt musí být před jeho vytvořením deklarována třída, ať
už navržená v programu nebo knihovní. Knihovní třídy jsou uloženy
v balících (viz kap. 12.).
11.2.1. Deklarace třídy
Nejjednodušší deklarace třídy má syntaxi:
class JménoTřídy {
// tělo třídy
}
Identifikátor JménoTřídy slouží jako objektový typ, například v deklaraci
referenční proměnné (viz 7.2.). V těle třídy mezi složenými
závorkami mohou být deklarace členských proměnných
(viz 11.2.4.) a/nebo deklarace a definice metod
(viz 11.2.2.) (3) - obvykle v tomto pořadí, ale není to vyžadováno. Všimněte
si, že za uzavírající závorkou deklarace třídy není středník. Speciálním případem je třída, která neobsahuje metody. Ta pak slouží jako
klasická datová struktura (record v Turbo Pascalu, struct v C).
Obecná deklarace třídy vypadá takto:
[ modifikátory ] class jménoTřídy
[ extends jménoRodičovskéTřídy ]
[ implements seznamRozhraní ] {
// tělo třídy
}
| Priklad 11.7. |
|
Deklarace veřejné třídy Appletik, jejíž rodičovskou je třída
java.applet.Applet, a která implementuje rozhraní Cloneable
a Runnable (z balíku java.lang) vypadá takto:
public class Appletik extends java.applet.Applet
implements Cloneable, Runnable {
public void run() { // ...
}
// ...
}
Rozhraní Runnable obsahuje metodu run, a proto musí
třída Appletik její definici obsahovat. Rozhraní Cloneable je
prázdné a slouží jen k identifikaci třídy (její instance je možné klonovat
- viz 11.5.).
|
|
11.2.2. Metody
Nejjednodušší definice metody má tvar:
NávratovýTyp jménoMetody ( parametry ) {
// tělo metody
}
Obecná deklarace metody vypadá takto:
[ práva ] [static] [abstract] [final] [native]
[synchronized] NávratovýTyp jménoMetody ( parametry )
[throws seznamVýjimek ]
- práva - tato položka určuje přístupnost metody vně třídy
a pravidla pro dědičnost. Metoda může být buď veřejná (public),
chráněná (protected), soukromá (private) nebo
nemusí mít práva specifikována vůbec (default access) (7) . Více viz
11.3. a 11.4..
- static - označuje statickou metodu.
Statické metody je možné narozdíl od nestatických volat i tehdy, neexistuje-li
žádná instance dané třídy. Mohou však přímo manipulovat pouze se statickými
(a svými lokálními) proměnnými.
Volání statické metody má tvar:
[ JménoTřídy. ] jménoMetody ( parametry );
JménoTřídy se nemusí specifikovat uvnitř třídy, která statickou metodu
definuje.V jedné třídě nemůže být definována shodně pojmenovaná statická i nestatická
metoda se stejným počtem a typem parametrů - jinak dojde k chybě při
překladu.
- abstract - metody deklarované jako abstraktní nemají
v dané třídě tělo a musí být definovány až potomky třídy. Třída, která
obsahuje abstraktní metody, nemůže být instanciována a musí být rovněž
deklarována jako abstraktní (viz 11.2.1.).
| Priklad 11.11. |
abstract class A {
abstract void metoda(); // deklarace abstraktní metody
}
|
|
- synchronized - viz 16.5.2..
- final - označuje koncovou metodu. Koncová metoda nesmí
být potomky překryta.
- native - nativní metody umožňují sloučit programy psané
v Javě a jiných jazycích. Například většina nízkoúrovňových (8) metod z Java Core API je nativních.
V běžných aplikacích se nativní metody nepoužívají kvůli jejich
nepřenositelosti. V appletech se používat nesmí.
- Klíčové slovo throws uvozuje jedno nebo více jmen tříd výjimek (viz kap. 13.), které může metoda vyvolat. Je-li výjimek více
jsou odděleny čárkami.
| Priklad 11.12. |
|
Následující metoda deklaruje, že může vyvolat výjimky třídy ArithmeticException a SecurityException:
void metoda() throws ArithmeticException, SecurityException {
// ...
}
|
|
Zárověň nelze použít dvojic static abstract a final abstract.
Argumenty metod se vždy předávají hodnotou, tzn. že hodnotu argumentu
sice v metodě měnit lze, ale navenek se to neprojeví:
| Priklad 11.13. |
|
Metoda prohod() má zaměnit hodnoty svých dvou argumentů:
void prohod(int x, int y) {
int tmp = x; x = y; y = tmp;
}
void hop() {
int a = 1, b = 2;
prohod(a,b); // tohle nefunguje! (1)
// nadále a = 1, b = 2
}
Po zavolání metody prohod (1) se hodnoty argumentů nezamění. Pro
správnou funkci je třeba provést tuto úpravu: proměnné x, y se
umístí do jedné instance třídy (2), na kterou se metodě prohod předá
reference (3):
class XY {
public int x, y; // (2)
}
void prohod(XY xy) {
int tmp = xy.x;
xy.x = xy.y;
xy.y = tmp;
}
void hop() {
XY xy = new XY(); // objekt xy namísto a, b
xy.x = 1;
xy.y = 2;
prohod(xy); // (3)
// nyní: xy.x = 2, xy.y = 1
}
|
|
Podobně jako lze měnit obsah přístupných členských proměnných, lze také měnit
hodnoty položek pole, které je předáno jako argument metodě.
11.2.3. Konstruktory
Konstruktor je speciální metoda, která se volá pouze při vytváření
objektu (viz 11.1.1.) a slouží k jeho inicializaci. Jméno
konstruktoru musí být shodné se jménem třídy, v níž je definován. Návratový
typ konstruktoru se neuvádí.Pro konstruktory platí pravidla uvedená pro metody (viz 11.2.2.). Jejich
deklarace však nesmí obsahovat modifikátory abstract, final, native, static a synchronized a nedochází k dědění konstruktorů.
| Priklad 11.14. |
class Bod {
Bod() { // konstrukor třídy Bod
// ...
}
}
|
|
Každá třída má alespoň jeden konstruktor. Pokud ve třídě konstruktor není
uveden, vytvoří překladač automaticky implicitní konstruktor bez
parametrů (default constructor), který nic neprovádí. Konstruktor každé třídy musí na začátku obsahovat volání konstruktoru
rodičovské třídy, aby se zajistila řádná inicializace zděděných proměnných
(tzv. řetězení konstruktorů).
K volání rodičovského konstruktoru slouží klíčové slovo super (viz též
11.8.).
super( parametryKonstruktoru );
Toto volání musí být provedeno jako první, aby se zajistila řádná inicializace
v rodičovské třídě. Volání rodičovského konstruktoru lze vynechat pouze
v případě, že rodičovská třída má pouze jeden konstruktor bez parametrů nebo
konstruktor implicitní - pak toto volání překladač na začátek konstruktoru
sám doplní.
Volání konstruktoru téže třídy se provádí pomocí operátoru this (viz též
str. 11). Volat konstruktor však lze opět pouze z konstruktoru
a toto volání musí být provedeno jako první.
| Priklad 11.15. |
class Trida {
public Trida() {
this(0); // volání konstruktoru (*)
}
public Trida(int i) { // (*)
// ...
}
}
|
|
Pokud je potřeba zabránit instanciování dané třídy z jiných tříd, stačí
nadefinovat všechny její konstruktory jako soukromé.
11.2.4. Členské proměnné
Členské proměnné se deklarují v těle třídy - mimo těla metod (jinak
by se jednalo o lokální proměnné). Podle konvence se deklarace členských
proměnných uvádějí před deklaracemi metod. Pro členské proměnné platí podobná pravidla jako pro lokální proměnné (viz
9.4.). Jejich deklarace může navíc obsahovat následující modifikátory:
[ práva ] [static] [transient] [final] [volatile]
typ jménoProměnné
Pokud není členská proměnná v deklaraci inicializována, je jí přiřazena
implicitní hodnota:
- nula - pro celočíselné a racionální typy,
- \u0000 - pro typ char,
- false - pro logický typ,
- null - pro referenční typy (neplatná reference).
| Priklad 11.17. |
|
Deklarace veřejné celočíselné statické konstanty MAX_VALUE,
která je inicializována číslem 0x7fffffff (maximální hodnota pro typ
int) vypadá takto:
public static final int MAX_VALUE = 0x7fffffff;
|
|
11.3. Dědičnost
Třída-potomek se od rodičovské třídy odvodí v deklaraci pomocí klíčového slova
extends (viz 11.2.1.). Potomek od přímého rodiče dědí, tj.
přejímá jako by byly znovu definovány, všechny členské proměnné a metody,
které: (12)
- jsou deklarovány jako veřejné (public) nebo chráněné (protected),
- nemají explicitně určena přístupová práva a zároveň se rodičovská třída
nachází ve stejném balíku jako potomek.
Potomek nedědí členské proměnné a metody, které:
- jsou deklarovány jako soukromé (private) (13) ,
- jsou deklarovány v jiném balíku a nejsou veřejné (public),
- mají v potomkovi stejné jméno (a typy parametrů - u metod) jako
v rodičovské třídě. Tyto členské proměnné (metody) jsou předefinovány -
hovoří se o zastínění (hiding) proměnných a překrytí
(overriding) metod.
Při překrývání metod je možné přístupová práva pouze rozšířit (na public
nebo protected - v případě implicitních práv). Naopak seznam (resp.
typy) výjimek deklarovaných pomocí throws lze pouze zúžit. Na
změny modifikátorů a členské proměnné omezení kladena nejsou. K překrytým metodám a zastíněným proměnným rodiče se přistupuje pomocí
operátoru super (14) (viz též str.
11), který vrací referenci na rodičovskou třídu:
super. jménoČlenskéProměnné
super. jménoMetody
| Priklad 11.18. |
class A {
void a() throws Exception {
// ...
}
}
class B extends A {
void a() { // zúžení seznamu výjimek
try {
super.a(); // volání metody rodiče: A.a
a(); // volání sama sebe
// ...
} catch (Exception e) {}
}
}
|
|
11.4. Přístupová práva
Členské proměnné a metody mají specifikována přístupová práva (viz
kap. 11.2.2. a 11.2.4.) určující okruh tříd, které k nim
mají přístup. Přístupem se rozumí možnost přímé manipulace se členskými
proměnnými a volání metod.
Třída má přístup pouze k metodám a členským proměnným, které:
- sama deklaruje,
- dědí (viz 11.3.),
- jsou deklarovány jako public v jiných veřejných třídách,
- jsou umístěny ve třídě téhož balíku (viz kap. 12.)
a zároveň mají přístup nespecifikován nebo nastaven jako public či protected.
Třída nemá přístup ke členským proměnným a metodám z jiných balíků, které jsou
soukromé, chráněné nebo mají nespecifikován přístup a dále ke třídám z jiných
balíků, které nejsou deklarovány jako veřejné (15) .
| Priklad 11.19. |
|
V příkladu 11.16. je konstanta MAX_VALUE deklarována jako
veřejná a je tedy přímo přístupná všem ostatním třídám (i mimo svůj balík).
|
|
11.5. Třída Object
Třída Object z balíku java.lang je kořenovou třídou ve
stromu tříd, tj. všechny třídy, ať už knihovní nebo navržené
programátorem, mají společného (nepřímého) rodiče třídu Object.
Object definuje základní metody, které musí mít každý objekt v Javě -
většinu z nich používá runtime systém. Jedná se o metody:
- protected native clone() - vytvoří identický objekt (ale nevolá
konstruktor) a přiřadí stejné hodnoty všem členským
proměnným. (16) Funguje pouze u tříd, které implementují
rozhraní Cloneable.
- public boolean equals(Object obj) - porovnává objekt s objektem
obj (způsob porovnávání se pro jedntlivé potomky liší).
- public final Class getClass() - vrací objekt reprezentující
třídu instance v runtime systému.
- protected void finalize() throws Throwable - je volána při
úklidu (viz 11.1.3.); standardně neprovádí nic.
- public int hashCode() - používá se k hašování (17) , není-li překrytá
vrací totéž co metoda System.identityHashCode().
- public String toString() - vrací identifikační řetězec objektu
(často předefinovávaná metoda pro účely ladění).
- wait(), notify(), notifyAll() - viz
16.5.3..
11.6. Rozhraní (interface)
Rozhraní (interface) je syntaktická struktura obsahující
deklarace konstant a metod (bez implementací). Deklarace rozhraní je podobná
deklaraci třídy:
[public] interface jménoRozhraní
[ extends seznamRozhraní ] {
// tělo rozhraní
}
- public - označuje veřejné rozhraní. Veřejné rozhraní je
přístupné i mimo balík (viz kap. 12.), kde je deklarováno.
Není-li rozhraní veřejné, je přístupné pouze ve svém balíku.
- V nepovinné části za klíčovým slovem extends (angl. rozšiřuje) následuje jedno nebo více jmen rozhraní, jejichž konstanty
a metody toto rozhraní dědí (18) .
Děděné deklarace konstant a metod z více rodičovských rozhraní nesmí
kolidovat, podobně jako je tomu u deklarací v rámci jedné
třídy (19) .
Kromě hierarchického stromu tříd tedy v Javě existuje ještě graf
rozhraní. Oproti třídě může mít rozhraní více rodičů - jména rodičovských
rozhraní jsou oddělena čárkami:
| Priklad 11.20. |
|
Deklarace rozhraní Slucujici, které má dvě rodičovská rozhraní:
Runnable a Cloneable vypadá takto:
interface Slucujici extends Runnable, Cloneable {}
|
|
Tělo rozhraní smí obsahovat pouze deklarace konstant a metod. Při
tom platí následující pravidla:
- Všechny metody a konstanty uvedené v deklaraci rozhraní jsou automaticky
veřejné (public) a nesmí mít specifikována přístupová práva
protected ani private.
- Všechny metody jsou navíc automaticky abstraktní.
- I když u proměnné není modifikátor final, jedná se vždy
o konstantu.
- V rozhraní nesmí být použity modifikátory: transient, volatile a synchronized.
| Priklad 11.21. |
public interface NoveRozhraní {
int MAX_DELKA_RETEZCE = 20; // automaticky veřejná konstanta
void vypis(String retezec); // automaticky veřejná abstraktní metoda
}
|
|
Rozhraní se používají k zachycení společných prvků tříd, které spolu nemusí
souviset ve stromu dědičnosti - společnými prvky jsou konstanty a metody
deklarované rozhraním. Třída, která implementuje dané rozhraní (viz
11.2.), musí obsahovat definice všech(!) metod tohoto rozhraní. Rozhraní
pak lze použít jako objektový typ třídy:
| Priklad 11.22. |
|
Program bude obsahovat schránku (clipboard), přes kterou lze
kopírovat, a vkládat objekty (text, obrázky, zvuky). Všechny objekty, které
lze do schránky umístit, musí kopírování samy umožňovat - musí obsahovat
metodu copy(). Z hlediska návrhu není vhodné, aby třídy takto rozdílných objektů měly
společného rodiče - třídu, deklarující metodu copy(), kterou všechny
povinně zdědí. Výhodnější je deklarovat rozhraní (Clip) obsahující
metodu copy(), které budou jednotlivé třídy implementovat - i v tomto
případě bude zaručena podpora kopírování ze strany objektů.
public interface Clip {
byte[] copy();
}
Metoda copy() bude vracet pole bytů reprezentující objekt ve schránce.
Každá třída, jejíž instance lze kopírovat přes schránku, musí implementovat
rozhraní Clip. Její deklarace bude:
class Obrazek implements Clip {
byte[] copy() {
// ...
}
}
Schránka pak může obsahovat libovolný objekt typu Clip:
class Schranka {
byte[] schranka;
// metoda pro vložení (kopírovatelného) objektu
public void vlozit(Clip objekt) { // typ parametru je rozhraní
schranka = objekt.copy(); // vložení objektu do schránky
}
// ...
}
|
|
Rozhraní může být prázdné. Třídu implementující rozhraní lze identifikovat
operátorem instanceof, viz 8.2..
Rozhraní neumožňují vícenásobnou dědičnost, neboť třídy prostřednictvím
rozhraní nedědí definice (kód) metod. Hierarchie rozhraní je nezávislá na
hierarchii tříd.
11.7. Inicializace tříd a rozhraní
K inicializaci třídy nebo rozhraní dochází při prvním aktivním
použití, které nastane, je-li splněna aspoň jedna
z podmínek (20) :
- je vyvolána metoda nebo konstruktor deklarovaný danou třídou.
- je vytvořeno pole s prvky typu dané třídy,
- je proveden přístup k nekonstantní členské proměnné třídy nebo konstantě
rozhraní,
- je proveden přístup ke členské proměnné třídy s modifikátorem final
nebo static, která je inicializována hodnotou vypočítanou za běhu programu.
Inicializace třídy se skládá z inicializace statických členských proměnných a
vykonání statických inicializátorů (viz dále), přičemž před tím musí
být inicializována nejprve její rodičovská třída. Inicializace rozhraní spočívá pouze v inicializaci v něm definovaných
konstant, nedochází automaticky k inicializaci rodičovského rozhraní.
11.7.1. Inicalizátory
Od JDK 1.1 lze k inicializaci třídy (resp. instance) použít jeden nebo více
statických (resp. nestatických) inicializátorů. Syntaxe vypadá následovně:
deklaraceTřídy {
[static] {
// inicializace
}
}
Jedná se o blok, který obsahuje inicializace členských proměnných. Statický
inicializátor vyvolává třída a to pouze jednou. Nestatický inicializátor
vyvolávají všechny konstruktory třídy. Nestatický inicializátor smí vyvolávat
pouze výjimky, které deklarují všechny konstruktory třídy. (21) .
| Priklad 11.23. |
class A {
String ahoj;
static {
ahoj = "ahoj";
}
// ...
}
|
|
11.8. Vnořené třídy
Od verze JDK 1.1 je možné třídy do sebe vnořovat (22) a Java rozeznává dva druhy tříd:
- Třídy nejvyšší úrovně (top-level classes) - jsou
"normální" třídy a statické třídy (23) umístěné v jiné
třídě (na úrovni vnoření nezáleží). Do této skupiny se také řadí také vnořená rozhraní.
| Priklad 11.24. |
|
Obě následující třídy TopLevel1 a TopLevel2 jsou
třídy nejvyšší úrovně.
public class TopLevel1 {
static private class TopLevel2 {
// ...
}
interface Cool {
// i rozhraní může být vnořené
}
}
|
|
Vnořené třídy a rozhraní mohou mít specifikována přístupová práva a mimo
vnější třídu mohou být zpřístupněna udáním úplného jména. Podobně jako
u balíků (viz kap. 12.) se používá tečková notace: TopLevel1.TopLevel2 (24) je úplné jméno vnořené třídy TopLevel2 z příkladu 11.24.. Třídy nejvyšší úrovně umožňují vytvářet hierarchickou strukturu na úrovni
tříd, nikoliv pouze na úrovni balíků.
- Vnitřní třídy (inner classes) - jsou nestatické vnořené třídy a lze je umístit i do těla metody nebo do bloku.
Vnitřní třídy definované v bloku nebo metodě nejsou "zvenku" přístupné
a nemohou mít modifikátory public, protected, private
a static. Vnitřní třídy nesmí obsahovat statické proměnné a metody,
statické inicializátory, ani deklarace rozhraní.
Zvláštním druhem vnitřní třídy je nepojmenovaná, anonymní
třída (anonymous class). Deklarace anonymní třídy je součástí
rozšířené syntaxe operátoru new:
new Typ ( parametry ) {
// tělo anonymní třídy
}
Typ představuje:
- jméno konstruktoru rodičovské(!) třídy, od které je anonymní třída
odvozena (následují jeho parametry), nebo
- jméno rozhraní - anonymní třída jako jediná může přímo instanciovat
rozhraní (zde se parametry neuvádí). (25)
| Priklad 11.25. |
|
Vytvoření členské proměnné r jako instance rozhraní Runnable (viz
též 16.2.) vypadá následovně:
class NejakaTrida {
Runnable r = new Runnable() {
public void run() {
// ...
}
}
}
|
|
Vnitřní třídy mají přímý přístup ke všem, tedy i soukromým proměnným a metodám
vnější třídy a nemusí používat jejich úplná jména. Třídy nejvyšší
úrovně mohou manipulovat pouze se statickými proměnnými a statickými metodami
vnějších tříd. Pokud je vnitřní třída umístěna v metodě nebo bloku s používá lokální proměnné
nebo parametry, které sama nedeklaruje, musí tyto být deklarovány
s modifikátorem final.
Protože vnitřní (tj. nestatická) třída nemůže existovat samostatně, nýbrž je
vázána na třídu vnější, je třeba v některých případech použití operátorů new a super explicitně uvést referenci na instanci
příslušné vnější třídy:
referenceNaVnějšíInstanci. new
referenceNaVnějšíInstanci. super
Podobně byla rozšířena syntaxe operátoru this, kde je možné specifikovat
jméno vnější třídy:
JménoVnějšíTřídy. this
| Priklad 11.26. |
class Vnejsi {
static int i = 10; // (1)
int x;
class Vnitrni {
Vnitrni() {
int i = 0; // (2)
int j = Vnejsi.this.i; // (3)
// ...
}
}
static Vnitrni vytvor(Vnejsi obj) {
// ...
return obj.new Vnitrni(); // (4)
}
}
Na řádce (3) je proměnné j přiřazen obsah statické proměnné i
(1) - v případě neuvedení třídy by se přiřadila hodnota proměnné i (2). Na řádce (4) je nutné u operátoru new uvést referenci na instanci
obj, neboť metoda vytvor() je statická a jako taková nemůže
(automaticky) předat konstruktoru referenci na instanci vnější třídy.
|
|
|