Syntetiske konstruksjoner i Java

1. Oversikt

I denne veiledningen tar vi en titt på Java syntetiske konstruksjoner, kode introdusert av kompilatoren for å håndtere tilgang til medlemmer på en transparent måte som ellers ville være utilgjengelig på grunn av utilstrekkelig synlighet eller manglende referanser.

Merk: Fra og med JDK 11 genereres ikke syntetiske metoder og konstruktører lenger, da de erstattes av rede-basert tilgangskontroll.

2. Syntetisk i Java

Den beste definisjonen av syntetisk Vi kan muligens finne kommer direkte fra Java Language Specification (JLS 13.1.7):

Eventuelle konstruksjoner introdusert av en Java-kompilator som ikke har en tilsvarende konstruksjon i kildekoden, må merkes som syntetiske, bortsett fra standardkonstruktører, klassens initialiseringsmetode og verdiene og verdien av metodene til Enum-klassen.

Det finnes forskjellige typer kompileringskonstruksjoner, nemlig felt, konstruktører og metoder. På den andre siden, selv om nestede klasser kan endres av kompilatoren (dvs. anonyme klasser), regnes de ikke som syntetiske.

Uten videre, la oss dykke dypt inn i hver av disse.

3. Syntetiske felt

La oss begynne med en enkel nestet klasse:

offentlig klasse SyntheticFieldDemo {class NestedClass {}}

Når det er samlet, enhver indre klasse vil inneholde et syntetisk feltsom refererer til toppklassen. Tilfeldigvis er dette det som gjør det mulig å få tilgang til de omsluttende klassemedlemmene fra en nestet klasse.

For å sikre at dette er hva som skjer, implementerer vi en test som får de nestede klassefeltene ved refleksjon og sjekker dem ved hjelp av isSynthetic () metode:

public void givenSyntheticField_whenIsSynthetic_thenTrue () {Field [] fields = SyntheticFieldDemo.NestedClass.class .getDeclaredFields (); assertEquals ("Denne klassen skal bare inneholde ett felt", 1, fields.length); for (Felt f: felt) {System.out.println ("Felt:" + f.getName () + ", isSynthetic:" + f.isSynthetic ()); assertTrue ("Alle feltene i denne klassen skal være syntetiske", f.isSynthetic ()); }}

En annen måte vi kunne bekrefte dette på, var å kjøre demonteren gjennom kommandoen javap. I begge tilfeller viser utdataene et syntetisk felt med navnet denne $ 0.

4. Syntetiske metoder

Deretter legger vi til et privat felt i vår nestede klasse:

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

I dette tilfellet, samlingen vil generere aksessorer til variabelen. Uten disse metodene ville det være umulig å få tilgang til et privat felt fra den vedlagte forekomsten.

Nok en gang kan vi sjekke dette med samme teknikk som viser to syntetiske metoder som kalles få tilgang til $ 0 og få tilgang til $ 1:

public void givenSyntheticMethod_whenIsSynthetic_thenTrue () {Method [] methods = SyntheticMethodDemo.NestedClass.class .getDeclaredMethods (); assertEquals ("Denne klassen skal bare inneholde to metoder", 2, methods.length); for (Metode m: metoder) {System.out.println ("Metode:" + m.getName () + ", isSynthetic:" + m.isSynthetic ()); assertTrue ("Alle metodene i denne klassen skal være syntetiske", m.isSynthetic ()); }}

Legg merke til det for å generere koden, må feltet faktisk leses fra eller skrives til, Ellers blir metodene optimalisert borte. Dette er grunnen til at vi også la til en getter og en setter.

Som nevnt ovenfor genereres ikke disse syntetiske metodene lenger med JDK 11.

4.1. Brometoder

Et spesielt tilfelle av syntetiske metoder er bridgemetoder som håndterer sletting av generiske stoffer.

La oss for eksempel vurdere en enkel Komparator:

offentlig klasse BridgeMethodDemo implementerer Comparator {@Override public int compare (Integer o1, Integer o2) {retur 0; }}

Selv om sammenligne() tar to Heltall argumenter i kilden, når det er samlet, tar det to Gjenstand argumenter i stedet på grunn av type sletting.

For å klare dette, kompilatoren lager en syntetisk bro som tar seg av å kaste argumentene:

offentlig int sammenligne (Objekt o1, Objekt o2) {retur sammenligne ((Heltall) o1, (Heltall) o2); }

I tillegg til våre tidligere tester, vil vi også ringe denne gangen isBridge () fra Metode klasse:

offentlig ugyldig givenBridgeMethod_whenIsBridge_thenTrue () {int syntetiskMetoder = 0; Metode [] metoder = BridgeMethodDemo.class.getDeclaredMethods (); for (Metode m: metoder) {System.out.println ("Metode:" + m.getName () + ", isSynthetic:" + m.isSynthetic () + ", isBridge:" + m.isBridge ()); hvis (m.isSynthetic ()) {syntetiske metoder ++; assertTrue ("Den syntetiske metoden i denne klassen skal også være en brometode", m.isBridge ()); }} assertEquals ("Det skal være nøyaktig 1 syntetisk brometode i denne klassen", 1, syntetiske metoder); }

5. Syntetiske konstruktører

Til slutt legger vi til en privat konstruktør:

offentlig klasse SyntheticConstructorDemo {private NestedClass nestedClass = new NestedClass (); klasse NestedClass {private NestedClass () {}}}

Denne gangen, når vi kjører testen eller demontereren, ser vi at det faktisk er to konstruktører, hvorav den ene er syntetisk:

offentlig ugyldig givenSyntheticConstructor_whenIsSynthetic_thenTrue () {int syntetiskConstructors = 0; Constructor [] constructors = SyntheticConstructorDemo.NestedClass .class.getDeclaredConstructors (); assertEquals ("Denne klassen skal bare inneholde to konstruktører", 2, konstruktører. lengde); for (Constructor c: constructors) {System.out.println ("Constructor:" + c.getName () + ", isSynthetic:" + c.isSynthetic ()); hvis (c.isSynthetic ()) {syntetiskConstructors ++; }} assertEquals (1, syntetiske konstruksjoner); }

På samme måte som de syntetiske feltene, denne genererte konstruktøren er avgjørende for å instansiere en nestet klasse med en privat konstruktør fra sin vedlagte forekomst.

Som nevnt ovenfor genereres ikke den syntetiske konstruktøren lenger med JDK 11.

6. Konklusjon

I denne artikkelen diskuterte vi syntetiske konstruksjoner generert av Java-kompilatoren. For å teste dem brukte vi refleksjon, som du kan lære mer om her.

Som alltid er all koden tilgjengelig på GitHub.


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