Zahŕňa podpis metódy v Jave návratový typ?

1. Prehľad

Podpis metódy je iba podmnožinou celej definície metódy v Jave. Presná anatómia podpisu môže teda spôsobiť zmätok.

V tomto tutoriáli sa dozvieme prvky podpisu metódy a jej implikácie v programovaní v Jave.

2. Podpis metódy

Metódy v Jave podporujú preťaženie, čo znamená, že v jednej triede alebo hierarchii tried je možné definovať viac metód s rovnakým názvom. Preto musí byť kompilátor schopný staticky viazať metódu, na ktorú odkazuje kód klienta. Z tohto dôvodu je metóda podpis jedinečne identifikuje každú metódu.

Podľa Oracle, metóda podpis sa skladá z názvu a typov parametrov. Preto všetky ostatné prvky deklarácie metódy, ako sú modifikátory, návratový typ, názvy parametrov, zoznam výnimiek a telo, nie sú súčasťou podpisu.

Pozrime sa podrobnejšie na preťaženie metódy a na to, ako to súvisí s podpismi metód.

3. Chyby preťaženia

Uvažujme o nasledujúcom kóde:

public void print () {System.out.println ("Podpis je: print ()"); } public void print (parameter int) {System.out.println ("Podpis je: print (int)"); }

Ako vidíme, kód sa kompiluje, pretože metódy majú rôzne zoznamy typov parametrov. V skutočnosti môže kompilátor deterministicky viazať ľubovoľné volanie na jedno alebo druhé.

Teraz otestujme, či je preťaženie legálne, a to pridaním nasledujúcej metódy:

public int print () {System.out.println ("Podpis je: print ()"); návrat 0; }

Pri kompilácii sa zobrazí chyba „metóda je už definovaná v triede“. To dokazuje metódu návratový typ nie je súčasťou podpisu metódy.

Skúsme to isté s modifikátormi:

private final void print () {System.out.println ("Podpis je: print ()"); }

Stále vidíme rovnakú chybu „metóda je už definovaná v triede“. Preto metóda podpis nezávisí od modifikátorov.

Preťaženie zmenou vyvolaných výnimiek je možné otestovať pridaním:

public void print () hodí IllegalStateException {System.out.println ("Podpis je: print ()"); hodiť novú IllegalStateException (); }

Opäť vidíme chybu „metóda je už definovaná v triede“, ktorá označuje vyhlásenie o hode nemôže byť súčasťou podpisu.

Posledná vec, ktorú môžeme otestovať, je, či zmena názvov parametrov umožňuje preťaženie. Pridajme nasledujúcu metódu:

public void print (int anotherParameter) {System.out.println ("Podpis je: print (int)"); }

Ako sa dalo očakávať, dostaneme rovnakú chybu kompilácie. To znamená, že názvy parametrov neovplyvňujú podpis metódy.

3. Generické mazanie a mazanie typov

S generickými parametrami, vymazanie typu zmení platný podpis. V skutočnosti to môže spôsobiť kolíziu s inou metódou, ktorá používa hornú hranicu generického typu namiesto generického tokenu.

Uvažujme o nasledujúcom kóde:

verejná trieda OverloadingErrors {public void printElement (T t) {System.out.println ("Podpis je: printElement (T)"); } public void printElement (Serializable o) {System.out.println ("Podpis je: printElement (Serializable)"); }}

Aj keď sa podpisy javia rôzne, kompilátor nemôže po vymazaní typu staticky viazať správnu metódu.

Vidíme nahradzovanie kompilátora T s hornou hranicou, Serializovateľné, z dôvodu vymazania typu. Preto je v rozpore s výslovne použitou metódou Serializovateľné.

Rovnaký výsledok by sme videli aj pri základnom type Objekt keď generický typ nemá väzbu.

4. Zoznamy parametrov a polymorfizmus

Podpis metódy zohľadňuje presné typy. To znamená, že môžeme preťažiť metódu, ktorej typ parametra je podtrieda alebo nadtrieda.

Musíme však venovať osobitnú pozornosť, pretože statická väzba sa pokúsi o zhodu pomocou polymorfizmu, automatického boxu a propagácie typu.

Pozrime sa na nasledujúci kód:

public Number sum (Celé číslo 1, Celé číslo 2) {System.out.println ("Pridanie celých čísel"); návratový termín1 + termín2; } public Number sum (Number term1, Number term2) {System.out.println ("Sčítanie čísel"); návrat term1.doubleValue () + term2.doubleValue (); } public number sum (Object term1, Object term2) {System.out.println ("Pridanie objektov"); návrat term1.hashCode () + term2.hashCode (); }

