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

Αντικείμενα και πίνακες

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

Αντικειμενοστραφής μηχανή

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

Στην εικονική μηχανή Java, η μνήμη κατανέμεται στον σωρό που συλλέγεται σκουπίδια μόνο ως αντικείμενα. Δεν υπάρχει τρόπος εκχώρησης μνήμης για πρωτόγονο τύπο στο σωρό, εκτός από μέρος ενός αντικειμένου. Εάν θέλετε να χρησιμοποιήσετε έναν πρωτόγονο τύπο όπου ένα Αντικείμενο απαιτείται αναφορά, μπορείτε να εκχωρήσετε ένα αντικείμενο περιτύλιξης για τον τύπο από το java.lang πακέτο. Για παράδειγμα, υπάρχει ένα Ακέραιος αριθμός τάξη που τυλίγει ένα int πληκτρολογήστε με ένα αντικείμενο. Μόνο οι αναφορές αντικειμένων και οι πρωτόγονοι τύποι μπορούν να βρίσκονται στη στοίβα Java ως τοπικές μεταβλητές. Τα αντικείμενα δεν μπορούν ποτέ να βρίσκονται στη στοίβα Java.

Ο αρχιτεκτονικός διαχωρισμός αντικειμένων και πρωτόγονων τύπων στο JVM αντικατοπτρίζεται στη γλώσσα προγραμματισμού Java, στην οποία τα αντικείμενα δεν μπορούν να δηλωθούν ως τοπικές μεταβλητές. Μόνο οι αναφορές αντικειμένων μπορούν να δηλωθούν ως τέτοιες. Κατά τη δήλωση, μια αναφορά αντικειμένου δεν αναφέρεται σε τίποτα. Μόνο αφού η αναφορά έχει αρχικοποιηθεί ρητά - είτε με αναφορά σε υπάρχον αντικείμενο είτε με κλήση προς νέος - αναφέρεται η αναφορά σε ένα πραγματικό αντικείμενο.

Στο σύνολο εντολών JVM, όλα τα αντικείμενα δημιουργούνται και έχουν πρόσβαση στο ίδιο σύνολο opcodes, εκτός από πίνακες. Στην Java, οι πίνακες είναι πλήρη αντικείμενα και, όπως κάθε άλλο αντικείμενο σε ένα πρόγραμμα Java, δημιουργούνται δυναμικά. Οι αναφορές συστοιχιών μπορούν να χρησιμοποιηθούν οπουδήποτε μια αναφορά στον τύπο Αντικείμενο ζητείται, και οποιαδήποτε μέθοδος Αντικείμενο μπορεί να κληθεί σε έναν πίνακα. Ωστόσο, στην εικονική μηχανή Java, οι πίνακες αντιμετωπίζονται με ειδικούς κωδικούς bytecodes.

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

Opcodes για αντικείμενα

Η δημιουργία νέων αντικειμένων πραγματοποιείται μέσω του

νέος

κώδικας πράξης. Δύο τελεστές ενός byte ακολουθούν το

νέος

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

Δημιουργία αντικειμένων
Κώδικας πράξηςOperand (ες)Περιγραφή
νέοςindexbyte1, indexbyte2δημιουργεί ένα νέο αντικείμενο στο σωρό, ωθεί την αναφορά

Ο επόμενος πίνακας δείχνει τους opcodes που τοποθετούν και λαμβάνουν πεδία αντικειμένων. Αυτά τα opcodes, putfield και getfield, λειτουργούν μόνο σε πεδία που είναι μεταβλητές παρουσίας. Οι στατικές μεταβλητές έχουν πρόσβαση από putstatic και getstatic, οι οποίες περιγράφονται αργότερα. Οι οδηγίες putfield και getfield παίρνουν το καθένα από δύο τελεστές ενός byte. Οι τελεστές συνδυάζονται για να σχηματίσουν έναν δείκτη 16-bit στη σταθερή ομάδα. Το σταθερό στοιχείο συγκέντρωσης σε αυτό το ευρετήριο περιέχει πληροφορίες σχετικά με τον τύπο, το μέγεθος και την μετατόπιση του πεδίου. Η αναφορά αντικειμένου λαμβάνεται από τη στοίβα τόσο στο putfield όσο και στο getfield οδηγίες. Η εντολή putfield παίρνει την τιμή μεταβλητής παρουσίας από τη στοίβα και η εντολή getfield ωθεί την ανακτήσιμη τιμή μεταβλητής παρουσίας στη στοίβα.

