Szintetikus konstrukciók Java-ban

1. Áttekintés

Ebben az oktatóanyagban megvizsgáljuk a Java szintetikus konstrukcióit, a fordító által bevezetett kódot, amely átlátható módon kezeli a tagokhoz való hozzáférést, amely egyébként nem érhető el az elégtelen láthatóság vagy hiányzó hivatkozások miatt.

Megjegyzés: a JDK 11-től kezdődően a szintetikus módszerek és a konstruktorok már nem jönnek létre, mivel azokat fészekalapú hozzáférés-vezérlés váltja fel.

2. Szintetikus Java-ban

A legjobb definíciója szintetikus valószínűleg a Java nyelvspecifikációból származik (JLS 13.1.7):

Minden olyan Java fordító által bevezetett konstrukciót, amelynek nincs megfelelő konstrukciója a forráskódban, szintetikusként kell megjelölni, kivéve az alapértelmezett konstruktorokat, az osztály inicializálási módszert, valamint az Enum osztály értékeit és valueOf metódusait.

Különféle kompilációs konstrukciók léteznek, nevezetesen mezők, konstruktorok és módszerek. Másrészről, bár a beágyazott osztályokat a fordító módosíthatja (azaz anonim osztályok), nem tekinthetők szintetikusnak.

Minden további nélkül mélyedjünk el ezekben.

3. Szintetikus mezők

Kezdjük egy egyszerű beágyazott osztállyal:

public class SyntheticFieldDemo {class NestedClass {}}

Összeállításakor bármely belső osztály tartalmaz szintetikus mezőtamely a legfelsõbb osztályra hivatkozik. Véletlenül ez teszi lehetővé a befogadó osztálytagok bejutását egy beágyazott osztályból.

Annak érdekében, hogy megbizonyosodjon arról, hogy ez történik, egy tesztet hajtunk végre, amely tükrözi a beágyazott osztálymezőket, és a isSynthetic () módszer:

public void givenSyntheticField_whenIsSynthetic_thenTrue () {Mező [] mezők = SyntheticFieldDemo.NestedClass.class .getDeclaredFields (); assertEquals ("Ez az osztály csak egy mezőt tartalmazhat", 1, mezők.hossz); mert (f mező: mezők) {System.out.println ("Mező:" + f.getName () + ", isSynthetic:" + f.isSynthetic ()); assertTrue ("Ennek az osztálynak minden mezőjének szintetikusnak kell lennie", f.isSynthetic ()); }}

Ezt egy másik módon ellenőrizhetjük, ha a szétszerelőt futtatjuk a parancs segítségével javap. Mindkét esetben a kimenet egy szintetikus mezőt nevez meg ezt a 0 dollárt.

4. Szintetikus módszerek

Ezután hozzáadunk egy privát mezőt beágyazott osztályunkhoz:

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

Ebben az esetben, az összeállítás hozzáférőket generál a változóhoz. E módszerek nélkül lehetetlen elérni egy privát mezőt a mellékelő példányból.

Ismét ellenőrizhetjük ezt ugyanazzal a technikával, amely két szintetikus módszert mutat be hozzáférés a $ 0-hoz és hozzáférés a $ 1-hez:

public void givenSyntheticMethod_whenIsSynthetic_thenTrue () {Method [] method = SyntheticMethodDemo.NestedClass.class .getDeclaredMethods (); assertEquals ("Ennek az osztálynak csak két metódust kell tartalmaznia", 2, method.length); mert (m módszer: módszerek) {System.out.println ("Módszer:" + m.getName () + ", isSynthetic:" + m.isSynthetic ()); assertTrue ("Ennek az osztálynak minden módszerének szintetikusnak kell lennie", m.isSynthetic ()); }}

Figyelje meg a kód előállításához a mezőt valóban be kell olvasni vagy oda kell írni, különben a módszereket távol optimalizálják. Ez az oka annak, hogy hozzáadtunk egy getteret és egy setert is.

Mint fent említettük, ezeket a szintetikus módszereket már nem a JDK 11-től kezdve generálják.

4.1. Híd módszerek

A szintetikus módszerek speciális esete a híd módszerek, amelyek a generikusok törlésével foglalkoznak.

Vegyünk például egy egyszerűt Összehasonlító:

public class BridgeMethodDemo megvalósítja az összehasonlítót {@Orride public int összehasonlítás (egész o1, egész o2) {return 0; }}

Habár összehasonlít () kettőt vesz igénybe Egész szám A forrás argumentumai, miután összeállítottuk, kettőt vesz igénybe Tárgy érvek helyett, a típus törlése miatt.

Ennek kezeléséhez a fordító létrehoz egy szintetikus hidat, amely gondoskodik az érvek leadásáról:

public int összehasonlítás (o1 objektum, o2 objektum) {return összehasonlítás ((egész) o1, (egész) o2); }

Korábbi tesztjeink mellett ezúttal felhívjuk is isBridge () tól Módszer osztály:

public void givenBridgeMethod_whenIsBridge_thenTrue () {int synthMethods = 0; Method [] method = BridgeMethodDemo.class.getDeclaredMethods (); mert (m módszer: módszerek) {System.out.println ("Módszer:" + m.getName () + ", isSynthetic:" + m.isSynthetic () + ", isBridge:" + m.isBridge ()); if (m.isSynthetic ()) {szintetikus módszerek ++; assertTrue ("Az ebbe az osztályba tartozó szintetikus módszernek híd módszernek is kell lennie", m.isBridge ()); }} assertEquals ("Pontosan 1 szintetikus híd módszernek kell lennie ebben az osztályban", 1, synthMethods); }

5. Szintetikus kivitelezők

Végül hozzáadunk egy privát kivitelezőt:

public class SyntheticConstructorDemo {private NestedClass nestedClass = new NestedClass (); osztály NestedClass {private NestedClass () {}}}

Ezúttal, miután lefuttattuk a tesztet vagy a szétszerelőt, látni fogjuk, hogy valójában két konstruktor létezik, az egyik szintetikus:

public void givenSyntheticConstructor_whenIsSynthetic_thenTrue () {int synthConstructors = 0; Konstruktor [] konstruktorok = SyntheticConstructorDemo.NestedClass .class.getDeclaredConstructors (); assertEquals ("Ez az osztály csak két konstruktort tartalmazhat", 2, konstruktorok.hossz); a (Constructor c: konstruktorok) {System.out.println ("Constructor:" + c.getName () + ", isSynthetic:" + c.isSynthetic ()); if (c.isSynthetic ()) {szintetikusKonstruktorok ++; }} assertEquals (1, szintetikus konstruktorok); }

A szintetikus mezőkhöz hasonlóan ez a generált konstruktor elengedhetetlen egy beágyazott osztály példázásához egy magán konstruktorral a hozzá tartozó példányból.

Mint fent említettük, a szintetikus konstruktort már nem állítjuk elő, kezdve a JDK 11-vel.

6. Következtetés

Ebben a cikkben a Java fordító által létrehozott szintetikus konstrukciókról tárgyaltunk. Kipróbálásukhoz reflexiót használtunk, amelyről itt többet tudhat meg.

Mint mindig, az összes kód elérhető a GitHubon.


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