Ohjelmointi

Javan synteettiset menetelmät

Tässä blogiviestissä tarkastelen Java-synteettisten menetelmien käsitettä. Viestissä esitetään yhteenveto siitä, mikä on Java-synteettinen menetelmä, miten se voidaan luoda ja tunnistaa, sekä Java-synteettisten menetelmien vaikutuksista Java-kehitykseen.

Java-kielimäärityksessä (osa 13.1) todetaan: "Kaikki kääntäjän käyttöön ottamat rakenteet, joilla ei ole vastaavaa rakennetta lähdekoodissa, on merkittävä synteettisiksi paitsi oletusrakentajat ja luokan alustusmenetelmä." Lisävihjeitä synteettisen sisällön merkityksestä Javassa löytyy Javadoc-dokumentaatiosta Member.isSynthetic (): lle. Kyseisen menetelmän dokumentaatiossa sanotaan, että se palauttaa arvon "tosi vain ja vain, jos kääntäjä esitteli tämän jäsenen". Pidän tuosta erittäin lyhyestä "synteettisen" määritelmästä: kääntäjän esittämä Java-rakenne.

Java-kääntäjän on luotava synteettisiä menetelmiä sisäkkäisiin luokkiin, kun sulkeutuva luokka käyttää niiden yksityisellä muokkaimella määritettyjä määritteitä. Seuraava koodinäyte osoittaa tämän tilanteen.

DemonstrateSyntheticMethods.java (luokan sulkeminen kutsuu yhden sisäkkäisen luokan yksityisen määritteen)

