Programmēšana

Java sintētiskās metodes

Šajā emuāra ziņā es aplūkoju Java sintētisko metožu jēdzienu. Ziņa apkopo, kas ir Java sintētiskā metode, kā to var izveidot un identificēt, kā arī Java sintētisko metožu ietekme uz Java attīstību.

Java valodas specifikācijā (13.1. Sadaļa) teikts: "Visiem kompilatora ieviestajiem konstruktiem, kuru avota kodā nav atbilstoša konstrukcija, jābūt atzīmētiem kā sintētiskiem, izņemot noklusējuma konstruktorus un klases inicializācijas metodi." Papildu norādījumus par sintētiskās valodas nozīmi Java var atrast Javadoc dokumentācijā Member.isSynthetic (). Šīs metodes dokumentācijā ir teikts, ka tā atgriež vērtību “taisnība tikai tad, ja kompilators ir ieviesis šo dalībnieku”. Man patīk šī ļoti īsā "sintētiskā" definīcija: kompilatora ieviesta Java konstrukcija.

Ja kompilatoram ir piekļuve to atribūtiem, kas norādīti ar privāto modifikatoru, Java kompilatoram jāizveido sintezētas metodes ligzdotām klasēm. Nākamais koda paraugs norāda šo situāciju.

DemonstrateSyntheticMethods.java (klases aizvēršana izsauc vienu ligzdotu klases privāto atribūtu)

iepakojums dustin.piemēri; importēt java.util.Calendar; importēt statisko java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] arguments) {DemonstrateSyntheticMethods.NestedClass nested = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Virkne:" + ligzdots.augstsKonfidenciāls); } privāta statiska gala klase NestedClass {private String veryConfidential = "Nesaki nevienam par mani"; privāts int ļotiConfidentialInt = 42; privātais kalendārs veryConfidentialCalendar = Calendar.getInstance (); privāts būla lielumsConfidentialBoolean = true; }} 

Iepriekš minētais kods tiek apkopots bez starpgadījumiem. Kad javap tiek palaists pret kompilēto .klase failu, izeja ir tāda, kā parādīts nākamajā ekrāna momentuzņēmumā.

Kā norādīts iepriekš redzamajā ekrāna momentuzņēmumā, sintētiska metode ar nosaukumu piekļūt 100 ASV dolāriem ir izveidots ligzdotajā klasē NestedClass nodrošināt savu privāto stīgu norobežojošajai klasei. Ņemiet vērā, ka sintētiskā metode tiek pievienota tikai vienam NestedClass privātajam atribūtam, kuram piekļūst norobežojošā klase. Ja mainīšu norobežojošo klasi, lai piekļūtu visiem NestedClass privātajiem atribūtiem, tiks ģenerētas papildu sintētiskās metodes. Nākamais koda piemērs parāda tieši to, un ekrāna momentuzņēmums, kas seko tam, pierāda, ka šajā gadījumā tiek ģenerētas četras sintētiskās metodes.

DemonstrateSyntheticMethods.java (klases aizvēršana izsauc četrus ligzdotus klases privātos atribūtus)

iepakojums dustin.piemēri; importēt java.util.Calendar; importēt statisko java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] arguments) {DemonstrateSyntheticMethods.NestedClass nested = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Virkne:" + ligzdots.augstsKonfidenciāls); out.println ("Int:" + nested.highlyConfidentialInt); out.println ("Kalendārs:" + nested.highlyConfidentialCalendar); out.println ("Būla:" + nested.highlyConfidentialBoolean); } privāta statiskā gala klase NestedClass {private String veryConfidential = "Nesaki nevienam par mani"; privāts int ļotiConfidentialInt = 42; privātais kalendārs veryConfidentialCalendar = Calendar.getInstance (); privāts būla lielumsConfidentialBoolean = true; }} 

Kā rāda iepriekšējie divi iepriekšējie koda fragmenti un saistītie attēli, Java kompilators pēc nepieciešamības ievieš sintētiskās metodes. Kad pievienojošā klase piekļuva tikai vienam no ligzdotās klases privātajiem atribūtiem, tikai viena sintētiskā metode (piekļūt 100 ASV dolāriem) izveidoja sastādītājs. Tomēr, kad visiem četriem ligzdotās klases privātajiem atribūtiem piekļuva pievienojošā klase, kompilators izveidoja četras atbilstošās sintētiskās metodes (piekļūt 100 ASV dolāriem, piekļūt 200 USD, piekļūt 300 USD, un piekļūt 400 ASV dolāriem).

Visos gadījumos, kad norobežojošā klase piekļūst ligzdotās klases privātajiem datiem, tika izveidota sintētiska metode, kas ļautu šai piekļuvei notikt. Kas notiek, kad ligzdotā klase nodrošina piekļuvi saviem privātajiem datiem, kurus var izmantot pievienojošā klase? Tas tiek parādīts nākamajā kodu sarakstā un tā izvadē, kā parādīts nākamajā ekrāna momentuzņēmumā.

DemonstrateSyntheticMethods.java ar ligzdotu klases privāto datu publisko piekļuvi

iepakojums dustin.piemēri; importēt java.util.Calendar; importēt java.util.Date; importēt statisko java.lang.System.out; public final class DemonstrateSyntheticMethods {public static void main (final String [] argumenti) {DemonstrateSyntheticMethods.NestedClass nested = new DemonstrateSyntheticMethods.NestedClass (); out.println ("Virkne:" + ligzdots.augstsKonfidenciāls); out.println ("Int:" + nested.highlyConfidentialInt); out.println ("Kalendārs:" + nested.highlyConfidentialCalendar); out.println ("Būla:" + nested.highlyConfidentialBoolean); out.println ("Datums:" + ligzdots.getDate ()); } privāta statiska gala klase NestedClass {private String veryConfidential = "Nesaki nevienam par mani"; privāts int ļotiConfidentialInt = 42; privātais kalendārs veryConfidentialCalendar = Calendar.getInstance (); privāts būla lielumsConfidentialBoolean = true; privāts datuma datums = jauns datums (); public Date getDate () {return this.date; }}} 

Iepriekš redzamais ekrāna momentuzņēmums parāda, ka kompilatoram nebija jāveido sintētiska metode, lai piekļūtu privātajam datuma atribūtam ligzdotajā klasē, jo norobežojošā klase šim atribūtam piekļuva, izmantojot norādīto getDate () metodi. Pat ar getDate () ja kompilators būtu ģenerējis sintētisku metodi piekļuvei datums vai pievienošanas kods ir uzrakstīts, lai piekļūtu datums atribūtu tieši (kā rekvizītu), nevis izmantojot piekļuves metodi.

Pēdējais ekrāna momentuzņēmums rada vēl vienu novērojumu. Kā tikko pievienots getDate () metode šajā ekrāna momentuzņēmumā parāda modifikatorus, piemēram, publiski ir iekļauti javap izvadē. Tā kā sastādītāja izveidotajām sintētiskajām metodēm netiek parādīts modifikators, mēs zinām, ka tās ir paketes līmeņa (vai paketes privātas). Īsāk sakot, kompilators ir izveidojis paketes-privātas metodes piekļuvei privātiem atribūtiem.

Java atspoguļošanas API nodrošina citu pieeju sintētisko metožu noteikšanai. Nākamais kodu saraksts ir Groovy skriptam, kas izmantos Java atspoguļošanas API, lai ērti sniegtu informāciju par iepriekš parādīto ligzdotās klases metodēm.

reflektēt On Metodes.groovy

#! / usr / bin / env groovy import java.lang.reflect.Method import java.lang.reflect.Modifier if (args == null || args.size () <2) {println "Ārējiem un ligzdotajiem klases nosaukumiem jābūt jāsniedz. " println "\ nLietojums # 1: reflektētOnMethods kvalificētsOuterClassName nestedClassName \ n" println "\ nLietojums # 2: groovy -cp klasespats reflektētOnMethods.groovy kvalificētsOuterClassName nestedClassName \ n" println "\ t1" Iekļaut ārējo un nested klasi. t2. NESAVIET iekļaut \ $ ligzdotās klases nosaukuma priekšā. \ n "System.exit (-1)} def enclosingClassName = args [0] def nestedClassName = args [1] def fullNestedClassName = enclosingClassName + '$' + nestedClassName def enclosingClass = Class.forName (enclosingClassName) Klase nestedClass = null enclosingClass.declaredClasses.each {if (! nestedClass && fullNestedClassName.equals (it.name)) {nestedClass = it}} if (nestedClass == null) {println "Nevar atrast ligzdoto klasi $ {fullNestedClassName} "System.exit (-2)} // Izmantojiet deklarētās metodes, jo jums nav nozīmes mantotajām metodēm nestedClass.declaredMethods.each {print" \ nMethod '$ {it.name}' "print" ir darbības joma $ {getScopeModifier (it)}, "drukāt" $ {it.synthetic? 'ir sintētiska': 'NAV sintētisks'}, un "println" $ {it.bridge? 'is bridge': 'NAV tilts'}. "} def virkne getScopeModifier (Metodes metode) {def modifiers = method.modifiers def isPrivate = Modifier.isPrivate (modifiers) def isPublic = Modifier.isPublic (modifiers) def isProtected = Modifier .isProtected (modifikatori) String scopeString = "package-private" // noklusējums if (isPublic) {scopeString = "public"} else if (isProtected) {scopeString = "protected"} else if (isPrivate) {scopeString = "private" } return rangeString} 

Kad iepriekšminētais Groovy skripts tiek izpildīts pret klasi un ligzdoto klasi, kas parādīta iepriekš, izeja ir tāda, kas parādīta nākamajā ekrāna momentuzņēmumā.

Iepriekšējā attēlā redzamie Groovy skripta rezultāti apstiprina to, ko javap jau bija teicis: ligzdotajā klasē ir noteiktas četras sintētiskās metodes un viena nesintētiskā metode NestedClass. Skripts arī mums saka, ka kompilatoru ģenerētās sintētiskās metodes ir paketes privātas darbības jomas.

Sintētisko metožu pievienošana ligzdotajai klasei paketes un privātās jomas līmenī nav vienīgais, ko kompilators izdarīja iepriekš minētajā piemērā. Tas arī mainīja pašas ligzdotās klases darbības jomu no privātā iestatījuma kodā uz paketi-privāts .klase failu. Patiešām, kaut arī sintētiskās metodes tika pievienotas tikai gadījumā, ja pievienojošā klase piekļuva privātajam atribūtam, kompilators vienmēr ligzdoto klases paketi padara privātu, pat ja kodā tā ir norādīta kā privāta. Labā ziņa ir tā, ka tas ir kompilācijas procesa artefakts, kas nozīmē, ka kodu nevar sastādīt tā, kā tas ir pret mainīto ligzdotās klases darbības jomu vai tā sintētiskajām metodēm. Izpildlaiks ir tas, kur lietas var kļūt dicey.

Klase Rogue mēģina piekļūt dažām NestedClass sintētiskajām metodēm. Tālāk tiek parādīts tā pirmkods, kam seko kompilatora kļūda, kas redzama, mēģinot apkopot šo Rogue avota kodu.

Rogue.java kompilēšanas laikā mēģina piekļūt sintētiskām metodēm

iepakojums dustin.piemēri; importēt statisko java.lang.System.out; public class Rogue {public static void main (final String [] argumenti) {out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); }} 

