Programiranje

Javine sintetične metode

V tem prispevku si ogledujem koncept sintetičnih metod Java. Prispevek povzema, kaj je sintetična metoda Java, kako jo je mogoče ustvariti in identificirati ter posledice sintetičnih metod Java na razvoj Jave.

Specifikacija jezika Java (oddelek 13.1) navaja: "Vsi konstrukti, ki jih je uvajal prevajalnik in nimajo ustreznega konstrukta v izvorni kodi, morajo biti označeni kot sintetični, razen privzetih konstruktorjev in metode inicializacije razreda." Nadaljnje namige o pomenu sintetike v Javi najdete v dokumentaciji Javadoc za Member.isSynthetic (). Dokumentacija te metode navaja, da vrne "true, če in samo, če je tega člana uvedel prevajalnik." Všeč mi je ta zelo kratka definicija "sintetike": konstrukcija Java, ki jo je predstavil prevajalnik.

Prevajalnik Java mora ustvariti sintetične metode v ugnezdenih razredih, ko do njihovih atributov, podanih z zasebnim modifikatorjem, dostopa zaprt razred. Naslednji vzorec kode kaže na to situacijo.

DemonstrateSyntheticMethods.java (zapiranje razreda prikliče en ugnezden zasebni atribut razreda)

paket prah v.primeri; uvoz java.util.Calendar; uvoz statičnega java.lang.System.out; javni končni razred DemonstrateSyntheticMethods {public static void main (final String [] argument)) {DemonstrateSyntheticMethods.NestedClass ugnezdeno = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Niz:" + ugnezdeni.highlyConfidential); } private static final class NestedClass {private String močnoConfidential = "Nikomur ne povej o meni"; zaseb int intConfidentialInt = 42; zasebni koledar visokoConfidentialCalendar = Calendar.getInstance (); zasebno logično zeloConfidentialBoolean = true; }} 

Zgornja koda se prevede brez incidentov. Ko se javap zažene proti prevedenemu .razred datoteka, je rezultat, kot je prikazano na naslednjem posnetku zaslona.

Kot kaže zgornji posnetek zaslona, ​​sintetična metoda z imenom dostop do 100 USD je bil ustvarjen v ugnezdenem razredu NestedClass da posreduje svoj zasebni niz zapiralnemu razredu. Upoštevajte, da je sintetična metoda dodana samo za en zasebni atribut NestedClass, do katerega dostopa razred, ki ga vsebuje. Če spremenim zaprti razred za dostop do vseh zasebnih atributov NestedClass, bodo ustvarjene dodatne sintetične metode. Naslednji primer kode dokazuje, da počnemo prav to, posnetek zaslona, ​​ki sledi, dokazuje, da so v tem primeru ustvarjene štiri sintetične metode.

DemonstrateSyntheticMethods.java (zapiranje razreda prikliče štiri ugnezdene zasebne atribute razreda)

paket prah v.primeri; uvoz java.util.Calendar; uvoz statičnega java.lang.System.out; javni končni razred DemonstrateSyntheticMethods {public static void main (final String [] argument)) {DemonstrateSyntheticMethods.NestedClass ugnezdeno = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + ugnezdeno.highlyConfidential); out.println ("Int:" + ugnezdeno.highlyConfidentialInt); out.println ("Koledar:" + ugnezdeni.highlyConfidentialCalendar); out.println ("logična vrednost:" + ugnezdena.highlyConfidentialBoolean); } private static final class NestedClass {private String močnoConfidential = "Nikomur ne povej o meni"; zaseb int intConfidentialInt = 42; zasebni koledar visokoConfidentialCalendar = Calendar.getInstance (); zasebno logično zeloConfidentialBoolean = true; }} 

Kot kažeta prejšnja dva zgornja delčka kode in pripadajoče slike, prevajalnik Java po potrebi uvaja sintetične metode. Ko je zaprti razred dostopal le do enega od zasebnih atributov ugnezdenega razreda, je bila uporabljena le ena sintetična metoda (dostop do 100 USD) je ustvaril prevajalnik. Ko pa je zaprti razred dostopal do vseh štirih zasebnih atributov ugnezdenega razreda, je prevajalnik ustvaril štiri ustrezne sintetične metode (dostop do 100 USD, dostop 200 $, dostop 300 USD, in dostop 400 $).