Πρόσβαση σε μεταβλητές παρουσίας
Κώδικας πράξηςOperand (ες)Περιγραφή
putfieldindexbyte1, indexbyte2καθορισμένο πεδίο, υποδεικνυόμενο από ευρετήριο, αντικειμένου προς τιμή (και τα δύο λαμβάνονται από στοίβα)
getfieldindexbyte1, indexbyte2ωθεί το πεδίο, που υποδεικνύεται από το ευρετήριο, του αντικειμένου (που λαμβάνεται από στοίβα)

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

Πρόσβαση σε μεταβλητές κλάσης
Κώδικας πράξηςOperand (ες)Περιγραφή
putstaticindexbyte1, indexbyte2καθορισμένο πεδίο, υποδεικνυόμενο από ευρετήριο, αντικειμένου προς τιμή (και τα δύο λαμβάνονται από στοίβα)
γευστικόςindexbyte1, indexbyte2ωθεί το πεδίο, υποδεικνυόμενο από ευρετήριο, αντικειμένου (που λαμβάνεται από στοίβα)

Οι ακόλουθοι κώδικες ελέγχου ελέγχουν αν η αναφορά αντικειμένου στην κορυφή της στοίβας αναφέρεται σε μια παρουσία της κλάσης ή της διεπαφής που ευρετηριάζεται από τους τελεστές που ακολουθούν τον κώδικα. Η εντολή checkcast ρίχνει CheckCastException εάν το αντικείμενο δεν είναι παρουσία της καθορισμένης κλάσης ή διεπαφής. Διαφορετικά, το checkcast δεν κάνει τίποτα. Η αναφορά αντικειμένου παραμένει στη στοίβα και η εκτέλεση συνεχίζεται στην επόμενη οδηγία. Αυτή η οδηγία διασφαλίζει ότι τα cast είναι ασφαλή στο χρόνο εκτέλεσης και αποτελούν μέρος της κουβέρτας ασφαλείας του JVM.

Η εντολή instanceof εμφανίζει την αναφορά αντικειμένου από την κορυφή της στοίβας και ωθεί το true ή false. Εάν το αντικείμενο είναι πράγματι μια παρουσία της καθορισμένης κλάσης ή διεπαφής, τότε το true ωθείται στη στοίβα, διαφορετικά, το false ωθείται στη στοίβα. Το στιγμιότυπο της εντολής χρησιμοποιείται για την εφαρμογή του παράδειγμα λέξη-κλειδί της Java, η οποία επιτρέπει στους προγραμματιστές να ελέγχουν εάν ένα αντικείμενο είναι μια παρουσία συγκεκριμένης κλάσης ή διεπαφής.

Τύπος ελέγχου
Κώδικας πράξηςOperand (ες)Περιγραφή
checkcastindexbyte1, indexbyte2Ρίχνει ClassCastException εάν το αντικείμενο δεν μπορεί να μεταφερθεί στην κλάση στο ευρετήριο
παράδειγμαindexbyte1, indexbyte2Πιέζει true αν το αντικείμενοref στη στοίβα είναι ένα στιγμιότυπο κλάσης στο ευρετήριο, αλλιώς πιέζει false

Opcodes για συστοιχίες

