Προγραμματισμός

Συνθετικές μέθοδοι Java

Σε αυτήν την ανάρτηση ιστολογίου, εξετάζω την έννοια των συνθετικών μεθόδων Java. Η ανάρτηση συνοψίζει τι είναι μια συνθετική μέθοδος Java, πώς μπορεί να δημιουργηθεί και να προσδιοριστεί κάποιος, και τις επιπτώσεις των συνθετικών μεθόδων Java στην ανάπτυξη της Java.

Η προδιαγραφή γλώσσας Java (ενότητα 13.1) δηλώνει "Οποιαδήποτε κατασκευάσματα που εισήχθησαν από τον μεταγλωττιστή και δεν έχουν αντίστοιχη δομή στον πηγαίο κώδικα πρέπει να επισημαίνονται ως συνθετικά, εκτός από τους προεπιλεγμένους κατασκευαστές και τη μέθοδο αρχικοποίησης κλάσης." Περαιτέρω ενδείξεις σχετικά με την έννοια του συνθετικού στη Java μπορείτε να βρείτε στην τεκμηρίωση Javadoc για το Member.isSynthetic (). Η τεκμηρίωση αυτής της μεθόδου δηλώνει ότι επιστρέφει "true εάν και μόνο εάν αυτό το μέλος εισήχθη από τον μεταγλωττιστή." Μου αρέσει αυτός ο πολύ σύντομος ορισμός του "συνθετικού": μια κατασκευή Java που εισήγαγε ο μεταγλωττιστής.

Ο μεταγλωττιστής Java πρέπει να δημιουργήσει συνθετικές μεθόδους σε ένθετες κλάσεις όταν τα χαρακτηριστικά τους που καθορίζονται με τον ιδιωτικό τροποποιητή έχουν πρόσβαση από την κλάση που περικλείει. Το επόμενο δείγμα κώδικα δείχνει αυτήν την κατάσταση.

DemonstrateSyntheticMethods.java (Το να περικλείει την τάξη προκαλεί ένα ιδιωτικό χαρακτηριστικό μιας ένθετης τάξης)

πακέτο dustin.example; εισαγωγή java.util.Calendar; εισαγωγή στατικού java.lang.System.out; δημόσια τελική τάξη DemonstrateSyntheticMethods {public static void main (final String [] επιχειρήματα) {DemonstrateSyntheticMethods.NestedClass nested = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + nested.highlyConfidential); } ιδιωτικό στατικό τελικό μάθημα NestedClass {private String υψηλήςConfidential = "Μην πείτε σε κανέναν για μένα"; ιδιωτικό int ιδιαίτεραConfidentialInt = 42; ιδιωτικό ημερολόγιο ιδιαίτεραConfidentialCalendar = Calendar.getInstance (); ιδιωτικό boolean υψηλήςConfidentialBoolean = true; }} 

Ο παραπάνω κώδικας μεταγλωττίζεται χωρίς συμβάν. Όταν το javap εκτελείται ενάντια στο μεταγλωττισμένο .τάξη αρχείο, η έξοδος είναι όπως φαίνεται στο παρακάτω στιγμιότυπο οθόνης.

Όπως δείχνει το παραπάνω στιγμιότυπο οθόνης, μια συνθετική μέθοδος με το όνομα πρόσβαση σε $ 100 έχει δημιουργηθεί στην ένθετη τάξη NestedClass για να παρέχει την ιδιωτική του συμβολοσειρά στην κατηγορία που περικλείει. Σημειώστε ότι η συνθετική μέθοδος προστίθεται μόνο για το μοναδικό ιδιωτικό χαρακτηριστικό του NestedClass στο οποίο έχει πρόσβαση η κλάση εγκλεισμού. Αν αλλάξω την κλάση εγκλεισμού για πρόσβαση σε όλα τα ιδιωτικά χαρακτηριστικά του NestedClass, θα δημιουργηθούν πρόσθετες συνθετικές μέθοδοι. Το επόμενο παράδειγμα κώδικα δείχνει ότι κάνει ακριβώς αυτό και το στιγμιότυπο οθόνης που ακολουθεί αποδεικνύει ότι δημιουργούνται τέσσερις συνθετικές μέθοδοι σε αυτήν την περίπτωση.