V vseh primerih, ko zaprt razred dostopa do zasebnih podatkov svojega ugnezdenega razreda, je bila ustvarjena sintetična metoda, ki omogoča, da se ta dostop zgodi. Kaj se zgodi, ko ugnezdeni razred zagotovi dostop do svojih zasebnih podatkov, ki jih lahko uporabi zaprti razred? To je razvidno iz naslednjega seznama kode in njegovega rezultata, kot je prikazano na naslednjem posnetku zaslona.

DemonstrateSyntheticMethods.java z gnezdenim javnim dostopnikom za zasebne podatke

paket prah v.primeri; uvoz java.util.Calendar; uvoz java.util.Date; uvoz statičnega java.lang.System.out; javni končni razred DemonstrateSyntheticMethods {public static void main (final String [] argument)) {DemonstrateSyntheticMethods.NestedClass ugnezdeno = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + ugnezdeno.highlyConfidential); out.println ("Int:" + ugnezdeno.highlyConfidentialInt); out.println ("Koledar:" + ugnezdeni.highlyConfidentialCalendar); out.println ("logična vrednost:" + ugnezdena.highlyConfidentialBoolean); out.println ("Datum:" + ugnezdeni.getDate ()); } private static final class NestedClass {private String močnoConfidential = "Nikomur ne povej o meni"; zaseb int intConfidentialInt = 42; zasebni koledar visokoConfidentialCalendar = Calendar.getInstance (); zasebno logično zeloConfidentialBoolean = true; datum zasebnega datuma = nov datum (); javni datum getDate () {return this.date; }}} 

Zgornji posnetek zaslona dokazuje, da prevajalniku ni bilo treba ustvariti sintetične metode za dostop do zasebnega atributa Date v ugnezdenem razredu, ker je zaprti razred do tega atributa dostopal prek posredovanega getDate () metoda. Tudi z getDate () pod pogojem, da bi prevajalnik ustvaril sintetično metodo za dostop do datoteke datum je priložena koda napisana za dostop do datum atribut neposredno (kot lastnost) in ne prek metode accessor.

Zadnji posnetek zaslona prikazuje še eno opažanje. Kot novo dodana getDate () metoda prikazuje na posnetku zaslona modifikatorje, kot je javnosti so vključeni v izhod javap. Ker za sintetične metode, ki jih je ustvaril prevajalnik, ni prikazan noben modifikator, vemo, da so na ravni paketa (ali zasebno). Skratka, prevajalnik je ustvaril paketno-zasebne metode za dostop do zasebnih atributov.

API-ji za odsev Java ponujajo drug pristop za določanje sintetičnih metod. Naslednji seznam kod je namenjen skriptu Groovy, ki bo uporabil API-je za odsev Java za priročno zagotavljanje podrobnosti o metodah zgoraj prikazanega ugnezdenega razreda.

ReflectOnMethods.groovy

#! / usr / bin / env groovy import java.lang.reflect.Method import java.lang.reflect.Modifier if (args == null || args.size () <2) {println "Zunanja in ugnezdena imena razredov morajo biti zagotoviti. " println "\ nUporaba # 1: odražajMontede qualiOuterClassName ugnezdenoClassName \ n" println "\ nUporaba št.2: groovy -cp classpath refleOnMethods.groovy qualiOuterClassName nestedClassName \ n" println "\ t nujno. t2. NE vključujte \ $ pred gnezdeno ime razreda. \ n "System.exit (-1)} def enclosingClassName = args [0] def nestedClassName = args [1] def fullNestedClassName = enclosingClassName + '$' + nestedClassName def enclosingClass = Class.forName (enclosingClassName) Razred nestedClass = null enclosingClass.declaredClasses.each {if (! nestedClass && fullNestedClassName.equals (it.name)) {nestedClass = it}} if (nestedClass == null) {print poiščite ugnezdeni razred $ {fullNestedClassName} "System.exit (-2)} // Uporabite prijavljene metode, ker jim ni mar za podedovane metode nestedClass.declaredMethods.each {print" \ nMetoda '$ {it.name}' "print" je $ {getScopeModifier (it)} obseg, "print" $ {it.synthetic? 'je sintetično': 'NI sintetično'} in "println" $ {it.bridge? 'is bridge': 'NI most'}. "} def String getScopeModifier (metoda metode) {def modifiers = method.modifiers def isPrivate = Modifier.isPrivate (modifikatorji) def isPublic = Modifier.isPublic (modifikatorji) def isProtected = Modifikator .isProtected (modifikatorji) String scopeString = "package-private" // privzeto if (isPublic) {scopeString = "public"} else if (isProtected) {scopeString = "protected"} else if (isPrivate) {scopeString = "private" } vrni obsegString} 

