Co jsou konstruktory pro java. Konstruktéři

1. Koncept výchozího konstruktoru

Výchozí konstruktor je konstruktor, který nemá žádné parametry. Výchozí konstruktor může být deklarován explicitně ve třídě nebo generován automaticky.

V nejobecnějším případě pro třídu ClassName je výchozí konstruktor následující:

třída Jméno třídy (... // deklarace konstruktoru Jméno třídy () ( // tělo konstruktoru // ... } ... }
2. V jakých případech je výchozí konstruktor generován ve třídě automaticky a v jakých ne? Příklad

Pokud nejsou ve třídě deklarovány žádné konstruktory, vygeneruje se výchozí konstruktor. To znamená, že výchozí konstruktor je automaticky generován ve třídě pouze v případě, že třída neobsahuje jiné implementace konstruktoru. Pokud třída obsahuje implementaci alespoň jednoho konstruktoru s parametry, pak aby bylo možné deklarovat výchozí konstruktor, musí být ve třídě explicitně deklarován.

Například. V následující deklaraci třídy se automaticky vygeneruje výchozí konstruktor

třída CMyClass ( int d; int GetD () ( vrátit se d; ) prázdnota SetD ( int nd) (d = nd;))

Výše uvedený kód znamená, že můžete deklarovat objekt třídy pomocí výchozího konstruktoru:

// funguje, protože třída již neimplementuje žádné konstruktory CMyClass mc = Nový CMyClass ();

Pokud do těla třídy CMyClass přidáte alespoň jeden další konstruktor (například konstruktor s jedním parametrem), výchozí konstruktor se nevygeneruje automaticky.

třída CMyClass ( int d; // výchozí konstruktor se již negeneruje automaticky CMyClass ( int nd) (d = nd;) int GetD () ( vrátit se d; ) prázdnota Nastavit ( int nd) (d = nd;))

Po výše uvedené implementaci se deklarace objektu pomocí výchozího konstruktoru nezdaří. Je však možné deklarovat objekt pomocí konstruktoru s jedním parametrem.

// chyba kompilace, protože ve třídě již byl deklarován jiný konstruktor // CMyClass mc = new CMyClass (); CMyClass mc2 = Nový CMyClass (7); // a tento kód funguje

V důsledku provedení výše uvedeného řádku se zobrazí chyba kompilace:

Konstruktor CMyClass () není definován

Aby bylo možné mít implementaci výchozího konstruktoru a deklarovat objekt třídy pomocí výchozího konstruktoru, musí být nastaven explicitně. Mohlo by to být například takto

třída CMyClass ( int d; // explicitně deklaruje výchozí konstruktor CMyClass () (d = 0;) // deklarace konstruktoru s 1 parametrem, CMyClass ( int nd) (d = nd;) int GetD () ( vrátit se d; ) prázdnota Nastavit ( int nd) (d = nd;))

Po takové implementaci můžete vytvořit instanci třídy například pomocí dvou konstruktorů

CMyClass mc = Nový CMyClass (); // je volán výchozí konstruktor mc.d = 25; CMyClass mc2 = Nový CMyClass (5); // je volán konstruktor s 1 parametrem

3. Volání konstruktorů z jiných konstruktorů. Příklad

Programovací jazyk Java umožňuje volat konstruktory třídy z jiného konstruktoru stejné třídy. K tomu se používá klíčové slovo toto, což je odkaz na aktuální třídu.

Příklad. Příklad ukazuje použití třídy CPixel, která implementuje pixel na obrazovce monitoru.

// Třída, která implementuje pixel na obrazovce monitoru veřejnost třída CPixel ( // interní proměnné třídy soukromé int x, y; // souřadnice pixelů soukromé int barva; // barva pixelu // konstruktor bez parametrů (výchozí konstruktor) CPixel () (x = y = barva = 0;) // konstruktor se 2 parametry, které inicializují pouze souřadnice CPixel ( int _X, int _y) (x = _x; y = _y; barva = 0;) // konstruktor s 1 parametrem, který inicializuje pouze barvu CPixel ( int _color) (barva = _barva; x = y = 0;) // 3-parametrový konstruktor, který volá 2-parametrový konstruktor CPixel ( int _X, int _y, int _barva) ( // volání konstruktoru se 2 parametry: první operace je povinná a pouze jednou tento(_x, _y); // toto (_color); // opakované volání konstruktoru je zakázáno tento.barva = _barva; // takže je to možné) // metody přístupového objektu int GetX () ( vrátit se X; ) int GetY () ( vrátit se y; ) int GetColor () ( vrátit se barva; ))

Použití třídy CPixel v jiném kódu programu (metoda)

CPixel cp1 = Nový CPixel (2,8); // volání konstruktoru se 2 parametry CPixel cp2 = Nový CPixel (3,5,8); // zavolá konstruktor, který zavolá jiný konstruktor int d; d = cpl.GetX (); // d = 2 d = cp2.GetColor (); // d = 8 d = cp2.GetY (); // d = 5 ...

4. Jaká omezení (požadavky) jsou kladeny na volání jiných konstruktorů z konstruktoru třídy?

Chcete-li správně volat další konstruktory z konstruktoru třídy, musíte dodržovat následující požadavky (omezení):

  • lze volat pouze jeden další konstruktor třídy. Je zakázáno volat dva nebo více dalších konstruktorů této třídy. To vyplývá z logiky, že konstruktor třídy je určen k vytvoření objektu třídy pouze jednou (a nikoli dvakrát nebo vícekrát);
  • volání jiného konstruktoru musí být první operací ve volajícím konstruktoru. Pokud je ve volajícím konstruktoru volání jiného konstruktoru implementováno druhou (třetí atd.) operací, kompilátor vygeneruje chybu.
Konstruktor je struktura podobná metodě, jejímž účelem je vytvořit instanci třídy. Vlastnosti konstruktoru:
  • Název konstruktoru se musí shodovat s názvem třídy (podle konvence je první písmeno velké, obvykle podstatné jméno);
  • Každá třída má konstruktor. I když jste to nenapsali, kompilátor Java sám vytvoří výchozí konstruktor, který je prázdný a nedělá nic jiného, ​​než volá konstruktor nadtřídy.
  • Konstruktor je podobný metodě, ale není to metoda, dokonce se nepovažuje za člena třídy. Proto jej nelze zdědit nebo přepsat v podtřídě;
  • Konstruktory se nedědí;
  • Ve třídě může být několik konstruktorů. V tomto případě se říká, že konstruktory jsou přetížené;
  • Pokud není ve třídě popsán žádný konstruktor, kompilátor automaticky přidá do kódu konstruktor bez parametrů;
  • Konstruktor nemá návratový typ, nemůže to být ani typ void, pokud se vrátí typ void, tak už to není konstruktor, ale metoda, navzdory shodě s názvem třídy.
  • Příkaz return je v konstruktoru povolen, ale pouze prázdný, bez návratové hodnoty;
  • V konstruktoru lze použít modifikátory přístupu, lze nastavit jeden z modifikátorů: veřejný, chráněný, soukromý nebo bez modifikátoru.
  • Konstruktor nemůže mít abstraktní, konečné, nativní, statické nebo synchronizované modifikátory;
  • Klíčové slovo this odkazuje na jiný konstruktor ve stejné třídě. Je-li použito, musí být jeho volání na prvním řádku konstruktoru;
  • Klíčové slovo super volá konstruktor rodičovské třídy. Pokud je použit, musí být přístupný na prvním řádku konstruktoru;
  • Pokud konstruktor nevolá konstruktor nadřazené třídy nadřazené třídy (s argumenty nebo bez nich), kompilátor automaticky přidá kód pro volání konstruktoru nadřazené třídy bez argumentů;

Výchozí konstruktor

Každá třída má konstruktor. I když jste to nenapsali, kompilátor Java sám vytvoří výchozí konstruktor. Tento konstruktor je prázdný a nedělá nic jiného, ​​než volá konstruktor nadtřídy. Tito. pokud napíšete: public class Příklad () pak je to ekvivalentní psaní: public class Příklad (Příklad () (super;)) B tento případ nadřazená třída není explicitně specifikována a ve výchozím nastavení všechny třídy Java dědí třídu Object, takže je volán konstruktor třídy Object. Pokud je ve třídě definován konstruktor s parametry, ale neexistuje žádný přetížený konstruktor bez parametrů, je volání konstruktoru bez parametrů chybou. V Javě však od verze 1.5 můžete používat konstruktory s argumenty proměnné délky. A pokud existuje konstruktor, který má argument proměnné délky, pak volání výchozího konstruktoru nebude chybou. Nebude, protože argument proměnné délky může být prázdný. Například následující příklad se nezkompiluje, ale pokud zrušíte komentář konstruktoru s argumentem proměnné délky, pak bude kompilace a spuštění úspěšné a jako výsledek řádku kódu DefaultDemo dd = new DefaultDemo (); bude zavolán konstruktor DefaultDemo (int ... v). Přirozeně je v tomto případě nutné použít JSDK 1.5. Soubor DefaultDemo.java třída DefaultDemo (DefaultDemo (String s) (System.out.print ("DefaultDemo (String)");) / * DefaultDemo (int ... v) (System.out.println ("DefaultDemo (int ...)");) * / public static void main (String args) (DefaultDemo dd = new DefaultDemo ();)) Výstup programu s nekomentovaným konstruktorem: DefaultDemo (int...) Nicméně v běžném případě, kdy není ve třídě na adrese definován žádný konstruktor vše, volání výchozího konstruktoru (bez parametrů) bude vyžadováno, protože nahrazení výchozího konstruktoru proběhne automaticky.

Při vytváření objektu se postupně provádějí následující akce:
  • Třída objektu se hledá mezi třídami již použitými v programu. Pokud neexistuje, hledá se ve všech adresářích a knihovnách, které má program k dispozici. Jakmile je třída nalezena v adresáři nebo knihovně, jsou vytvořena a inicializována statická pole třídy. Tito. pro každou třídu jsou statická pole inicializována pouze jednou.
  • Paměť pro objekt je přidělena.
  • Pole třídy jsou inicializována.
  • Prochází konstruktorem třídy.
  • Vytvoří se odkaz na vytvořený a inicializovaný objekt. Tento odkaz je hodnotou výrazu, který vytváří objekt. Objekt lze také vytvořit voláním metody newInstance () třídy java.lang.Class. V tomto případě je použit konstruktor bez seznamu parametrů.

Přetížení konstruktérů

Konstruktory stejné třídy mohou mít stejný název a různé podpisy. Tato vlastnost se nazývá přetěžování. Pokud má třída více konstruktorů, dochází k přetížení konstruktoru.

Parametrizované konstruktéry

Signatura konstruktoru je počet a typy parametrů a také pořadí jejich typů v seznamu parametrů konstruktoru. Návratový typ je ignorován. Konstruktor nevrací žádné parametry. Toto prohlášení v jistém smyslu vysvětluje, jak Java rozlišuje mezi přetíženými konstruktory nebo metodami. Java rozlišuje přetížené metody nikoli podle návratového typu, ale podle počtu, typů a posloupnosti typů vstupních parametrů. Konstruktor ani nemůže vrátit typ void, jinak se změní na běžnou metodu, i když se podobá názvu třídy. Následující příklad to ukazuje. Soubor VoidDemo.java třídy VoidDemo ( / ** * Toto je konstruktor * / VoidDemo () (System. Out. Println ("Konstruktor");) void VoidDemo () (System. Out. Println ("Metoda"));) public static void main (String s) (VoidDemo m = nové VoidDemo (); )) V důsledku toho program zobrazí: Konstruktor To opět dokazuje, že konstruktor je metoda bez návratových parametrů. Konstruktor však může být nastaven na jeden ze tří veřejných, soukromých nebo chráněných modifikátorů. A příklad bude nyní vypadat takto: Soubor VoidDemo2.java class VoidDemo2 ( / ** * Toto je konstruktor * / public VoidDemo2 () (System.out.println ("Konstruktor");) / ** * A toto je již normální metoda, i když se podobá * názvu třídy, protože existuje typ návratu void * / private void VoidDemo2 () (System. out. println ("Metoda"));) public static void main (String s) (VoidDemo2 m = new VoidDemo2 ();)) V konstruktoru je povoleno napsat příkaz return, ale pouze prázdné, bez návratové hodnoty. ReturnDemo.java třída ReturnDemo ( / ** * V konstruktoru je povoleno používat návratový operátor * bez parametrů. * / public ReturnDemo () (System. out. println ("Konstruktor"); return;) public static void main (String s) (ReturnDemo r = nové ReturnDemo ();))

Konstruktory parametrizované pomocí argumentů s proměnnou délkou

Java SDK 1.5 představuje dlouho očekávaný nástroj – argumenty s proměnnou délkou pro konstruktory a metody. Předtím se proměnlivý počet dokumentů zpracovával dvěma nepohodlnými způsoby. První z nich byl vypočítán na základě skutečnosti, že maximální počet argumentů je omezen na malý počet a je předem znám. V tomto případě bylo možné vytvořit přetížené verze metody, jednu pro každou variantu seznamu argumentů předávaných metodě. Druhá metoda je určena pro předem neznámé a velké množství argumentů. V tomto případě byly argumenty umístěny do pole a toto pole bylo předáno metodě. Argumenty s proměnnou délkou se nejčastěji používají při následných manipulacích s inicializacemi proměnných. Absence některých očekávaných argumentů konstruktoru nebo metody je pohodlně nahrazena výchozími hodnotami. Argument proměnné délky je pole a je s ním zacházeno jako s polem. Například konstruktor pro třídu Checking s proměnným počtem argumentů by vypadal takto: class Checking (veřejná kontrola (int... N) ()) Symbolická kombinace ... říká kompilátoru, že proměnný počet argumentů bude být použit a že tyto argumenty budou uloženy v poli, jehož hodnota je obsažena v proměnné n. Konstruktor lze volat s různým počtem argumentů, včetně žádných. Argumenty jsou automaticky umístěny do pole a předávány přes n. Pokud nejsou žádné argumenty, je délka pole 0. Kromě argumentů s proměnnou délkou mohou být v seznamu parametrů zahrnuty povinné parametry. V tomto případě musí být parametr obsahující proměnný počet argumentů nutně poslední v seznamu parametrů. Například: class Checking (veřejná kontrola (String s, int... N) ()) Zjevné omezení se týká počtu parametrů proměnné délky. V seznamu parametrů musí být pouze jeden parametr proměnné délky. Se dvěma parametry s proměnnou délkou kompilátor nemůže říct, kde jeden parametr končí a druhý začíná. Například: kontrola třídy (veřejná kontrola (String s, int... N, double... D) // CHYBA! ()) Soubor Checking.java navštívil každý z vozů daného dne. Z celkové hmotnosti evidovaných aut je potřeba vybrat ta, která se během dne nacházela ve dvou daných čtvercích, řekněme 22 a 15, podle mapy oblasti. Je zcela přirozené, že automobil může během dne navštívit mnoho náměstí, nebo jen jedno. Je zřejmé, že počet navštívených polí je omezen fyzickou rychlostí vozidla. Sestavme si malý program, kde konstruktor třídy přijme jako argumenty číslo auta jako požadovaný parametr a čísla navštívených polí terénu, jejichž počet může být proměnný. Návrhář zkontroluje, zda se auto objevilo ve dvou čtvercích, pokud ano, zobrazí jeho číslo na obrazovce.

Předání parametrů konstruktoru

V programovacích jazycích existují v zásadě dva druhy parametrů:
  • základní typy (primitiva);
  • odkazy na objekty.
Termín volání hodnotou znamená, že konstruktor obdrží hodnotu, kterou mu předá volající modul. Naproti tomu volání odkazem znamená, že konstruktor obdrží adresu proměnné od volajícího modulu. V jazyce Java se používá pouze volání podle hodnoty. Podle hodnoty parametru a podle referenční hodnoty parametru. Java nepoužívá pro objekty vyvolání odkazem (ačkoli to mnozí programátoři a autoři některých knih tvrdí). Parametry při předávání objektů v Javě se provádějí ne odkazem, a podle referenční hodnoty objektu! V každém případě konstruktor obdrží kopie hodnot všech parametrů. Konstruktor nemůže dělat se svými vstupními parametry:
  • konstruktor nemůže měnit hodnoty vstupních parametrů základních (primitivních) typů;
  • konstruktor nemůže měnit odkazy vstupních parametrů;
  • konstruktor nemůže znovu přiřadit odkazy na vstupní parametry novým objektům.
Konstruktor si vystačí se svými vstupními parametry:
  • změnit stav objektu předaného jako vstupní parametr.
Následující příklad dokazuje, že v Javě jsou vstupní parametry pro konstruktor předány hodnotou odkazu na objekt. Tento příklad také odráží skutečnost, že konstruktor nemůže měnit odkazy vstupních parametrů, ale ve skutečnosti mění odkazy kopií vstupních parametrů. Třída souboru Empoyee.java Employee (Zaměstnanec (String x, String y) (String temp = x; x = y; y = temp;) public static void main (String args) (String name1 = new String ("Alice"); String name2 = nový řetězec ("Mary"); Zaměstnanec a = nový zaměstnanec (jméno1, jméno2); System.out.println ("jméno1 =" + jméno1); System.out.println ("jméno2 =" + jméno2); )) Výstupem programu je: jméno1 = Alice jméno2 = Marie Pokud by se v Javě pro předávání objektů jako parametrů použilo volání odkazem, konstruktor by v tomto příkladu zaměnil jméno1 a jméno2. Konstruktor ve skutečnosti nezamění odkazy na objekty uložené v proměnných name1 a name2. To naznačuje, že parametry konstruktoru jsou inicializovány kopiemi těchto odkazů. Poté konstruktor vymění již kopie. Po dokončení konstruktoru jsou proměnné x a y zničeny a původní proměnné název1 a název2 nadále odkazují na staré objekty.

Změna parametrů předávaných konstruktoru.

Konstruktor nemůže upravit předané parametry základních typů. Konstruktor však může upravit stav objektu předaného jako parametr. Uvažujme například následující program: Soubor Plat1.java třída Plat1 (Mzda1 (int x) (x = x * 3; System.out.println ("x =" + x);) public static void main (String args) (int value = 1000; Plat1 s1 = nový Plat1 (hodnota); System.out.println ("value =" (! JAZYK: + hodnota);)) Výstupem programu je: x = 3000 hodnota = 1000 Tato metoda samozřejmě nezmění parametr hlavního typu. Po zavolání konstruktoru tedy hodnota proměnné zůstane rovna 1000. V zásadě se dějí tři věci:
  1. Proměnná x je inicializována kopií hodnoty parametru value (tedy číslem 1000).
  2. Hodnota proměnné x se ztrojnásobí – nyní se rovná 3000. Hodnota proměnné však zůstává 1000.
  3. Konstruktor se ukončí a proměnná x se již nepoužívá.
Následující příklad ztrojnásobí plat zaměstnance úspěšně, protože referenční hodnota objektu je předána jako parametr metodě. Soubor Plat2.java třída Plat2 (hodnota int = 1000; Plat2 () () Plat2 (Mzda2 x) (x. Hodnota = x. Hodnota * 3;) public static void main (String args) (Plat2 s1 = nový Plat2 () ; Plat2 s2 = nový Plat2 (s1); System.out.println ("s1.value="+ s1. hodnota); Systém. ven. println ("s2.value="+ s2. hodnota); )) Výstupem programu je: s1. hodnota = 3000 s2. hodnota = 1000 Jako parametr je použita hodnota odkazu na objekt. Při provádění řádku Mzda2 s2 = nový Mzda2 (s1); konstruktoru Plat2 (plat x) bude předána referenční hodnota objektu proměnné s1 a konstruktor ve skutečnosti ztrojnásobí plat pro s1.hodnota, protože i kopie (plat x) vytvořená uvnitř konstruktoru ukazuje na objekt proměnné s1 .

Primitivní parametrizované konstruktory.

V případě, že je v parametrech přetíženého konstruktoru použito primitivum, které lze zúžit (např. int<- double), то вызов метода со суженным значением возможен, несмотря на то, что метода, перегруженного с таким параметром нет. Например: Файл Primitive.java class Primitive { Primitive (double d) { d = d + 10 ; System. out. println (!}"d=" + d) ; } public static void main (String args ) { int i = 20 ; Primitive s1 = new Primitive (i) ; } } Výstupem programu je: d = 30.0 Navzdory skutečnosti, že třída Primitive nemá konstruktor, který má parametr typu int, bude fungovat konstruktor se vstupním parametrem double. Před voláním konstruktoru bude proměnná i rozšířena z typu int na typ double. Opačná varianta, kdy by proměnná i byla typu double a konstruktor by bral pouze parametr int, by v této situaci vedla k chybě kompilace.

Volání konstruktéra a nový operátor

Konstruktor je vždy volán operátorem new. Když je konstruktor volán s operátorem new, konstruktor vždy vygeneruje odkaz na nový objekt. Není možné přinutit konstruktor, aby vytvořil odkaz na existující objekt namísto odkazu na nový objekt, s výjimkou nahrazení deserializovaného objektu. A s operátorem new není možné místo odkazu na nový objekt vytvořit odkaz na existující objekt. Například: Soubor Plat3.java třída Plat3 (hodnota int = 1000; Plat3 () () Plat3 (Mzda3 x) (x. Hodnota = x. Hodnota * 3;) public static void main (String args) (Plat3 s1 = nový Plat3 (); System.out.println ("První vytvoření objektu:" + s1. Hodnota); Plat3 s2 = nový Plat3 (s1); System.out.println ("Vytvoření druhého objektu:" + s2. Hodnota); Systém out.println (+ s1. hodnota); Plat3 s3 = nový Plat3 (s1); System.out.println ("Vytvoření třetího objektu:" + hodnota s3.); System. out.println ( "Co" se stalo s prvním objektem?: "+ s1. hodnota); )) Výstupem programu je: Vytvoření prvního objektu: 1000 Vytvoření druhého objektu: 1000 Co se stalo s prvním objektem?: 3000 Vytvoření třetího objektu: 1000 Co se stalo s prvním objektem? : 9000 Nejprve s řádkem Plat3 s1 = nový Plat3 (); je vytvořen nový objekt. Dále, pokud použijete řádek Plat3 s2 = nový Plat3 (s1); nebo řádky Plat3 s3 = nový Plat3 (s1); bylo by možné vytvořit odkaz na existující objekt, pak by s1.hodnota s2.hodnota a s3.hodnota uložily stejnou hodnotu 1000. Vlastně v řádku Plat3 s2 = nový Plat3 (s1); pro proměnnou s2 bude vytvořen nový objekt a stav objektu pro proměnnou s1 se změní předáním její hodnoty odkazu na objekt v parametru konstruktoru. To je vidět z výsledků stažení. A při provádění řádku Plat3 s3 = nový Plat3 (s1); vytvořte NOVÝ objekt pro s3 a znovu změňte stav objektu pro s1.

Konstruktory a inicializační bloky, sekvence akcí při volání konstruktoru

Sekce Vytváření objektů a konstruktory uvádí obecné kroky, které jsou provedeny při vytváření objektu. Mezi nimi jsou spojeny procesy inicializace polí třídy a vypracování konstruktoru třídy, které zase mají také vnitřní řád:
  1. Všechna datová pole jsou inicializována na své výchozí hodnoty (0, false nebo null).
  2. Všechny inicializátory polí a inicializační bloky se provádějí v pořadí, v jakém jsou uvedeny v deklaraci třídy.
  3. Pokud je na prvním řádku konstruktoru zavolán jiný konstruktor, provede se volaný konstruktor.
  4. Tělo konstruktoru je provedeno.
Konstruktor souvisí s inicializací, protože v Javě existují tři způsoby, jak inicializovat pole ve třídě:
  • přiřadit hodnotu v deklaraci;
  • přiřadit hodnoty v inicializačním bloku;
  • nastavte jeho hodnotu v konstruktoru.
Přirozeně musíte svůj inicializační kód uspořádat tak, aby byl snadno srozumitelný. Následující třída je uvedena jako příklad: třída Inicializace (int i; krátké z = 10; statické int x; statické plovoucí y; statické (x = 2000; y = 3,141;) Inicializace () (System. Out. Println (" i = "+ i); System. out. println (" z = "+ z); z = 20; System. out. println (" z = "+ z);)) Ve výše uvedeném příkladu jsou proměnné inicializovány v v následujícím pořadí: nejprve se statické proměnné x a y inicializují na výchozí hodnoty. Dále se provede statický inicializační blok. Poté je proměnná i inicializována na výchozí hodnotu a proměnná z je inicializována. Následuje konstruktor. Volání konstruktorů tříd by mělo být nezávislé na pořadí, ve kterém jsou pole deklarována. To může vést k chybám.

Konstruktéři a dědičnost

Konstruktory se nedědí. Například: veřejná třída Příklad (Příklad () () public void sayHi () (systém. Out. Println ("Ahoj"));)) veřejná třída SubClass rozšiřuje Příklad () Třída SubClass automaticky zdědí metodu sayHi () definovanou v rodičovská třída. Zároveň konstruktor Example () nadřazené třídy nedědí její potomek SubClass.

Klíčové slovo this v konstruktorech

Konstruktory to používají k odkazování na jiný konstruktor ve stejné třídě, ale s jiným seznamem parametrů. Pokud konstruktor používá klíčové slovo this, pak musí být na prvním řádku, ignorování tohoto pravidla povede k chybě kompilátoru. Například: File ThisDemo.java public class ThisDemo (String name; ThisDemo (String s) (name = s; System.out.println (name);) ThisDemo () (this ("John"));) public static void main (String args) (ThisDemo td1 = nové ThisDemo ("Mary"); ThisDemo td2 = nové ThisDemo ();)) Výstupem programu je: Mary John Tento příklad má dva konstruktory. První obdrží řetězec argumentů. Druhý nebere žádné argumenty, pouze volá první konstruktor pomocí výchozího jména "John". Můžete tedy použít konstruktory k explicitní a výchozí inicializaci hodnot polí, což je v programech často nezbytné.

Super klíčové slovo v konstruktorech

Konstruktory používají super k volání konstruktoru nadtřídy. Pokud konstruktor používá super, pak toto volání musí být na prvním řádku, jinak překladač vyhodí chybu. Níže je příklad: Soubor SuperClassDemo.java veřejná třída SuperClassDemo (SuperClassDemo () ()) class Child rozšiřuje SuperClassDemo (Child () (super ();)) V tomto jednoduchém příkladu konstruktor Child () obsahuje volání super ( ), který kromě třídy Child vytváří instanci třídy SuperClassDemo. Protože super musí být prvním příkazem provedeným v konstruktoru podtřídy, je toto pořadí vždy stejné, bez ohledu na to, zda je použit super (). Pokud se nepoužije, pak se jako první provede výchozí konstruktor (bez parametrů) každé nadtřídy, počínaje základní třídou. Následující program ukazuje, kdy jsou spouštěny konstruktory. Soubor Call.java // Vytvořte nadtřídu A třída A (A () (System. out.println ("Konstruktor uvnitř A.");)) // Vytvořte podtřídu B rozšiřující třídu A třída B rozšiřuje A (B () (System.out.println ("Konstruktor uvnitř B.");)) // Vytvořte třídu (C), která rozšiřuje třídu B třída C rozšiřuje B (C () (System. out.println ("Konstruktor uvnitř C.");)) volání třídy (public static void main (String args) (C c = nové C ();)) Výstupem tohoto programu je: Uvnitř konstruktoru. Uvnitř B konstruktor. Uvnitř konstruktoru C. Konstruktory jsou volány v pořadí hierarchie tříd. To dává určitý smysl. Protože nadtřída nezná žádnou podtřídu, každá inicializace, kterou potřebuje provést, je samostatná. Kdykoli je to možné, mělo by předcházet jakékoli inicializaci prováděné podtřídou. Proto by měl být proveden jako první.

Přizpůsobitelné konstruktéry

Mechanismus identifikace typu za běhu je jedním z mocných základů jazyka Java, který implementuje polymorfismus. Takový mechanismus však v některých případech nezajistí vývojáře proti převodu nekompatibilního typu. Nejčastějším případem je manipulace se skupinou objektů, jejichž různé typy nejsou předem známy a jsou určeny za běhu. Protože chyby spojené s nekompatibilitou typů se mohou objevit pouze ve fázi běhu, je obtížné je najít a odstranit. Zavedení vlastních typů v Javě 2 5.0 přesouvá některé z těchto chyb z run-time do doby kompilace a poskytuje chybějící bezpečnost typu. Při přechodu z typu objektu na konkrétní typ není potřeba explicitní typové obsazení. Všimněte si, že úpravy typů pracují pouze s objekty a nevztahují se na primitivní datové typy, které leží mimo strom dědičnosti tříd. Díky přizpůsobitelným typům jsou všechna vrhání prováděna automaticky a skryta. To vám umožňuje být v bezpečí proti neshodám typu a používat kód mnohem častěji. V konstruktorech lze použít vlastní typy. Konstruktory lze přizpůsobit, i když jejich třída není vlastního typu. Například: class GenConstructor (private double val;< T extends Number >GenConstructor (T arg) (val = argument. DoubleValue ();) void printValue () (System. Out.println ("val:" + val);)) class GenConstructorDemo (public static void main (String args) (GenConstructor gc1 = nový GenConstructor (100); GenConstructor gc2 = nový GenConstructor (123.5F); gc1. printValue (); gc2. printValue ();)) Protože konstruktor GenConstructor určuje parametr vlastního typu, který musí být odvozen od třídy Number, lze volat jakkoli

Konstruktor je speciální metoda, která se volá při vytvoření nového objektu. Při vytváření instance třídy není vždy vhodné inicializovat všechny proměnné. Někdy je jednodušší, aby se některé hodnoty vytvořily ve výchozím nastavení při vytváření objektu. Ve skutečnosti je k automatické inicializaci proměnných potřeba konstruktor.

Konstruktor inicializuje objekt přímo v době vytvoření. Název konstruktoru je stejný jako název třídy, včetně velikosti písmen, a syntaxe konstruktoru je podobná metodě bez návratové hodnoty.

Private int Cat (); // takto vypadá metoda pojmenovaná Cat (); // takto vypadá konstruktor třídy Cat

Na rozdíl od metody konstruktor nikdy nic nevrací.

Konstruktor definuje akce, které se mají provést, když je vytvořen objekt třídy, a je důležitou součástí třídy. Programátoři se obvykle snaží explicitně specifikovat konstruktor. Pokud neexistuje žádný explicitní konstruktor, Java jej automaticky vytvoří pro použití ve výchozím nastavení. Když jsme implementovali třídu Krabice pak nebyl vytvořen žádný konstruktor.

Pojďme do třídy přidat konstruktor, který jednoduše nastaví počáteční hodnoty pro box.

Class Box (int width; // šířka boxu int height; // výška boxu int hloubka; // hloubka boxu // Constructor Box () (šířka = 10; výška = 10; hloubka = 10;) // výpočet objemu krabice int getVolume () (vrácená šířka * výška * hloubka;))

Metodu jsme dočasně odstranili setDim () a přidal konstruktor. Pojďme se podívat, co se stane:

Box catBox = new Box (); mInfoTextView.setText ("Objem krabice:" + catBox.getVolume ());

Program zobrazí objem krabice, i když jsme pro něj nezadali žádné rozměry. Díky konstruktoru bude mít každá vytvořená krabice nějaký pevný objem.

Přirozeně se můžete vrátit k metodě setDim ()(viz článek o třídách) a nastavte si vlastní rozměry krabice:

Box catBox = new Box (); // nastavíme vlastní rozměry krabice catBox.setDim (10, 20, 30); mInfoTextView.setText ("Objem krabice:" + catBox.getVolume ());

Nyní by vám mělo být jasné, že když za klíčovým slovem Nový napíšeme název třídy se závorkami, pak ve skutečnosti voláme konstruktor třídy.

Nabízí se otázka - ale přeci jen jsme nejprve při vytváření třídy nevytvořili konstruktor, ale kód nová krabice () pracoval. Jde o to, že pokud konstruktor není explicitně definován, Java vytvoří konstruktor, který se použije jako výchozí. V tomto případě jednoduše přiřadí nulové hodnoty všem proměnným. Pokud jste konstruktor vytvořili sami, nebude použit výchozí konstruktor.

Jako každá metoda může mít konstruktor argumenty. Argumenty konstruktoru jsou předávané parametry pro inicializaci objektu. Například pokud má třída Kočka existuje konstruktor, který obdrží jako argument celé číslo udávající věk kočky, pak objekty Kočka bude vytvořen takto:

Kočka kočka = nová Kočka (8); // kočce je 8 let

Li kočka (int) je jediným konstruktorem třídy, překladač nedovolí vytvářet objekty Kočka nějakým jiným způsobem.

Nicméně zpět ke krabicím pro kočky. Konstruktor, který jsme vytvořili, není příliš užitečný, protože vytváří stejné boxy. Vytvořme konstruktor s parametry ve třídě Krabice a okomentujte první konstruktor bez parametrů:

// Druhý konstruktor Box (int w, int v, int d) (šířka = w; výška = v; hloubka = d;)

Pokud třída obsahuje jeden konstruktor s parametry, budete muset při deklaraci třídy zadat hodnoty:

// Tento konstruktor již není platný // Box catBox = new Box (); // V konstruktoru musíte zadat hodnoty velikosti boxu Box catBox = new Box (100, 200, 100); mInfoTextView.setText ("Objem krabice:" + catBox.getVolume ());

Mimochodem, s takovým konstruktorem metoda setDim () už to nepotřebujeme. Rozměry boxu můžeme nastavit přímo v konstruktoru. Vzhledem k tomu, že pole je s největší pravděpodobností konstantní a nemění svou velikost, metoda je možná zbytečná. Pokud ale změníme velikost krabice, pak bude muset být metoda ponechána.

Třída může mít více konstruktorů. Odkomentujte první konstruktor a vytvořte dvě krabice - výchozí krabici a velkou krabici.

Box defaultBox = new Box (); mInfoTextView.setText ("Standardní objem boxu:" + defaultBox.getVolume ()); Box bigBox = nový Box (100, 200, 200); mInfoTextView.append ("\ nVelký objem krabice:" + bigBox.getVolume ());

To znamená, že vidíme, že konstruktory podporují přetěžování, stejně jako metody.

Například můžeme vytvořit další konstruktor speciálně pro krabici ve tvaru krychle, kde jsou všechny strany stejné:

// Třetí konstruktor pro krychli Box (int len) (šířka = výška = hloubka = délka;)

Vypočítáme velikost krychle:

Krabicová kostka = nová Krabice (5); int vol = cube.getVolume (); mInfoTextView.setText ("Objem krychle:" + objem);

Použití objektu jako parametrů

Dosud jsme jako parametry v konstruktorech používali jednoduché typy. Ale můžete také předat objekt třídy samotné. Přidejme ještě jeden konstruktor:

// Použijte objekt typu Box Box (Box ob) (width = ob.width; height = ob.height; depth = ob.depth;)

V kódu programu můžete použít konstruktor takto:

Box box1 = nový Box (100, 200, 100); Box cloneBox = nový Box (box1); int vol = cloneBox.getVolume (); mInfoTextView.setText ("Objem krabice:" + objem);

Box class (zdroj)

balíček ru.alexanderklimov.box; class Box (int width; // šířka boxu int height; // výška boxu int hloubka; // hloubka boxu // Constructor Box () (šířka = 10; výška = 10; hloubka = 10;) // Druhý konstruktor Box ( int w, int v, int d) (šířka = w; výška = v; hloubka = d;) // Třetí konstruktor pro kostku Box (int len) (width = výška = hloubka = délka; ) // Použijte objekt typu Box Box (Box ob) (width = ob.width; height = ob.height; depth = ob.depth;) // vypočítejte objem krabice int getVolume () (return width * výška * hloubka;) // nastavení velikosti krabice void setDim (int w, int v, int d) (šířka = š; výška = v; hloubka = d;))

Volání přetížených konstruktorů přes toto ()

Při práci s přetíženými konstruktory je vhodné volat jeden konstruktor z jiného pomocí klíčového slova tento... Při provádění konstruktoru tento () přetížený konstruktor, který odpovídá seznamu parametrů, je spuštěn jako první. Pak jsou provedeny příkazy uvnitř původního konstruktoru, pokud existují. Vyvolání konstruktoru tento () musí být prvním příkazem v konstruktoru.

Nejprve vytvořte třídu, která nepoužívá konstruktor. tento () abyste pochopili rozdíl.

Třída Cat (int věk; int narozeniny; // Inicializujte proměnné explicitně Cat (int i, int j) (věk = i; narozeniny = j;) // Inicializujte proměnné se stejnou hodnotou Cat (int i) (věk = i; narozeniny = i;) // Nastavit výchozí hodnoty na 0 Kočka () (věk = 0; narozeniny = 0;))

Vytvořili jsme třídu se třemi konstruktory. Přepišme třídu pomocí konstruktoru tento ().

Třída Cat (int věk; int narozeniny; // Inicializace proměnných explicitně Cat (int i, int j) (věk = i; narozeniny = j;) // Inicializace proměnných se stejnou hodnotou Cat (int i) (toto (i, i); // Zavolá se Cat (i, i);) // Nastaví výchozí hodnoty na 0 Cat () (toto (0); // Cat (0);))

Nyní máme pouze jeden konstruktor, který přiřazuje hodnoty polím - Cat (int, int). Co se stane po provedení příkazu:

Kočka kočka = nová Kočka (8);

Vyvolání konstruktoru kočka (8) vede k provedení konstruktoru toto (8, 8), což je stejné jako volání konstruktoru Kočka (8, 8).

Co se stane po provedení příkazu:

Cat cat2 = nová Cat ();

V tomto případě je zavolán konstruktor toto (0) což vede k provedení konstruktoru kočka (0) protože toto je verze konstruktoru, která odpovídá seznamu parametrů. Navíc konstruktér kočka (0) v podstatě volá konstruktor Kočka (0, 0).

Použití přetížených konstruktorů prostřednictvím konstruktoru tento () umožňuje eliminovat duplikaci kódu a zkracovat dobu načítání třídy.

Ale měli bychom být opatrní, protože konstruktéři volají konstruktor tento () běžet trochu pomaleji.

Soukromý konstruktér

Někdy je třída vytvořena pouze pro uložení nějakého druhu statických polí a statických metod. Je obvyklé dávat těmto třídám jména. Utils, ale je to volitelné. Taková třída nepotřebuje konstruktor, ale pokud jej autor třídy nevytvořil, pak systém sám vytvoří výchozí konstruktor. Takový konstruktor je nesmyslný a může také způsobit chyby. Chcete-li se tomuto problému bránit, musíte sami explicitně vytvořit prázdný konstruktor a nastavit jej jako soukromý.

Veřejná třída Utils (soukromé Utils () (vyhoďte novou AssertionError ();) ... // váš správný kód // Nesprávný kód, jen pro ukázku! Public static void someMethod () (Utils utils = nové Utils (); utils. toString ();))

Čára hodit novou chybu AssertionError () je volitelný, ale pomůže vám zachytit chybu, pokud zavoláte konstruktor v samotné třídě. Kompilátor tuto možnost přeskočí, ale program selže.

Utils.someMetoda (); // program se ukončí s chybou

Pro tuto třídu nemůžete vytvořit podtřídu.

Nejdůležitější funkcí v každé třídě je konstruktor. Umožňuje vytvořit instanci objektu. Pokud nemáte konstruktor, vytvoří se výchozí konstruktor:

Uživatel veřejné třídy (
int věk; // pole
String firstName; // pole
String lastName; // pole
User () (// takto vypadá výchozí konstruktor
// prázdný
}
}

Jak vidíte, konstruktor má stejný název jako název třídy.
Konstruktory, stejně jako funkce, mohou jako vstup přijmout sadu parametrů, které později použijí při vytváření objektu.

Uživatel veřejné třídy (
int věk; // pole
String firstName; // pole
String lastName; // pole
public User (int age, String firstName, String lastName) (// konstruktor se třemi parametry
this.věk = věk;
this.firstName = jméno;
this.lastName = prijmeni;
}
}

Je zřejmé, že konstruktory jsou volány, když je objekt vytvořen:

Uživatel uživatel = nový uživatel (18, "Bendjamin", "Tlačítko");

Vytvořili jsme tedy objekt třídy User, jehož pole Age obsahuje hodnoty 18, jméno Bendjamin a tlačítko lastName.
Použití tohoto konstruktoru je mnohem pohodlnější, než kdybychom to zkusili udělat ručně:

Uživatel uživatel = nový uživatel ();
uživatel.věk = 18;
user.firstName = "Bendjamin";
user.lastName = "Tlačítko";

Kromě toho, pokud použijete nějaké konstruktory, výchozí konstruktor se nevytvoří. Pokud tedy máme pouze konstruktor se třemi parametry, nemůžeme vytvořit objekt této třídy, aniž bychom jej zavolali:

Uživatel uživatel = nový uživatel (); // chyba, žádný výchozí konstruktor

Pojďme k některým vychytávkám myšlenky intellij. Stiskněte alt + vložit:

Toto je nabídka pro automatické generování některých užitečných věcí pro třídu. Dnes nás zde zajímá položka Constructor. Nyní, pokud máte ve třídě pole, můžete si vybrat, ze kterých polí potřebujete vytvořit konstruktor a programovací prostředí za vás napíše svůj kód. Pokud potřebujete další konstruktor, stiskněte znovu drahá tlačítka a přidejte další:

Uživatel veřejné třídy (
int věk; // pole
String firstName; // pole
String lastName; // pole
public User (int age, String firstName, String lastName) (
this.věk = věk;
this.firstName = jméno;
this.lastName = prijmeni;
}

veřejný uživatel (int věk) (
this.věk = věk;
}
}

Nyní zvažte podivný řádek this.VariableName = VariableName. Klíčové slovo this označuje, že je nutné přiřadit hodnotu předávanou konstruktoru aktuální instanci třídy. Pokud bychom tedy měli psát mimo třídu, pak uživatel.věk = věk, kde věk je regulérní proměnná.
Jiné konstruktory lze volat uvnitř konstruktorů, například:

Uživatel veřejné třídy (
int věk; // pole
String firstName; // pole
String lastName; // pole

public User (int age, String firstName, String lastName) (
this.věk = věk;
this.firstName = jméno;
this.lastName = prijmeni;
}

veřejný uživatel (int věk) (
this (věk, "neznámý", "neznámý"); // volání konstruktoru ze tří parametrů
}
}

Kromě toho, pokud byla ve vaší třídě použita dědičnost, pak abyste mohli zavolat konstruktor rodiče, musíte použít klíčové slovo super
Konstruktory jsou potřebné pro prvotní nastavení objektu, pokud je potřeba provést nějaké akce s poli, například je inicializovat.

Faktem je, že:

1. Pokud vytvoříte třídu a definujete konstruktor s argumenty v něm (třída AClass, která má pouze jeden konstruktor, který přijímá int i), pak překladač již nebude vytvářet výchozí konstruktor. Protože by to porušilo smlouvu třídy AClass, kterou nelze inicializovat bez argumentů. Pokud chcete mít také výchozí konstruktor, nastavte ho nyní explicitně.

Jinak by nebylo možné zakázat vytvoření výchozího konstruktoru, což by bylo špatné.

2. Při vytváření konstruktorů pro třídu BClass, která dědí z jiné třídy, kompilátor vyžaduje, aby první řádek konstruktoru zavolal jiný konstruktor (zděděný nebo v této třídě).

Proč? Protože dědíte od třídy, chcete znovu použít její logiku. Konstruktor uvádí instanci třídy do nějakého počátečního koherentního stavu. Ve vašem případě vyžaduje AClass argument k inicializaci, bez kterého JVM neví, jak inicializovat instanci třídy.

Pokud třída nemá definované žádné konstruktory, pak se pokusí vytvořit výchozí konstruktor, tzn. žádné argumenty:

Veřejná třída ACclass1 ()

Protože konstruktory zde nejsou explicitně definovány A třída nedědí z jiných tříd, kompilátor vytvoří výchozí konstruktor.

To je ekvivalentní této definici:

Veřejná třída ACtřída1 (veřejná třída AC1 () ())

Nyní se podívejme na BClass1:

Veřejná třída BClass1 rozšiřuje třídu AC1 ()

Ani zde nejsou konstruktory explicitně definovány a kompilátor se snaží vytvořit výchozí konstruktor. Protože AClass1 má výchozí konstruktor, vytvoří výchozí konstruktor, který vyvolá konstruktor AClass1. Tento kód je ekvivalentní tomuto:

Veřejná třída BClass1 rozšiřuje třídu AC1 (veřejná třída BClass1 () (super ();))

Ve vašem případě se vytvoří třída BEZ výchozího konstruktoru:

Veřejná ACtřída (veřejná ACtřída (int i) ())

Protože je zde popsán (alespoň jeden) konstruktor, výchozí konstruktor se již nevytváří. To znamená, že tento kód již nebude kompilován:

ACtřída a = nová ACtřída (); // nefunguje

potřebovat něco jako

ACtřída a = nová ACtřída (1);

Podle toho bude jakýkoli konstruktor třídy BC vyžadovat volání jakéhokoli konstruktoru třídy AC nebo BClass. S takovým popisem bude kompilátor přísahat:

Public BCclasss rozšiřuje ACclass ()

Protože dojde k pokusu o volání výchozího konstruktoru třídy AClass, která není definována:

Public BCclasss rozšiřuje ACtřídu (veřejná BCclass () (super (); // chyba; v ACtřídě žádný takový konstruktor není))

Můžete však vytvořit BClass s výchozím konstruktorem nastavením nějaké hodnoty pro konstruktor AClass:

Veřejná třída BClass rozšiřuje třídu AC (veřejná třída BClass () (super (1);))

Tím se zkompiluje.