Η εγκατάσταση νέων συστοιχιών πραγματοποιείται μέσω των κωδικών newarray, anewarray και multianewarray. Ο κώδικας newarray χρησιμοποιείται για τη δημιουργία συστοιχιών πρωτόγονων τύπων εκτός από τις αναφορές αντικειμένων. Ο συγκεκριμένος πρωτόγονος τύπος καθορίζεται από έναν τελεστή ενός byte ακολουθώντας τον νέο κώδικα. Η εντολή newarray μπορεί να δημιουργήσει πίνακες για byte, short, char, int, long, float, double ή boolean.

Η εντολή Anewarray δημιουργεί μια σειρά από αναφορές αντικειμένων. Δύο τελεστές ενός byte ακολουθούν τον κώδικα opewarray και συνδυάζονται για να σχηματίσουν ένα ευρετήριο 16-bit στη σταθερή ομάδα. Μια περιγραφή της κλάσης του αντικειμένου για την οποία πρόκειται να δημιουργηθεί ο πίνακας βρίσκεται στη σταθερή ομάδα στο καθορισμένο ευρετήριο. Αυτή η οδηγία εκχωρεί χώρο για τον πίνακα αναφορών αντικειμένων και αρχικοποιεί τις αναφορές στο null.

Η εντολή multianewarray χρησιμοποιείται για την εκχώρηση πολυδιάστατων συστοιχιών - που είναι απλώς πίνακες συστοιχιών - και θα μπορούσε να εκχωρηθεί με επαναλαμβανόμενη χρήση των εντολών anewarray και newarray. Η εντολή πολλαπλών συστοιχιών απλώς συμπιέζει τους κωδικούς bytec που απαιτούνται για τη δημιουργία πολυδιάστατων συστοιχιών σε μία εντολή. Δύο τελεστές ενός byte ακολουθούν τον κώδικα πολλαπλών συστοιχιών και συνδυάζονται για να σχηματίσουν ένα ευρετήριο 16-bit στη σταθερή ομάδα. Μια περιγραφή της κλάσης του αντικειμένου για την οποία πρόκειται να δημιουργηθεί ο πίνακας βρίσκεται στη σταθερή ομάδα στο καθορισμένο ευρετήριο. Αμέσως μετά τους δύο τελεστές ενός byte που σχηματίζουν το σταθερό δείκτη συγκέντρωσης είναι ένας τελεστής ενός byte που καθορίζει τον αριθμό των διαστάσεων σε αυτόν τον πολυδιάστατο πίνακα. Τα μεγέθη για κάθε διάσταση εμφανίζονται από τη στοίβα. Αυτή η οδηγία εκχωρεί χώρο για όλες τις συστοιχίες που απαιτούνται για την εφαρμογή των πολυδιάστατων συστοιχιών.

Δημιουργία νέων συστοιχιών
Κώδικας πράξηςOperand (ες)Περιγραφή
newarrayένα είδοςεμφανίζεται το μήκος, εκχωρεί νέο πίνακα πρωτόγονων τύπων που υποδεικνύονται από το atype, ωθεί το αντικείμενο του νέου πίνακα
ξανάindexbyte1, indexbyte2εμφανίζεται το μήκος, εκχωρεί μια νέα σειρά αντικειμένων της κλάσης που υποδεικνύονται από indexbyte1 και indexbyte2, ωθεί το αντικείμενοref του νέου πίνακα
πολυπαρασκευήindexbyte1, indexbyte2, διαστάσειςεμφανίζεται διαστάσεις αριθμός μήκους πίνακα, εκχωρεί μια νέα πολυδιάστατη συστοιχία κλάσης που υποδεικνύεται από indexbyte1 και indexbyte2, ωθεί το αντικείμενο της νέας συστοιχίας

Ο επόμενος πίνακας δείχνει την εντολή που εμφανίζει μια αναφορά πίνακα από την κορυφή της στοίβας και ωθεί το μήκος αυτού του πίνακα.

Λήψη του μήκους του πίνακα
Κώδικας πράξηςOperand (ες)Περιγραφή
μήκος σειράς(κανένας)εμφανίζεται το αντικείμενοref ενός πίνακα, ωθεί το μήκος αυτού του πίνακα

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