Ko se zgornji skript Groovy izvede proti razredu in ugnezdenemu razredu, prikazanemu zgoraj, je izhod prikazan na naslednjem posnetku zaslona.

Rezultati skripta Groovy, prikazani na prejšnji sliki, potrjujejo, kaj nam je javap že povedal: v ugnezdenem razredu so definirane štiri sintetične metode in ena nesintetična metoda NestedClass. Skript nam tudi pove, da so sintetične metode, ki jih ustvari prevajalnik, v zasebnem obsegu.

Dodajanje sintetičnih metod ugnezdenemu razredu na ravni zasebnega obsega paketov ni edino, kar je prevajalnik naredil v zgornjem primeru. Prav tako je spremenil obseg samega ugnezdenega razreda iz zasebne nastavitve v kodi v paketno-zasebno v .razred mapa. Medtem ko so bile sintetične metode dodane le v primeru, ko je razred, ki vključuje, dostopal do atributa private, prevajalnik ugnezdeni razred vedno naredi ugnezdeni paket private, tudi če je v kodi naveden kot private. Dobra novica je, da je to artefakt postopka prevajanja, kar pomeni, da kode ni mogoče prevesti takšne, kakršna je, glede na spremenjeno raven obsega ugnezdenega razreda ali njegovih sintetičnih metod. Med izvajanjem lahko stvari postanejo zapletene.

Razred Rogue poskuša dostopati do nekaterih sintetičnih metod NestedClass. Nato je prikazana njegova izvorna koda, ki ji sledi napaka prevajalnika, ki jo opazimo pri poskusu prevajanja te izvorne kode Rogue.

Rogue.java poskuša dostopati do sintetičnih metod v času prevajanja

paket prah v.primeri; uvoz statičnega java.lang.System.out; javni razred Rogue {public static void main (final String [] argument)) {out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); }} 

Zgornja koda se ne bo zbrala niti za nesintetično metodo getDate ()in poroča o tej napaki:

Datoteka gradnje: C: \ java \ examples \ sintetični \ build.xml -init: compile: [javac] Prevajanje 1 izvorne datoteke v C: \ java \ examples \ sintetični \ razredi [javac] C: \ java \ examples \ sintetični \ src \ dustin \ examples \ Rogue.java: 9: dustin.examples.DemonstrateSyntheticMethods.NestedClass ima zasebni dostop v dustin.examples.DemonstrateSyntheticMethods [javac] out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); [javac] ^ [javac] 1 napaka BUILD FAILED C: \ java \ examples \ sintetični \ build.xml: 29: Prevajanje ni uspelo; za podrobnosti glejte izpis napake prevajalnika. Skupni čas: 1 sekunda 

Kot kaže zgornje sporočilo o napaki pri prevajanju, tudi nesintetična metoda v ugnezdenem razredu ni dostopna v času prevajanja ker ima ugnezdeni razred zasebni obseg. V svojem članku Java Insecurities: Accounting for Subtilities That Can Compromise Code Charlie Lai razpravlja o možnih situacijah, v katerih so te spremembe, ki jih je uvedel prevajalnik, varnostne ranljivosti. Faisal Feroz gre še dlje in v prispevku Kako napisati varno kodo Java navaja: "Ne uporabljaj notranjih razredov" (za podrobnosti o notranjih razredih kot podmnožici ugnezdenih razredov glej razrede ugnezdenih, notranjih, članskih in najvišjih ravni). .

Mnogi od nas se lahko dolgo ukvarjamo z razvojem Jave, ne da bi morali bistveno razumeti sintetične metode. Vendar obstajajo situacije, ko je zavedanje o njih pomembno. Poleg varnostnih vprašanj, povezanih s tem, se je treba med branjem sledi skladov zavedati tudi, kaj so. Imena metod, kot so dostop do 100 USD, dostop 200 $, dostop 300 USD, dostop 400 $, dostop 500 USD, dostop 600 USD, in dostop 1000 $ v sledu sklada odraža sintetične metode, ki jih ustvari prevajalnik.

Izvirna objava na voljo na //marxsoftware.blogspot.com/

.

To zgodbo, "Sintetične metode Java", je prvotno objavil JavaWorld.

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