pakkaus pölyä.esimerkkejä; tuo java.util.Calendar; tuo staattinen java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumentit) {DemonstrateSyntheticMethods.NestedClass sisäkkäin = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Merkkijono:" + sisäkkäinen.erittäin luottamuksellinen); } yksityinen staattinen lopullinen luokka NestedClass {private String veryConfidential = "Älä kerro kenellekään"; yksityinen int erittäin luottamuksellinenInt = 42; yksityinen kalenteri veryConfidentialCalendar = Calendar.getInstance (); yksityinen totuusarvo erittäinConfidentialBoolean = true; }} 

Yllä oleva koodi kootaan ilman tapahtumia. Kun javap suoritetaan käännettyä vastaan .luokka tiedosto, lähtö on seuraavan näytön tilannekuvan mukainen.

Kuten yllä oleva kuvakaappaus osoittaa, synteettinen menetelmä, jolla on nimi pääsy 100 dollariin on luotu sisäkkäisiin luokkiin Sisäkkäinen luokka tarjoamaan yksityisen jousensa sulkeutuvalle luokalle. Huomaa, että synteettinen menetelmä lisätään vain NestedClassin yksityiselle attribuutille, jota sulkeva luokka käyttää. Jos muutan oheisen luokan käyttämään kaikkia NestedClassin yksityisiä määritteitä, syntyy lisää synteettisiä menetelmiä. Seuraava koodiesimerkki osoittaa juuri tämän tekemisen, ja sen seuraava näyttökuva osoittaa, että siinä tapauksessa syntyy neljä synteettistä menetelmää.

DemonstrateSyntheticMethods.java (luokan sulkeminen kutsuu neljä sisäkkäistä luokan yksityistä määritettä)

pakkaus pölyä.esimerkkejä; tuo java.util.Calendar; tuo staattinen java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumentit) {DemonstrateSyntheticMethods.NestedClass sisäkkäin = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Merkkijono:" + sisäkkäinen. erittäin luottamuksellinen); out.println ("Int:" + sisäkkäin.highlyConfidentialInt); out.println ("Kalenteri:" + sisäkkäin.highlyConfidentialCalendar); out.println ("Boolen:" + sisäkkäin.highlyConfidentialBoolean); } yksityinen staattinen lopullinen luokka NestedClass {private String veryConfidential = "Älä kerro kenellekään minusta"; yksityinen int erittäin luottamuksellinenInt = 42; yksityinen kalenteri veryConfidentialCalendar = Calendar.getInstance (); yksityinen totuusarvo erittäinConfidentialBoolean = true; }} 

Kuten edelliset kaksi yllä olevaa koodinpätkää ja niihin liittyvät kuvat osoittavat, Java-kääntäjä esittelee synteettisiä menetelmiä tarpeen mukaan. Kun sulkeutuva luokka käytti vain yhtä sisäkkäisen luokan yksityisistä määritteistä, vain yksi synteettinen menetelmä (pääsy 100 dollariin) loi kääntäjä. Kuitenkin, kun sisäkkäisen luokan kaikkia neljää yksityistä määritettä käytettiin sulkevalla luokalla, kääntäjä loi neljä vastaavaa synteettistä menetelmää (pääsy 100 dollariin, pääsy 200 dollariin, pääsy 300 dollariaja pääsy 400 dollaria).

Kaikissa tapauksissa, kun suljettu luokka käyttää pääsyä sisäkkäisen luokan yksityisiin tietoihin, luotiin synteettinen menetelmä tämän pääsyn sallimiseksi. Mitä tapahtuu, kun sisäkkäinen luokka tarjoaa pääsyn yksityisille tiedoilleen, joita sulkeva luokka voi käyttää? Tämä osoitetaan seuraavassa koodiluettelossa ja sen lähdössä seuraavan näytön tilannekuvan mukaisesti.

DemonstrateSyntheticMethods.java Nested Class Public Accessor for Private Data -sovelluksella

pakkaus pölyä.esimerkkejä; tuo java.util.Calendar; tuo java.util.Date; tuo staattinen java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumentit) {DemonstrateSyntheticMethods.NestedClass sisäkkäin = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Merkkijono:" + sisäkkäinen.erittäin luottamuksellinen); out.println ("Int:" + sisäkkäin.highlyConfidentialInt); out.println ("Kalenteri:" + sisäkkäin.highlyConfidentialCalendar); out.println ("Boolen:" + sisäkkäin.highlyConfidentialBoolean); out.println ("Päivämäärä:" + sisäkkäin.getDate ()); } yksityinen staattinen lopullinen luokka NestedClass {private String veryConfidential = "Älä kerro kenellekään minusta"; yksityinen int erittäin luottamuksellinenInt = 42; yksityinen kalenteri veryConfidentialCalendar = Calendar.getInstance (); yksityinen totuusarvo erittäinConfidentialBoolean = true; yksityinen päiväyspäivä = uusi päiväys (); public Date getDate () {return this.date; }}} 

Yllä oleva näytön tilannekuva osoittaa, että kääntäjän ei tarvinnut luoda synteettistä menetelmää yksityisen Date-määritteen käyttämiseksi sisäkkäisessä luokassa, koska sulkeva luokka käytti kyseistä määritettä toimitetun luokan kautta getDate () menetelmä. Jopa getDate () edellyttäen, kääntäjä olisi luonut synteettisen menetelmän Päivämäärä Onko liitteenä oleva koodi kirjoitettu pääsyä varten Päivämäärä attribuutti suoraan (ominaisuutena) eikä accessor-menetelmän kautta.

Viimeinen näyttökuva tuo esiin uuden havainnon. Kuten äskettäin lisätty getDate () menetelmä näyttää kyseisessä ruudun tilannekuvassa muokkaajia, kuten julkinen sisältyvät javap-tulostukseen. Koska kääntäjän luomille synteettisille menetelmille ei näytetä modifikaattoreita, tiedämme, että ne ovat pakettitasoisia (tai package-private). Lyhyesti sanottuna kääntäjä on luonut paketti-yksityiset menetelmät yksityisten määritteiden käyttämiseksi.

Java-pohtosovellusliittymät tarjoavat toisen lähestymistavan synteettisten menetelmien määrittämiseen. Seuraava koodiluettelo koskee Groovy-komentosarjaa, joka käyttää Java-heijastus-sovellusliittymiä tarjoamaan kätevästi yksityiskohtia yllä esitetyn sisäkkäisen luokan menetelmistä.

reflectedOnMethods.groovy

#! / usr / bin / env groovy import java.lang.reflect.Method import java.lang.reflect.Modifier if (args == null || args.size () <2) {println "Ulkoisten ja sisäkkäisten luokkien nimien on oltava tarjotaan. " println "\ nKäyttö # 1: reflectOnMethods qualifiedOuterClassName sisäkkäinenClassName \ n" println "\ nUsage # 2: groovy -cp luokan polku reflektionOnMethods.groovy qualifiedOuterClassName sisäkkäinClassName \ n" println "\ t1" sisällytä luokkaan \ n "tarvita. t2. ÄLÄ sisällytä \ $ sisäkkäisen luokan nimen eteen. \ n "System.exit (-1)} def enclosingClassName = args [0] def nestedClassName = args [1] def fullNestedClassName = enclosingClassName + '$' + sisäkkäinClassName def enclosingClass = Class.forName (enclosingClassName) Luokka sisäkkäinClass = null enclosingClass.declaredClasses.each {if (! nestedClass && fullNestedClassName.equals (it.nimi)) {nestedClass = it}} if (sisäkkäinenClass == null) {println "Ei voida etsi sisäkkäinen luokka $ {fullNestedClassName} "System.exit (-2)} // Käytä deklaroituja menetelmiä, koska älä välitä perinnöllisistä menetelmistä nestedClass.declaredMethods.each {print" \ nMethod '$ {it.name}' "print" on laajuus $ {getScopeModifier (it)}, "tulosta" $ {it.synthetic? 'on synteettinen': 'EI ole synteettinen'}, ja "println" $ {it.bridge? 'is bridge': 'EI EI siltaa'}. "} def merkkijono getScopeModifier (Method method) {def modifiers = method.modifiers def isPrivate = Modifier.isPrivate (modifiers) def isPublic = Modifier.isPublic (modifiers) def isProtected = Modifier .isProtected (modifiers) Merkkijono scopeString = "package-private" // oletusarvo, jos (isPublic) {scopeString = "public"} else if (isProtected) {scopeString = "protected"} else if (isPrivate) {scopeString = "private" } return scopeString} 

Kun yllä oleva Groovy-komentosarja suoritetaan edellä esitettyä luokkaa ja sisäkkäistä luokkaa vastaan, tulos on seuraava näytön tilannekuva.

Edellisessä kuvassa esitetyt Groovy-komentosarjan tulokset vahvistavat, mitä javap oli jo kertonut meille: sisäkkäisillä luokilla on neljä synteettistä menetelmää ja yksi ei-synteettinen menetelmä Sisäkkäinen luokka. Skripti kertoo meille myös, että kääntäjän luomat synteettiset menetelmät ovat paketti-yksityisiä.

Synteettisten menetelmien lisääminen sisäkkäisiin luokkiin paketti-yksityinen laajuus-tasolla ei ole ainoa asia, jonka kääntäjä teki yllä olevassa esimerkissä. Se muutti myös itse sisäkkäisen luokan laajuuden koodin yksityisestä asetuksesta paketiksi yksityiseksi .luokka tiedosto. Vaikka synteettiset menetelmät lisättiin vain siinä tapauksessa, että liitettävä luokka käytti yksityistä määritettä, kääntäjä tekee sisäkkäisen luokan paketin yksityiseksi, vaikka se olisikin määritelty yksityiseksi koodissa. Hyvä uutinen on, että tämä on tuloksena oleva kääntöprosessin artefakti, mikä tarkoittaa, että koodia ei voida kääntää sellaisenaan sisäkkäisen luokan muuttuneen laajuustason tai sen synteettisten menetelmien kanssa. Suoritusaika on paikka, josta asiat voivat tulla nopeiksi.

Luokka, Rogue, yrittää käyttää joitain NestedClass-synteettisiä menetelmiä. Sen lähdekoodi näkyy seuraavaksi, jota seuraa kääntäjävirhe yritettäessä kääntää tätä Rogue-lähdekoodia.

Rogue.java yrittää käyttää synteettisiä menetelmiä kokoamisajankohtana

pakkaus pölyä.esimerkkejä; tuo staattinen java.lang.System.out; public class Rogue {public static void main (final String [] argumentit) {out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); }} 