Ανάκτηση στοιχείου πίνακα
Κώδικας πράξηςOperand (ες)Περιγραφή
φορτίο(κανένας)αναδύει ευρετήριο και arrayref ενός πίνακα byte, ωθεί το arrayref [index]
κατεβάσει(κανένας)αναδύει το ευρετήριο και το arrayref ενός πίνακα χαρακτήρων, ωθεί το arrayref [index]
φόρτωση(κανένας)αναδύει ευρετήριο και arrayref μιας σειράς σορτς, ωθεί το arrayref [index]
iaload(κανένας)αναδύει ευρετήριο και arrayref ενός πίνακα ints, ωθεί το arrayref [index]
φορτίο(κανένας)εμφανίζεται το ευρετήριο και το arrayref ενός πίνακα longs, ωθεί το arrayref [index]
φολάου(κανένας)αναδύει ευρετήριο και arrayref μιας σειράς πλωτών, ωθεί το arrayref [index]
χτυπήστε(κανένας)αναδύει ευρετήριο και arrayref μιας σειράς διπλών, ωθεί το arrayref [index]
aaload(κανένας)αναδύει ευρετήριο και arrayref ενός πίνακα αντικειμένων, ωθεί το arrayref [index]

Στον επόμενο πίνακα εμφανίζονται οι opcodes που αποθηκεύουν μια τιμή σε ένα στοιχείο πίνακα. Η τιμή, το ευρετήριο και ο πίνακας αναφέρονται από την κορυφή της στοίβας.

Αποθήκευση σε στοιχείο πίνακα
Κώδικας πράξηςOperand (ες)Περιγραφή
μπάστορ(κανένας)εμφανίζει τιμή, ευρετήριο και arrayref ενός πίνακα bytes, εκχωρεί arrayref [index] = τιμή
κάστορα(κανένας)εμφανίζει την τιμή, το ευρετήριο και το arrayref ενός πίνακα χαρακτήρων, εκχωρεί το arrayref [index] = τιμή
σάστορ(κανένας)εμφανίζει τιμή, ευρετήριο και arrayref ενός πίνακα σορτς, εκχωρεί arrayref [index] = τιμή
Iastore(κανένας)εμφανίζει τιμή, ευρετήριο και arrayref ενός πίνακα ints, εκχωρεί arrayref [index] = τιμή
πάσσορε(κανένας)εμφανίζει τιμή, ευρετήριο και arrayref ενός πίνακα longs, εκχωρεί arrayref [index] = τιμή
fastore(κανένας)εμφανίζει την τιμή, το ευρετήριο και το arrayref ενός πίνακα floats, εκχωρεί το arrayref [index] = τιμή
Ντάστορ(κανένας)εμφανίζει την τιμή, το ευρετήριο και το arrayref ενός πίνακα διπλών, εκχωρεί το arrayref [index] = τιμή
αιώριο(κανένας)εμφανίζει την τιμή, το ευρετήριο και το arrayref ενός πίνακα των αντικειμένων, ορίζει το arrayref [index] = τιμή

Τρισδιάστατος πίνακας: προσομοίωση εικονικής μηχανής Java

Η παρακάτω εφαρμογή δείχνει μια εικονική μηχανή Java που εκτελεί μια ακολουθία bytecodes. Η ακολουθία bytecode στην προσομοίωση δημιουργήθηκε από το javac για το initAnArray () μέθοδος της τάξης που φαίνεται παρακάτω:

class ArrayDemo {static void initAnArray () {int [] [] [] threeD = νέο int [5] [4] [3]; για (int i = 0; i <5; ++ i) {για (int j = 0; j <4; ++ j) {για (int k = 0; k <3; ++ k) {threeD [ i] [j] [k] = i + j + k; }}}}} 

Οι κωδικοί bytes που δημιουργούνται από javac Για initAnArray () παρουσιάζονται παρακάτω: