Syntetické konštrukty v Jave

1. Prehľad

V tomto výučbe sa pozrieme na syntetické konštrukcie Java, kód zavedený kompilátorom na transparentné spracovanie prístupu k členom, ktorý by bol inak nedostupný z dôvodu nedostatočnej viditeľnosti alebo chýbajúcich referencií.

Poznámka: Počnúc JDK 11 sa syntetické metódy a konštruktory už negenerujú, pretože sú nahradené kontrolou prístupu založenou na hniezde.

2. Syntetické v Jave

Najlepšia definícia syntetický by sme mohli nájsť priamo zo špecifikácie jazyka Java (JLS 13.1.7):

Všetky konštrukty zavedené kompilátorom Java, ktoré nemajú zodpovedajúci konštrukt v zdrojovom kóde, musia byť označené ako syntetické, s výnimkou predvolených konštruktorov, metódy inicializácie triedy a metód a hodnôt a hodnotyOf triedy Enum.

Existujú rôzne druhy konštrukcií kompilácie, konkrétne polia, konštruktory a metódy. Na druhej strane, hoci vnorené triedy môže kompilátor zmeniť (t. j. anonymné triedy), nepovažujú sa za syntetické.

Poďme sa bez ďalších podrobností venovať každej z nich.

3. Syntetické polia

Začnime jednoduchou vnorenou triedou:

verejná trieda SyntheticFieldDemo {trieda NestedClass {}}

Po zostavení akákoľvek vnútorná trieda bude obsahovať syntetické polektorý odkazuje na triedu najvyššej úrovne. Zhodou okolností to je to, čo umožňuje prístup k obklopujúcim členom triedy z vnorenej triedy.

Aby sme sa uistili, že sa to práve deje, implementujeme test, ktorý odrazom dostane vnorené polia triedy a skontroluje ich pomocou je syntetický () metóda:

public void givenSyntheticField_whenIsSynthetic_thenTrue () {Field [] fields = SyntheticFieldDemo.NestedClass.class .getDeclaredFields (); assertEquals ("Táto trieda by mala obsahovať iba jedno pole", 1, fields.length); pre (Pole f: fields) {System.out.println ("Pole:" + f.getName () + ", isSynthetic:" + f.isSynthetic ()); assertTrue ("Všetky polia tejto triedy by mali byť syntetické", f.isSynthetic ()); }}

Ďalším spôsobom, ako by sme to mohli overiť, by bol spustenie demontéra prostredníctvom príkazu javap. V obidvoch prípadoch výstup zobrazuje syntetické pole s názvom to $ 0.

4. Syntetické metódy

Ďalej pridáme súkromné ​​pole do našej vnorenej triedy:

public class SyntheticMethodDemo {class NestedClass {private String nestedField; } public String getNestedField () {return new NestedClass (). nestedField; } public void setNestedField (String nestedField) {new NestedClass (). nestedField = nestedField; }}

V tomto prípade, kompilácia vygeneruje prístupových práv k premennej. Bez týchto metód by bolo nemožné získať prístup k súkromnému poľu z priloženej inštancie.

Opäť to môžeme skontrolovať rovnakou technikou, ktorá ukazuje dve syntetické metódy, ktoré sa nazývajú prístup $ 0 a prístup $ 1:

public void givenSyntheticMethod_whenIsSynthetic_thenTrue () {Method [] methods = SyntheticMethodDemo.NestedClass.class .getDeclaredMethods (); assertEquals ("Táto trieda by mala obsahovať iba dve metódy", 2, methods.length); pre (Metóda m: methods) {System.out.println ("Metoda:" + m.getName () + ", isSynthetic:" + m.isSynthetic ()); assertTrue ("Všetky metódy tejto triedy by mali byť syntetické", m.isSynthetic ()); }}

Všimni si na vygenerovanie kódu musí byť pole skutočne prečítané alebo zapísané do, inak budú metódy optimalizované. To je dôvod, prečo sme pridali aj getter a setter.

Ako už bolo spomenuté vyššie, tieto syntetické metódy sa už nevytvárajú počnúc JDK 11.

4.1. Mostné metódy

Špeciálnym prípadom syntetických metód sú premosťovacie metódy, ktoré sa zaoberajú mazaním druhov generík.

Uvažujme napríklad o jednoduchom Komparátor:

verejná trieda BridgeMethodDemo implementuje komparátor {@Override public int compare (Integer o1, Integer o2) {return 0; }}

Hoci porovnať () trvá dva Celé číslo argumenty v zdroji, po ich zostavení to bude trvať dva Objekt namiesto toho kvôli argumentu typu.

Ak to chcete spravovať, prekladač vytvorí syntetický most, ktorý sa postará o vrhanie argumentov:

public int porovnaj (Object o1, Object o2) {návrat porovnaj ((Integer) o1, (Integer) o2); }

Okrem našich predchádzajúcich testov si tentokrát zavoláme aj my isBridge () z Metóda trieda:

public void givenBridgeMethod_whenIsBridge_thenTrue () {int syntetickéMetódy = 0; Metóda [] methods = BridgeMethodDemo.class.getDeclaredMethods (); pre (Metóda m: methods) {System.out.println ("Metoda:" + m.getName () + ", isSynthetic:" + m.isSynthetic () + ", isBridge:" + m.isBridge ()); if (m.isSynthetic ()) {syntetickéMetódy ++; assertTrue ("Syntetická metóda v tejto triede by mala byť tiež mostíkovou metódou", m.isBridge ()); }} assertEquals ("V tejto triede by mala byť presne 1 metóda syntetického mosta", 1, syntetickéMetódy); }

5. Syntetické konštruktory

Nakoniec pridáme súkromného konštruktora:

verejná trieda SyntheticConstructorDemo {private NestedClass nestedClass = new NestedClass (); trieda NestedClass {private NestedClass () {}}}

Tentokrát, akonáhle spustíme test alebo demontážny program, uvidíme, že v skutočnosti existujú dva konštruktory, z ktorých jeden je syntetický:

public void givenSyntheticConstructor_whenIsSynthetic_thenTrue () {int syntetickéConštruktory = 0; Konštruktor [] konštruktory = SyntheticConstructorDemo.NestedClass .class.getDeclaredConstructors (); assertEquals ("Táto trieda by mala obsahovať iba dva konštruktory", 2, constructors.length); pre (konštruktor c: konštruktory) {System.out.println ("konštruktér:" + c.getName () + ", isSynthetic:" + c.isSynthetic ()); if (c.isSynthetic ()) {syntetickékonštruktory ++; }} assertEquals (1, syntetickékonštruktory); }

Podobne ako v prípade syntetických polí, tento vygenerovaný konštruktor je nevyhnutný na vytvorenie inštancie vnorenej triedy so súkromným konštruktorom z jeho obklopujúcej inštancie.

Ako už bolo spomenuté vyššie, syntetický konštruktér sa už negeneruje, počnúc JDK 11.

6. Záver

V tomto článku sme diskutovali o syntetických konštruktoch generovaných kompilátorom Java. Na ich otestovanie sme využili reflexiu, o ktorej sa tu dozviete viac.

Celý kód je ako vždy k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found