Programavimas

„Java“ sintetiniai metodai

Šiame tinklaraščio įraše apžvelgiu „Java“ sintetinių metodų sampratą. Įrašas apibendrina, kas yra „Java“ sintetinis metodas, kaip jį galima sukurti ir atpažinti, ir „Java“ sintetinių metodų reikšmė „Java“ plėtrai.

„Java“ kalbos specifikacijoje (13.1 skyrius) teigiama: „Visi kompiliatoriaus įvedami konstruktai, neturintys atitinkamo konstrukcijos šaltinio kode, turi būti pažymėti kaip sintetiniai, išskyrus numatytuosius konstruktorius ir klasės inicializavimo metodą“. Daugiau informacijos apie sintetinės „Java“ reikšmę galite rasti „Javadoc“ dokumente, skirtame Member.isSynthetic (). Šio metodo dokumentuose teigiama, kad jis grąžina „tiesa tik tada ir tik tuo atveju, jei šį narį pristatė kompiliatorius“. Man patinka tas labai trumpas „sintetinio“ apibrėžimas: kompiliatoriaus pateiktas „Java“ konstruktas.

„Java“ kompiliatorius turi sukurti sintetinius metodus įdėtose klasėse, kai jų atributus, nurodytus privačiame modifikatoriuje, pasiekia uždaroji klasė. Kitas kodo pavyzdys nurodo šią situaciją.

DemonstrateSyntheticMethods.java (Uždarant klasę iškviečiamas vienas įdėtos klasės privatus atributas)

pakuotė dustin.pavyzdžiai; importuoti java.util.Calendar; importuoti statinį java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumentai) {DemonstrateSyntheticMethods.NestedClass įdėta = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Stygos:" + įdėta. labai Konfidencialu); } privati ​​statinė galutinė klasė „NestedClass“ {private String veryConfidential = "Nesakyk apie mane niekam"; privatus int labaiConfidentialInt = 42; privatus kalendorius veryConfidentialCalendar = Calendar.getInstance (); privatus loginis logotipas labaiConfidentialBoolean = true; }} 

Aukščiau pateiktas kodas sudaromas be incidentų. Kai „javap“ paleidžiamas prieš kompiliuojamą .klasė failą, išvestis yra tokia, kaip parodyta šiame ekrano momentiniame vaizde.

Kaip rodo aukščiau pateiktas ekrano momentinis vaizdas, sintetinis metodas su pavadinimu prieiga prie 100 USD buvo sukurtas įdėtoje klasėje „NestedClass“ pateikti savo privačią stygą uždarymo klasei. Atkreipkite dėmesį, kad sintetinis metodas pridedamas tik prie vieno privataus „NestedClass“ atributo, prie kurio gauna pridedama klasė. Jei pakeisiu uždarą klasę, kad galėčiau pasiekti visus privačius „NestedClass“ atributus, bus sugeneruoti papildomi sintetiniai metodai. Kitas kodo pavyzdys rodo būtent tai ir ekrano momentinė nuotrauka įrodo, kad tokiu atveju generuojami keturi sintetiniai metodai.

DemonstrateSyntheticMethods.java (Uždaroma klasė iškviečia keturis įdėtus klasės asmeninius atributus)

pakuotė dustin.pavyzdžiai; importuoti java.util.Calendar; importuoti statinį java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumentai) {DemonstrateSyntheticMethods.NestedClass įdėta = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + įdėta. labai Konfidencialu); out.println ("Int:" + įdėta.highlyConfidentialInt); out.println ("Kalendorius:" + įdėtas.highlyConfidentialCalendar); out.println ("Boolean:" + įdėta.highlyConfidentialBoolean); } privati ​​statinė galutinė klasė „NestedClass“ {private String veryConfidential = "Nesakyk apie mane niekam"; privatus int labaiConfidentialInt = 42; privatus kalendorius veryConfidentialCalendar = Calendar.getInstance (); privatus loginis logotipas labaiConfidentialBoolean = true; }} 

Kaip rodo du ankstesni aukščiau pateikti kodo fragmentai ir susiję vaizdai, „Java“ kompiliatorius prireikus pristato sintetinius metodus. Kai pridedama klasė pasiekė tik vieną iš įdėtų klasės privačių atributų, tik vienas sintetinis metodas (prieiga prie 100 USD) sukūrė kompiliatorius. Tačiau, kai visus keturis privačius įdėtos klasės atributus pasiekė pridedama klasė, kompiliatorius sugeneravo keturis atitinkamus sintetinius metodus (prieiga prie 100 USD, prieiga prie 200 USD, naudotis 300 USDir naudotis 400 USD).