DemonstrateSyntheticMethods.java (Συμπερίληψη κλάσης επικαλείται τέσσερις ένθετες κατηγορίες ιδιωτικών χαρακτηριστικών)

πακέτο dustin.example; εισαγωγή java.util.Calendar; εισαγωγή στατικού java.lang.System.out; δημόσια τελική τάξη DemonstrateSyntheticMethods {public static void main (final String [] επιχειρήματα) {DemonstrateSyntheticMethods.NestedClass nested = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + nested.highlyConfidential); out.println ("Int:" + nested.highlyConfidentialInt); out.println ("Ημερολόγιο:" + nested.highlyConfidentialCalendar); out.println ("Boolean:" + nested.highlyConfidentialBoolean); } ιδιωτικό στατικό τελικό μάθημα NestedClass {private String highConfidential = "Μην πείτε σε κανέναν για μένα"; ιδιωτικό int ιδιαίτεραConfidentialInt = 42; ιδιωτικό ημερολόγιο ιδιαίτεραConfidentialCalendar = Calendar.getInstance (); ιδιωτικό boolean υψηλήςConfidentialBoolean = true; }} 

Όπως δείχνουν τα προηγούμενα δύο αποσπάσματα κώδικα και οι σχετικές εικόνες, ο μεταγλωττιστής Java εισάγει συνθετικές μεθόδους ανάλογα με τις ανάγκες. Όταν μόνο ένα από τα ιδιωτικά χαρακτηριστικά της ένθετης τάξης είχε πρόσβαση από την κλάση που περικλείει, μόνο μία συνθετική μέθοδος (πρόσβαση σε $ 100δημιουργήθηκε από τον μεταγλωττιστή. Ωστόσο, όταν και τα τέσσερα ιδιωτικά χαρακτηριστικά της ένθετης τάξης είχαν πρόσβαση από την κλάση εγκλεισμού, δημιουργήθηκαν τέσσερις αντίστοιχες συνθετικές μέθοδοι από τον μεταγλωττιστή (πρόσβαση σε $ 100, πρόσβαση 200 $, πρόσβαση 300 $, και πρόσβαση σε 400 $).

Σε όλες τις περιπτώσεις μιας κλειστής τάξης που αποκτά πρόσβαση στα ιδιωτικά δεδομένα της ένθετης τάξης, δημιουργήθηκε μια συνθετική μέθοδος που επιτρέπει την πραγματοποίηση αυτής της πρόσβασης. Τι συμβαίνει όταν η ένθετη τάξη παρέχει ένα βοηθητικό πρόγραμμα για τα ιδιωτικά δεδομένα που μπορεί να χρησιμοποιήσει η κλάση που περικλείει; Αυτό αποδεικνύεται στην επόμενη λίστα κωδικών και στην έξοδο όπως φαίνεται στο επόμενο στιγμιότυπο οθόνης.

DemonstrateSyntheticMethods.java με Πρόσθετο δημόσιο Accessor για έντυπα δεδομένα

πακέτο dustin.example; εισαγωγή java.util.Calendar; εισαγωγή java.util.Date; εισαγωγή στατικού java.lang.System.out; δημόσια τελική κλάση DemonstrateSyntheticMethods {public static void main (final επιχειρήματα String []) {DemonstrateSyntheticMethods.NestedClass nested = new DemonstrateSyntheticMethods.NestedClass (); out.println ("String:" + nested.highlyConfidential); out.println ("Int:" + nested.highlyConfidentialInt); out.println ("Ημερολόγιο:" + nested.highlyConfidentialCalendar); out.println ("Boolean:" + nested.highlyConfidentialBoolean); out.println ("Ημερομηνία:" + nested.getDate ()); } ιδιωτικό στατικό τελικό μάθημα NestedClass {private String υψηλήςConfidential = "Μην πείτε σε κανέναν για μένα"; ιδιωτικό int ιδιαίτεραConfidentialInt = 42; ιδιωτικό ημερολόγιο ιδιαίτεραConfidentialCalendar = Calendar.getInstance (); ιδιωτικό boolean υψηλήςConfidentialBoolean = true; ιδιωτική ημερομηνία ημερομηνία = νέα ημερομηνία (); δημόσια Ημερομηνία getDate () {return this.date; }}} 

Το παραπάνω στιγμιότυπο οθόνης δείχνει ότι ο μεταγλωττιστής δεν χρειάστηκε να δημιουργήσει μια συνθετική μέθοδο για την πρόσβαση στο ιδιωτικό χαρακτηριστικό Ημερομηνία στην ένθετη κλάση, επειδή η κλάση που περιλάμβανε πρόσβαση στο συγκεκριμένο χαρακτηριστικό μέσω των παρεχόμενων getDate () μέθοδος. Ακόμα και με getDate () υπό την προϋπόθεση, ο μεταγλωττιστής θα είχε δημιουργήσει μια συνθετική μέθοδο για την πρόσβαση στο ημερομηνία έχει γραφεί ο κωδικός για την πρόσβαση στο ημερομηνία χαρακτηριστικό απευθείας (ως ιδιοκτησία) και όχι μέσω της μεθόδου πρόσβασης.

Το τελευταίο στιγμιότυπο οθόνης εμφανίζει μια άλλη παρατήρηση. Όπως προστέθηκε πρόσφατα getDate () Η μέθοδος δείχνει σε αυτό το στιγμιότυπο οθόνης, τροποποιητές όπως δημόσιο περιλαμβάνονται στην έξοδο javap. Επειδή δεν εμφανίζεται τροποποιητής για τις συνθετικές μεθόδους που δημιουργούνται από τον μεταγλωττιστή, γνωρίζουμε ότι είναι επίπεδο πακέτου (ή πακέτο-ιδιωτικό). Εν ολίγοις, ο μεταγλωττιστής έχει δημιουργήσει μεθόδους ιδιωτικού πακέτου για πρόσβαση σε ιδιωτικά χαρακτηριστικά.

Τα API αντανάκλασης Java παρέχουν μια άλλη προσέγγιση για τον προσδιορισμό συνθετικών μεθόδων. Η επόμενη λίστα κωδικών αφορά ένα σενάριο Groovy που θα χρησιμοποιεί τα API αντανάκλασης Java για εύκολη παροχή λεπτομερειών σχετικά με τις μεθόδους της ένθετης τάξης που φαίνεται παραπάνω.

reflectOnMethods.groovy

#! / usr / bin / env groovy εισαγωγή java.lang.reflect.M Method import java.lang.reflect.Modifier if (args == null || args.size () <2) {println "Τα ονόματα εξωτερικών και ένθετων τάξεων πρέπει να παρέχεται." println "\ nΧρήση # 1: reflectOnMethods qualOuterClassName nestedClassName \ n" println "\ nΧρήση # 2: groovy -cp classpath reflectOnMethods.groovy qualifiedOuterClassName nestedClassName \ n" println "\ t1. Συμπεριλάβετε class και nested class t2. ΜΗΝ συμπεριλάβετε \ $ μπροστά από το όνομα της ένθετης τάξης. \ n "System.exit (-1)} def enclosingClassName = args [0] def nestedClassName = args [1] def fullNestedClassName = enclosingClassName + '$' + nestedClassName def enclosingClass = Class.forName (enclosingClassName) Κατηγορία nestedClass = null enclosingClass.declaredClasses.each {if (! nestedClass && fullNestedClassName.equals (it.name)) {nestedClass = it}} if (nestedClass == null) {println "Unable to βρείτε ένθετη τάξη $ {fullNestedClassName} "System.exit (-2)} // Χρησιμοποιήστε δηλωμένες μεθόδους γιατί δεν ενδιαφέρεστε για κληρονομικές μεθόδους nestedClass.declaredMethods.each {print" \ nMethod '$ {it.name}' "print" $ {getScopeModifier (it)} εύρος, "print" $ {it.synthetic? 'is synthetic': "ΔΕΝ είναι συνθετικό"} και "println" $ {it.bridge; 'is bridge': 'is NOT bridge'}. "} def String getScopeModifier (Method method) {def modifiers = method.modifiers def isPrivate = Modifier.isPrivate (modifiers) def isPublic = Modifier.isPublic (modifiers) def isProtected = Modifier .isProtected (τροποποιητές) String lingkupString = "package-private" // προεπιλογή εάν (isPublic) {cakupanString = "public"} αλλιώς εάν (isProtected) {lingkuptring = "προστατευμένο"} αλλιώς εάν (isPrivate) {cakupanString = "ιδιωτικό" } επιστροφή πεδίου String} 

Όταν το παραπάνω σενάριο Groovy εκτελείται έναντι της κλάσης και της ένθετης τάξης που φαίνεται παραπάνω, η έξοδος είναι αυτή που εμφανίζεται στο επόμενο στιγμιότυπο οθόνης.

Τα αποτελέσματα του σεναρίου Groovy που εμφανίζονται στην προηγούμενη εικόνα επιβεβαιώνουν τι είχε ήδη πει ο javap: υπάρχουν τέσσερις συνθετικές μέθοδοι και μία μη συνθετική μέθοδος που ορίζονται στην ένθετη τάξη NestedClass. Το σενάριο μας λέει επίσης ότι οι συνθετικές μέθοδοι που δημιουργούνται από τον μεταγλωττιστή είναι πακέτο ιδιωτικού πακέτου.

Η προσθήκη συνθετικών μεθόδων στην ένθετη τάξη σε επίπεδο πακέτου-ιδιωτικού πεδίου δεν είναι το μόνο πράγμα που έκανε ο μεταγλωττιστής στο παραπάνω παράδειγμα. Επίσης, άλλαξε το πεδίο εφαρμογής της ίδιας της ένθετης κλάσης από την ιδιωτική ρύθμιση σε κώδικα σε πακέτο-ιδιωτικό στο .τάξη αρχείο. Πράγματι, ενώ οι συνθετικές μέθοδοι προστέθηκαν μόνο στην περίπτωση όπου η κλάση εγκλεισμού είχε πρόσβαση στο ιδιωτικό χαρακτηριστικό, ο μεταγλωττιστής κάνει πάντα το ένθετο πακέτο κλάσης-ιδιωτικό ακόμη και αν έχει οριστεί ως ιδιωτικό στον κώδικα. Τα καλά νέα είναι ότι αυτό είναι ένα προκύπτον τεχνούργημα της διαδικασίας σύνταξης, που σημαίνει ότι ο κώδικας δεν μπορεί να μεταγλωττιστεί όπως είναι σε αντίθεση με το αλλαγμένο επίπεδο εμβέλειας της ένθετης τάξης ή των συνθετικών μεθόδων της. Ο χρόνος εκτέλεσης είναι όπου τα πράγματα μπορούν να γίνουν δυσάρεστα.

Η τάξη, Rogue, επιχειρεί να αποκτήσει πρόσβαση σε ορισμένες από τις συνθετικές μεθόδους NestedClass. Ο πηγαίος κώδικας του εμφανίζεται στη συνέχεια, ακολουθούμενος από το σφάλμα μεταγλωττιστή που εμφανίζεται κατά την προσπάθεια σύνταξης αυτού του πηγαίου κώδικα Rogue.

Ο Rogue.java προσπαθεί να αποκτήσει πρόσβαση σε συνθετικές μεθόδους τη στιγμή της μεταγλώττισης

πακέτο dustin.example; εισαγωγή στατικού java.lang.System.out; δημόσια τάξη Rogue {public static void main (final String [] επιχειρήματα) {out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()); }} 

Ο παραπάνω κωδικός δεν θα μεταγλωττιστεί, ακόμη και για τη μη συνθετική μέθοδο getDate ()και αναφέρει αυτό το σφάλμα:

Buildfile: C: \ java \ samples \ synthetic \ build.xml -init: compile: [javac] Μεταγλώττιση 1 αρχείου προέλευσης σε C: \ java \ example \ synthetic \ class [javac] C: \ java \ models \ synthetic \ src \ dustin \ example \ Rogue.java: 9: dustin.examples.DemonstrateSyntheticMethods.NestedClass έχει ιδιωτική πρόσβαση στο dustin.examples.DemonstrateSyntheticMethods [javac] out.println (DemonstrateSyntheticMethods.NestedClass.getDate ()) [javac] ^ [javac] 1 σφάλμα BUILD FAILED C: \ java \ samples \ synthetic \ build.xml: 29: Η μεταγλώττιση απέτυχε. δείτε την έξοδο σφάλματος μεταγλωττιστή για λεπτομέρειες. Συνολικός χρόνος: 1 δευτερόλεπτο 

Όπως δείχνει το παραπάνω μήνυμα σφάλματος σύνταξης, ακόμη και η μη συνθετική μέθοδος στην ένθετη τάξη δεν είναι προσβάσιμη κατά τη μεταγλώττιση επειδή η ένθετη τάξη έχει ιδιωτικό πεδίο. Στο άρθρο του Java Insecurities: Λογιστική για τις λεπτές αποχρώσεις που μπορούν να συμβιβαστούν με κώδικα, ο Τσάρλι Λάι συζητά τις πιθανές καταστάσεις στις οποίες αυτές οι αλλαγές που εισάγονται από τον μεταγλωττιστή είναι ευπάθειες ασφαλείας. Ο Faisal Feroz πηγαίνει πιο μακριά και δηλώνει, στην ανάρτηση Πώς να γράψετε ασφαλή κώδικα Java, "Μην χρησιμοποιείτε εσωτερικές τάξεις" (ανατρέξτε στις ενότητες Nested, Inner, Member και Top-Level για λεπτομέρειες σχετικά με τις εσωτερικές τάξεις ως υποσύνολο ένθετων τάξεων) .

Πολλοί από εμάς μπορούν να πάνε για μεγάλο χρονικό διάστημα στην ανάπτυξη Java χωρίς να χρειάζεται σημαντική κατανόηση των συνθετικών μεθόδων. Ωστόσο, υπάρχουν καταστάσεις όπου η συνειδητοποίηση αυτών είναι σημαντική. Εκτός από ζητήματα ασφαλείας που σχετίζονται με αυτά, πρέπει επίσης να γνωρίζετε τι είναι όταν διαβάζετε ίχνη στοίβας. Ονόματα μεθόδων όπως πρόσβαση σε $ 100, πρόσβαση 200 $, πρόσβαση 300 $, πρόσβαση σε 400 $, πρόσβαση 500 $, πρόσβαση σε 600 $, και πρόσβαση στα 1000 $ στο stack trace αντανακλούν συνθετικές μεθόδους που δημιουργούνται από τον μεταγλωττιστή.

Πρωτότυπη ανάρτηση Διαθέσιμη στη διεύθυνση //marxsoftware.blogspot.com/

.

Αυτή η ιστορία, "Java's Synthetic Methods" δημοσιεύθηκε αρχικά από το JavaWorld.

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