Sintetički konstrukti u Javi

1. Pregled

U ovom uputstvu pogledat ćemo Java sintetičke konstrukcije, kod koji je prevoditelj uveo za transparentno rukovanje pristupom članovima koji bi inače bili nedostupni zbog nedovoljne vidljivosti ili nedostajućih referenci.

Napomena: počevši od JDK 11, sintetske metode i konstruktori više se ne generiraju, jer ih zamjenjuje kontrola pristupa zasnovana na gnijezdu.

2. Sintetika u Javi

Najbolja definicija sintetička mogli bismo pronaći da dolazi izravno iz Specifikacije jezika Java (JLS 13.1.7):

Svi konstrukti uvedeni Java kompajlerom koji nemaju odgovarajući konstrukt u izvornom kodu moraju biti označeni kao sintetički, osim zadanih konstruktora, metode inicijalizacije klase i vrijednosti i valueOf metoda klase Enum.

Postoje različite vrste konstrukcija kompilacije, naime polja, konstruktori i metode. S druge strane, iako kompajler može izmijeniti ugniježđene klase (tj. anonimne klase), ne smatraju se sintetičkim.

Bez daljnjega, zaronimo duboko u svaku od njih.

3. Sintetička polja

Počnimo s jednostavnom ugniježđenom klasom:

javna klasa SyntheticFieldDemo {klasa NestedClass {}}

Kada se sastavi, bilo koja unutarnja klasa sadržavat će sintetičko poljekoji upućuje na klasu najviše razine. Slučajno je to ono što omogućuje pristup pridruženim članovima klase iz ugniježđene klase.

Kako bismo bili sigurni da se to događa, implementirat ćemo test koji reflektira ugniježđena polja klase i provjerava ih pomoću isSynthetic () metoda:

javna praznina givenSyntheticField_whenIsSynthetic_thenTrue () {Polje [] polja = SyntheticFieldDemo.NestedClass.class .getDeclaredFields (); assertEquals ("Ova klasa treba sadržavati samo jedno polje", 1, polja.duljina); za (Polje f: polja) {System.out.println ("Polje:" + f.getName () + ", isSynthetic:" + f.isSynthetic ()); assertTrue ("Sva polja ove klase trebaju biti sintetička", f.isSynthetic ()); }}

Drugi način na koji bismo to mogli provjeriti bio bi pokretanjem dissensera kroz naredbu javap. U oba slučaja, izlaz prikazuje sintetičko polje s imenom ovo 0 dolara.

4. Sintetske metode

Sljedeće ćemo dodati ugniježđenoj klasi privatno polje:

javna klasa SyntheticMethodDemo {klasa NestedClass {privatni niz nestedField; } public String getNestedField () {return new NestedClass (). nestedField; } javna praznina setNestedField (String nestedField) {new NestedClass (). nestedField = nestedField; }}

U ovom slučaju, kompilacija će generirati pristupnike varijabli. Bez ovih metoda bilo bi nemoguće pristupiti privatnom polju iz priložene instance.

Još jednom, to možemo provjeriti istom tehnikom koja pokazuje dvije sintetičke metode pristupiti $ 0 i pristupiti $ 1:

javna praznina givenSyntheticMethod_whenIsSynthetic_thenTrue () {Metoda [] metode = SyntheticMethodDemo.NestedClass.class .getDeclaredMethods (); assertEquals ("Ova klasa treba sadržavati samo dvije metode", 2, methods.length); za (Metoda m: metode) {System.out.println ("Metoda:" + m.getName () + ", isSynthetic:" + m.isSynthetic ()); assertTrue ("Sve metode ove klase trebaju biti sintetičke", m.isSynthetic ()); }}

Primijeti da da bi se generirao kôd, polje se zapravo mora pročitati ili upisati u njega, u suprotnom, metode će se optimizirati. To je razlog zašto smo dodali i getter i setter.

Kao što je gore spomenuto, ove sintetske metode više se ne generiraju počevši od JDK 11.

4.1. Mostovne metode

Poseban slučaj sintetičkih metoda su mostne metode koje se bave brisanjem tipova generika.

Na primjer, razmotrimo jednostavan Usporednik:

javna klasa BridgeMethodDemo implementira komparator {@Preuzmi public int compare (Integer o1, Integer o2) {return 0; }}

Iako usporedi () traje dvoje Cijeli broj argumenta u izvoru, jednom sastavljeni trebat će dva Objekt umjesto toga argumenti, zbog brisanja tipa.

Da biste upravljali ovim, kompajler stvara sintetički most koji se brine za lijevanje argumenata:

public int compare (Object o1, Object o2) {return compare ((Integer) o1, (Integer) o2); }

Uz naše prethodne testove, ovaj put ćemo i nazvati isBridge () od Metoda razred:

javna praznina givenBridgeMethod_whenIsBridge_thenTrue () {int syntheMethods = 0; Metoda [] metode = BridgeMethodDemo.class.getDeclaredMethods (); za (Metoda m: metode) {System.out.println ("Metoda:" + m.getName () + ", isSynthetic:" + m.isSynthetic () + ", isBridge:" + m.isBridge ()); if (m.isSynthetic ()) {sintetičkeMetode ++; assertTrue ("Sintetička metoda u ovoj klasi također bi trebala biti most metoda", m.isBridge ()); }} assertEquals ("U ovoj klasi trebala bi postojati točno 1 metoda sintetičkog mosta", 1, sintetičke metode); }

5. Sintetički konstruktori

Na kraju ćemo dodati privatni konstruktor:

javna klasa SyntheticConstructorDemo {private NestedClass nestedClass = new NestedClass (); klasa NestedClass {private NestedClass () {}}}

Ovaj put, nakon što pokrenemo test ili rastavljač, vidjet ćemo da zapravo postoje dva konstruktora, od kojih je jedan sintetički:

javna praznina givenSyntheticConstructor_whenIsSynthetic_thenTrue () {int SyntheticConstructors = 0; Konstruktor [] konstruktori = SyntheticConstructorDemo.NestedClass .class.getDeclaredConstructors (); assertEquals ("Ova klasa treba sadržavati samo dva konstruktora", 2, constructors.length); za (Konstruktor c: konstruktori) {System.out.println ("Konstruktor:" + c.getName () + ", isSynthetic:" + c.isSynthetic ()); if (c.isSynthetic ()) {syntConstructors ++; }} assertEquals (1, sintetički konstruktori); }

Slično sintetičkim poljima, ovaj generirani konstruktor je bitan za instanciranje ugniježđene klase s privatnim konstruktorom iz njegove zatvorene instance.

Kao što je gore spomenuto, sintetički konstruktor više se ne generira počevši od JDK 11.

6. Zaključak

U ovom smo članku razgovarali o sintetičkim konstrukcijama koje je generirao Java prevodilac. Da bismo ih testirali, poslužili smo se refleksijom o kojoj više možete saznati ovdje.

Kao i uvijek, sav je kôd dostupan na GitHub-u.


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