Visais atvejais, kai uždara klasė pasiekia savo įdėtos klasės asmeninius duomenis, buvo sukurtas sintetinis metodas, leidžiantis tai pasiekti. Kas atsitiks, kai įdėta klasė suteikia prieigą savo privatiems duomenims, kuriuos gaubianti klasė gali naudoti? Tai įrodyta kitame kodų sąraše ir jo išvestyje, kaip parodyta kitame ekrano momentiniame vaizde.

DemonstrateSyntheticMethods.java su „Nested Class Public Accessor for Private Data“

pakuotė dustin.pavyzdžiai; importuoti java.util.Calendar; importuoti java.util.Date; importuoti statinį java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumentai) {DemonstrateSyntheticMethods.NestedClass įdėta = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + įdėta. labai Konfidencialu); out.println ("Int:" + įdėta.highlyConfidentialInt); out.println ("Kalendorius:" + įdėtas.highlyConfidentialCalendar); out.println ("Boolean:" + įdėta.highlyConfidentialBoolean); out.println ("Data:" + įdėta.getDate ()); } privati ​​statinė galutinė klasė „NestedClass“ {private String veryConfidential = "Nesakyk apie mane niekam"; privatus int labaiConfidentialInt = 42; privatus kalendorius veryConfidentialCalendar = Calendar.getInstance (); privatus loginis logotipas labaiConfidentialBoolean = true; privati ​​data data = nauja data (); public Date getDate () {return this.date; }}} 

Pirmiau pateikta ekrano momentinė nuotrauka rodo, kad kompiliatoriui nereikėjo generuoti sintetinio metodo, kaip pasiekti privatų datos atributą įdėtoje klasėje, nes uždaroji klasė pasiekė tą atributą per pateiktą getDate () metodas. Netgi su getDate () jei kompiliatorius būtų sukūręs sintetinį būdą, kaip pasiekti data ar pridedamas kodas buvo parašytas norint pasiekti data atributą tiesiogiai (kaip savybę), o ne per prieigos metodą.

Paskutinis ekrano momentas pateikia dar vieną pastebėjimą. Kaip naujai pridėta getDate () metodas rodo toje ekrano nuotraukoje, modifikatorius, tokius kaip visuomenės yra įtraukti į „javap“ išvestį. Kadangi nėra rodomas kompiliatoriaus sukurtų sintetinių metodų modifikatorius, žinome, kad jie yra paketo lygio (arba paketo privatūs). Trumpai tariant, kompiliatorius sukūrė privačių paketų privačių atributų prieigos metodus.

„Java refleksijos“ API suteikia dar vieną metodą nustatant sintetinius metodus. Kitas kodų sąrašas yra „Groovy“ scenarijui, kuris naudos „Java“ atspindėjimo API, kad patogiai pateiktų išsamią informaciją apie aukščiau nurodytų įdėtos klasės metodus.

reflOnMethods.groovy

#! / usr / bin / env groovy import java.lang.reflect.Method import java.lang.reflect.Modifier if (args == null || args.size () <2) {println "Išoriniai ir įdėtieji klasių pavadinimai turi būti būti pateiktas “. println "\ nUsage # 1: reflectOnMethods kvalifikuojamasOuterClassName įdėtasClassName \ n" println "\ nUsage # 2: groovy -cp klasių kelias reflektuotiOnMethods.groovy ... t2. NENURODYKITE \ $ prieš įdėtą klasės pavadinimą. \ n "System.exit (-1)} def enclosingClassName = args [0] def nestedClassName = args [1] def fullNestedClassName = enclosingClassName + '$' + nestedClassName def enclosingClass = Class.forName (enclosingClassName) Klasė „nestedClass“ = nulinė „enclosingClass.declaredClasses.each“ {if (! nestedClass && fullNestedClassName.equals (it.name)) {nestedClass = it}} if (nestedClass == null) {println "Nepavyko rasti įdėtą klasę $ {fullNestedClassName} "System.exit (-2)} // Naudokite deklaruotus metodus, nes nerūpi paveldėti metodai nestedClass.declaredMethods.each {print" \ nMethod '$ {it.name}' "print" yra „$ {getScopeModifier (it)}“ sritis, „spausdinti“ $ {it.synthetic? 'yra sintetinis': 'nėra sintetinis'} ir „println“ $ {it.bridge? 'is bridge': 'NĖRA tiltas'}. "} def eilutė getScopeModifier (metodo metodas) {def modifiers = method.modifiers def isPrivate = Modifier.isPrivate (modifiers) def isPublic = Modifier.isPublic (modifiers) def isProtected = Modifier .isProtected (modifiers) String scopeString = "package-private" // default, jei (isPublic) {scopeString = "public"} else if (isProtected) {scopeString = "protected"} else if (isPrivate) {scopeString = "private" } grąžinimo apimtisString} 