Yllä olevaa koodia ei koota edes ei-synteettiselle menetelmälle getDate ()ja ilmoittaa tämän virheen:

Koontitiedosto: C: \ java \ esimerkit \ synteettinen \ build.xml -init: compile: [javac] 1 lähdetiedoston kääntäminen C: \ java \ esimerkit \ synteettinen \ luokat [javac] C: \ java \ esimerkit \ synteettinen \ src \ dustin \ esimerkit \ Rogue.java: 9: dustin.examples.DemonstrateSyntheticMethods.NestedClassilla on yksityinen pääsy osoitteeseen dustin.examples.DemonstrateSyntheticMethods [javac] out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); [javac] ^ [javac] 1-virhe BUILD FAILED C: \ java \ esimerkit \ synteettinen \ build.xml: 29: Kääntäminen epäonnistui; katso lisätietoja kääntäjän virhelähdöstä. Kokonaisaika: 1 sekunti 

Kuten yllä oleva koontivirheilmoitus osoittaa, jopa ei-synteettinen menetelmä sisäkkäisessä luokassa ei ole käytettävissä kokoamisajankohtana koska sisäkkäinen luokka on yksityinen. Artikkelissaan Java Insecurity: Accounting for Subtleties That Can Compromise Code Charlie Lai käsittelee mahdollisia tilanteita, joissa nämä kääntäjän tekemät muutokset ovat tietoturva-aukkoja. Faisal Feroz menee pidemmälle ja toteaa, kuinka kirjoitetaan suojattu Java-koodi, "Älä käytä sisäisiä luokkia" (katso sisäkkäiset luokat sisäkkäisten luokkien osajoukkona kohdasta Sisäkkäiset, sisäiset, jäsenet ja ylätason luokat) .

Monet meistä voivat mennä pitkään Java-kehitykseen tarvitsematta merkittävää ymmärrystä synteettisistä menetelmistä. On kuitenkin tilanteita, joissa tietoisuus näistä asioista on tärkeää. Näihin liittyvien turvallisuuskysymysten lisäksi on myös oltava tietoinen siitä, mitä ne ovat, kun luet pinon jälkiä. Menetelmien nimet, kuten pääsy 100 dollariin, pääsy 200 dollariin, pääsy 300 dollaria, pääsy 400 dollaria, pääsy 500 dollariin, pääsy 600 dollariaja pääsy 1000 dollariin pinon jäljitys heijastaa kääntäjän luomia synteettisiä menetelmiä.

Alkuperäinen viesti saatavilla osoitteesta //marxsoftware.blogspot.com/

.

Tämän tarinan, "Java's Synthetic Methods", julkaisi alun perin JavaWorld.

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