Iepriekš minētais kods netiks apkopots pat nesintētiskai metodei getDate ()un ziņo par šo kļūdu:

Veidošanas fails: C: \ java \ piemēri \ sintētisks \ build.xml -init: compile: [javac] 1 avota faila apkopošana C: \ java \ piemēri \ sintētisks \ klases [javac] C: \ java \ piemēri \ sintētisks \ src \ dustin \ piemēri \ Rogue.java: 9: dustin.examples.DemonstrateSyntheticMethods.NestedClass ir privāta piekļuve dustin.examples.DemonstrateSyntheticMethods [javac] out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); [javac] ^ [javac] 1 kļūda BUILD FAILED C: \ java \ piemēri \ syntheti \ build.xml: 29: Kompilēšana neizdevās; sīkāku informāciju skatiet kompilatora kļūdas izvadē. Kopējais laiks: 1 sekunde 

Kā norāda iepriekšējais apkopošanas kļūdas ziņojums, pat nesintētiskā metode ligzdotajā klasē nav pieejama sastādīšanas laikā jo ligzdotajai klasei ir privāta darbības joma. Savā rakstā Java Insecurity: Grāmatvedība par smalkumiem, kas var apdraudēt kodu, Čārlijs Lai apspriež iespējamās situācijas, kurās šīs kompilatora ieviestās izmaiņas ir drošības ievainojamības. Faisal Feroz iet tālāk un paziņojumā Kā rakstīt drošu Java kodu: "Nelietot iekšējās klases" (detalizētu informāciju par iekšējām klasēm kā ligzdotu klašu apakškopu skatiet sadaļā Nested, Inner, Member un Top-Level Class). .

Daudzi no mums var ilgi strādāt Java izstrādē, neprasot būtisku izpratni par sintētiskajām metodēm. Tomēr ir situācijas, kad to apzināšanās ir svarīga. Papildus drošības jautājumiem, kas saistīti ar tiem, ir jāapzinās arī kādi tie ir, lasot kaudzes pēdas. Metodes nosaukumi, piemēram, piekļūt 100 ASV dolāriem, piekļūt 200 USD, piekļūt 300 USD, piekļūt 400 ASV dolāriem, piekļūt 500 ASV dolāriem, piekļūt 600 ASV dolāriem, un piekļūt 1000 USD kaudzē izsekot atspoguļo sintētiskās metodes, ko ģenerējis kompilators.

Sākotnējais ziņojums pieejams vietnē //marxsoftware.blogspot.com/

.

Šo stāstu "Java sintētiskās metodes" sākotnēji publicēja JavaWorld.

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