Kai aukščiau pateiktas „Groovy“ scenarijus vykdomas prieš aukščiau pateiktą klasę ir įdėtą klasę, išvestis yra tokia, kuri parodyta kitame ekrano momentiniame vaizde.

Ankstesniame paveikslėlyje parodyti „Groovy“ scenarijaus rezultatai patvirtina, ką javapas jau mums pasakė: įdėtoje klasėje yra keturi sintetiniai metodai ir vienas nesintetinis metodas „NestedClass“. Scenarijuje taip pat sakoma, kad kompiliatorių sukurti sintetiniai metodai yra asmeninio paketo taikymo sritis.

Sintetinių metodų pridėjimas į įdėtą klasę paketo-privačios apimties lygiu nėra vienintelis dalykas, kurį kompiliatorius padarė aukščiau pateiktame pavyzdyje. Jis taip pat pakeitė pačios įdėtos klasės taikymo sritį nuo privataus kodo nustatymo iki paketo-privataus .klasė failą. Iš tiesų, nors sintetiniai metodai buvo pridėti tik tuo atveju, kai uždaroji klasė pasiekė privatų atributą, kompiliatorius visada įdėtą klasės paketą daro privatų, net jei kode jis nurodytas kaip privatus. Geros naujienos yra tai, kad tai yra kompiliavimo proceso artefaktas, o tai reiškia, kad kodo negalima kompiliuoti taip, kaip yra prieš pakeistą įdėtos klasės apimties lygį ar jo sintetinius metodus. Vykdymo laikas yra tas, kuriame viskas gali tapti kauliška.

Klasė „Rogue“ bando pasiekti kai kuriuos „NestedClass“ sintetinius metodus. Toliau rodomas jo šaltinio kodas, po kurio atsiranda kompiliatoriaus klaida, pastebėta bandant kompiliuoti šį „Rogue“ šaltinio kodą.

Rogue.java bando pasiekti sintetinius metodus kompiliavimo metu

pakuotė dustin.pavyzdžiai; importuoti statinį java.lang.System.out; public class Rogue {public static void main (final String [] argumentai) {out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); }} 

Aukščiau pateiktas kodas nebus sukompiliuojamas net ir nesintetinio metodo atveju getDate ()ir praneša apie šią klaidą:

Sukūrimo failas: C: \ java \ pavyzdžiai \ sintetinis \ build.xml -init: compile: [javac] 1 šaltinio failo kompiliavimas C: \ java \ pavyzdžiai \ sintetinis \ klasės [javac] C: \ java \ pavyzdžiai \ sintetinis \ src \ dustin \ pavyzdžiai \ Rogue.java: 9: dustin.examples.DemonstrateSyntheticMethods.NestedClass turi privačią prieigą dulkių.examples.DemonstrateSyntheticMethods [javac] out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); [javac] ^ [javac] 1 klaida BUILD FAILED C: \ java \ pavyzdžiai \ sintetinis \ build.xml: 29: kompiliacija nepavyko; daugiau informacijos rasite kompiliatoriaus klaidos išvestyje. Bendras laikas: 1 sekundė 

Kaip rodo pirmiau pateiktas kompiliacijos klaidos pranešimas, net nesintetinis metodas įdėtoje klasėje yra nepasiekiamas kompiliavimo metu nes įdėta klasė yra privati. Straipsnyje „Java Insecurity: subtilybių, galinčių pakenkti kodui, apskaita“ Charlie Lai aptaria galimas situacijas, kai šie kompiliatoriaus įvedami pakeitimai yra saugumo spragos. Faisalas Ferozas eina toliau ir pranešime „Kaip rašyti saugų„ Java “kodą“ „Nenaudoti vidinių klasių“ (išsamesnės informacijos apie vidines klases, kaip įdėtųjų klasių pogrupį, ieškokite įdėtose, vidinėse, nario ir aukščiausio lygio klasėse). .

Daugelis iš mūsų gali ilgai tobulėti kurdami Java, nereikalaudami didelio supratimo apie sintetinius metodus. Tačiau yra situacijų, kai jų suvokimas yra svarbus. Be saugumo problemų, susijusių su jomis, taip pat reikia žinoti, kas jie yra, kai skaitote kamino pėdsakus. Metodo pavadinimai, pvz prieiga prie 100 USD, prieiga prie 200 USD, naudotis 300 USD, naudotis 400 USD, naudotis 500 USD, naudotis 600 USDir naudotis 1000 USD kamino pėdsakai atspindi kompiliatoriaus sukurtus sintetinius metodus.

Originalus įrašas pasiekiamas adresu //marxsoftware.blogspot.com/

.

Šią istoriją „Sintetiniai„ Java “metodai“ iš pradžių paskelbė „JavaWorld“.