Vyššie uvedený zákon je úplne legálny a bude zostavený. Pri volaní týchto metód môže nastať zmätok, pretože nielenže potrebujeme poznať presný podpis metódy, ktorú voláme, ale aj to, ako sa Java staticky viaže na základe skutočných hodnôt.

Poďme preskúmať niekoľko volaní metód, ktoré nakoniec budú viazané suma (celé číslo, celé číslo):

StaticBinding obj = new StaticBinding (); obj.sum (Integer.valueOf (2), Integer.valueOf (3)); obj.sum (2, 3); obj.sum (2, 0x1);

Pre prvé volanie máme presné typy parametrov Celé číslo, celé číslo. Pri druhom hovore Java automaticky boxuje int do Celé číslo pre nás. Nakoniec Java transformuje hodnotu bajtu 0x1 do int pomocou typovej propagácie a potom ju automaticky zaškatuľkovať na Celé číslo.

Podobne máme aj nasledujúce volania, ktoré sa viažu na suma (počet, počet):

obj.sum (2,0d, 3,0d); obj.sum (Float.valueOf (2), Float.valueOf (3));

Na prvý hovor máme dvojitý hodnoty, ktoré sa automaticky označia Dvojitý. A potom pomocou polymorfizmu Dvojitý zápasy Číslo. Rovnako Plavák zápasy Číslo na druhý hovor.

Pozrime sa na to, že oboje Plavák a Dvojitý dediť z Číslo a Objekt. Predvolená väzba je však Číslo. Je to tak kvôli skutočnosti, že Java sa automaticky spojí s najbližšími super-typmi, ktoré zodpovedajú podpisu metódy.

Teraz zvážime nasledujúce volanie metódy:

obj.sum (2, "John");

V tomto príklade máme int do Celé číslo auto-box pre prvý parameter. Neexistuje však žiadna suma (celé číslo, reťazec) preťaženie pre tento názov metódy. V dôsledku toho bude Java prechádzať cez všetky nadradené typy parametrov, ktoré sa majú odovzdať z najbližšieho rodiča do Objekt kým nenájde zhodu. V takom prípade sa viaže na suma (Objekt, Objekt).

Na zmenu predvolenej väzby môžeme použiť explicitné obsadenie parametrov nasledovne:

obj.sum ((Objekt) 2, (Objekt) 3); obj.sum ((Číslo) 2, (Číslo) 3);

5. Varargové parametre

Teraz obráťme našu pozornosť na to, ako varargs vplyv na efektívny podpis metódy a statická väzba.

Tu máme preťaženú metódu použitia varargs:

public Number sum (Objekt term1, Objekt term2) {System.out.println ("Pridanie objektov"); návrat term1.hashCode () + term2.hashCode (); } public number sum (Object term1, Object ... term2) {System.out.println ("Pridanie argumentov premenných:" + term2.length); int result = term1.hashCode (); pre (Objekt o: term2) {vysledok + = o.hashCode (); } vrátiť výsledok; }

Aké sú teda účinné podpisy metód? To sme už videli suma (Objekt, Objekt) je podpis pre prvý. Variabilné argumenty sú v podstate polia, takže efektívny podpis pre druhú po kompilácii je suma (Objekt, Objekt []).

Zložitou otázkou je, ako si môžeme zvoliť spôsob viazania, keď máme iba dva parametre.

Zvážme nasledujúce výzvy:

obj.sum (nový objekt (), nový objekt ()); obj.sum (nový objekt (), nový objekt (), nový objekt ()); obj.sum (nový objekt (), nový objekt [] {nový objekt ()});

Je zrejmé, že prvé volanie sa bude viazať na suma (Objekt, Objekt) a druhý k suma (Objekt, Objekt []). Aby sme Javu prinútili volať druhú metódu s dvoma objektmi, musíme ju zabaliť do poľa ako pri treťom volaní.

Posledná vec, ktorú si treba uvedomiť, je, že vyhlásenie nasledujúcej metódy bude v rozpore s verziou vararg:

súčet verejných čísel (Objekt výraz1, Objekt [] výraz2) {// ...}

6. Záver

V tomto tutoriáli sme sa dozvedeli, že podpisy metód pozostávajú zo zoznamu názvov a typov parametrov. Modifikátory, návratový typ, názvy parametrov a zoznam výnimiek nemôžu rozlišovať medzi preťaženými metódami, a preto nie sú súčasťou podpisu.

Pozreli sme sa tiež na to, ako mazanie typu a varargy skrývajú efektívny podpis metódy a ako môžeme prepísať statickú väzbu metódy Java.

Ako obvykle sú všetky ukážky kódu zobrazené v tomto článku k dispozícii na GitHub.