Το Java 5 έφερε γενικά στη γλώσσα Java. Σε αυτό το άρθρο, σας παρουσιάζω γενόσημους και συζητάμε γενικούς τύπους, γενικές μεθόδους, γενικά και συμπεράσματα, γενικές αντιπαραθέσεις και γενικά και σωρούς ρύπανση.
λήψη Λήψη του κώδικα Λήψη του πηγαίου κώδικα για παραδείγματα σε αυτό το πρόγραμμα εκμάθησης Java 101. Δημιουργήθηκε από τον Jeff Friesen για το JavaWorld.Τι είναι τα γενόσημα;
Generics είναι μια συλλογή σχετικών γλωσσικών χαρακτηριστικών που επιτρέπουν σε τύπους ή μεθόδους να λειτουργούν σε αντικείμενα διαφόρων τύπων παρέχοντας ταυτόχρονα ασφάλεια τύπου μεταγλώττισης. Οι λειτουργίες Generics αντιμετωπίζουν το πρόβλημα του java.lang.ClassCastException
ρίχνονται κατά το χρόνο εκτέλεσης, που είναι το αποτέλεσμα ενός κώδικα που δεν είναι ασφαλής τύπου (δηλαδή, η μεταφορά αντικειμένων από τους τρέχοντες τύπους τους σε ασύμβατους τύπους).
Generics και το Java Συλλογές Πλαίσιο
Τα γενικά χρησιμοποιούνται ευρέως στο Java Συλλογές Πλαίσιο (επίσημα εισάγονται στο μέλλον Java 101 άρθρα), αλλά δεν είναι αποκλειστικά σε αυτό. Τα γενικά χρησιμοποιούνται επίσης σε άλλα μέρη της τυπικής βιβλιοθήκης κατηγορίας της Java, όπως java.lang.Class
, java.lang. Συγκρίσιμο
, java.lang.ThreadLocal
, και java.lang.ref.WeakReference
.
Εξετάστε το ακόλουθο τμήμα κώδικα, το οποίο καταδεικνύει την έλλειψη ασφάλειας τύπου (στο πλαίσιο του Java Συλλογές Πλαισίου java.util.LinkedList
class) που ήταν κοινό στον κώδικα Java πριν από την εισαγωγή γενικών:
Λίστα doubleList = new LinkedList (); doubleList.add (νέο Double (3.5)); Double d = (Double) doubleList.iterator (). Επόμενο ();
Αν και ο στόχος του παραπάνω προγράμματος είναι μόνο η αποθήκευση java.lang. Διπλό
αντικείμενα στη λίστα, τίποτα δεν εμποδίζει την αποθήκευση άλλων ειδών. Για παράδειγμα, μπορείτε να καθορίσετε doubleList.add ("Γεια");
για να προσθέσετε ένα java.lang.String
αντικείμενο. Ωστόσο, κατά την αποθήκευση ενός άλλου είδους αντικειμένου, η τελική γραμμή είναι (Διπλό)
αιτίες χειριστή cast ClassCastException
να πεταχτούν όταν έρχονται αντιμέτωποι με μηΔιπλό
αντικείμενο.
Επειδή αυτή η έλλειψη ασφάλειας τύπου δεν εντοπίζεται μέχρι το χρόνο εκτέλεσης, ένας προγραμματιστής ενδέχεται να μην γνωρίζει το πρόβλημα, αφήνοντάς τον στον πελάτη (αντί του μεταγλωττιστή) να το ανακαλύψει. Το Generics βοηθά τον μεταγλωττιστή να ειδοποιεί τον προγραμματιστή για το πρόβλημα της αποθήκευσης ενός αντικειμένου με μηΔιπλό
πληκτρολογήστε τη λίστα επιτρέποντας στον προγραμματιστή να επισημάνει τη λίστα ως μόνο Διπλό
αντικείμενα. Αυτή η βοήθεια παρουσιάζεται παρακάτω:
Λίστα doubleList = new LinkedList (); doubleList.add (νέο Double (3.5)); Double d = doubleList.iterator (). Επόμενο ();
Λίστα
τώρα διαβάζει «Λίστα
του Διπλό
.” Λίστα
είναι μια γενική διεπαφή, που εκφράζεται ως Λίστα
, χρειάζεται ένα Διπλό
τύπος ορίσματος, το οποίο καθορίζεται επίσης κατά τη δημιουργία του πραγματικού αντικειμένου. Ο μεταγλωττιστής μπορεί τώρα να επιβάλει την ορθότητα του τύπου κατά την προσθήκη ενός αντικειμένου στη λίστα - για παράδειγμα, η λίστα θα μπορούσε να αποθηκευτεί Διπλό
μόνο τιμές. Αυτή η επιβολή καταργεί την ανάγκη για το (Διπλό)
εκμαγείο.
Ανακαλύπτοντας γενικούς τύπους
ΕΝΑ γενικός τύπος είναι μια κλάση ή διεπαφή που εισάγει ένα σύνολο παραμετροποιημένων τύπων μέσω a λίστα παραμέτρων τυπικού τύπου, η οποία είναι μια λίστα διαχωρισμένων με κόμμα ονομάτων παραμέτρων τύπου μεταξύ ενός ζεύγους αγκύλων. Οι γενικοί τύποι συμμορφώνονται με την ακόλουθη σύνταξη:
τάξη αναγνωριστικό<formalTypeParameterList> διεπαφή {// class body} αναγνωριστικό<formalTypeParameterList> {// σώμα διεπαφής}
Το Java Συλλογές Πλαίσιο προσφέρει πολλά παραδείγματα γενικών τύπων και τις λίστες παραμέτρων τους (και τα αναφέρομαι σε αυτό το άρθρο). Για παράδειγμα, java.util.Set
είναι ένας γενικός τύπος, είναι ο επίσημος κατάλογος παραμέτρων τύπου, και
μι
είναι η μοναδική παράμετρος τύπου της λίστας. Ένα άλλο παράδειγμα είναιjava.util.Map
.
Σύμβαση ονομασίας παραμέτρων τύπου Java
Η σύμβαση προγραμματισμού Java υπαγορεύει ότι τα ονόματα παραμέτρων τύπου είναι με κεφαλαία γράμματα, όπως ΕΝΑ παράμετρος τύπου είναι μια παρουσία γενικού τύπου όπου οι παράμετροι τύπου γενικού τύπου αντικαθίστανται με πραγματικά επιχειρήματα τύπου (πληκτρολογήστε ονόματα). Για παράδειγμα, Η γλώσσα Java υποστηρίζει τα ακόλουθα είδη ορισμάτων πραγματικού τύπου: Κάθε γενικός τύπος υπονοεί την ύπαρξη ενός ακατέργαστος τύπος, ο οποίος είναι γενικός τύπος χωρίς λίστα παραμέτρων τυπικού τύπου. Για παράδειγμα, Η δήλωση ενός γενικού τύπου περιλαμβάνει τον καθορισμό μιας τυπικής λίστας παραμέτρων τύπου και την πρόσβαση σε αυτές τις παραμέτρους τύπου καθ 'όλη την εφαρμογή της. Η χρήση του γενικού τύπου συνεπάγεται τη μετάδοση πραγματικών ορισμάτων τύπου στις παραμέτρους τύπων κατά την παρουσίαση του γενικού τύπου. Βλέπε καταχώριση 1. Η Λίστα 1 δείχνει γενική δήλωση τύπου και χρήση στο πλαίσιο ενός απλού τύπου κοντέινερ που αποθηκεύει αντικείμενα του κατάλληλου τύπου ορίσματος. Για να διατηρήσω τον κώδικα απλό, έχω παραλείψει τον έλεγχο σφαλμάτων. ο ο Μεταγλώττιση καταχώρισης 1 ( Σημειώστε, ωστόσο, ότι δεν υπάρχει τρόπος παραβίασης της ασφάλειας τύπου σε αυτό το παράδειγμα. Απλώς δεν είναι δυνατόν να αποθηκεύσετε ένα μη Εκτέλεση ο Μερικές φορές θέλετε να περιορίσετε τους τύπους των πραγματικών ορισμάτων τύπου που μπορούν να μεταβιβαστούν σε μια παράμετρο τύπου. Για παράδειγμα, ίσως θέλετε να περιορίσετε μια παράμετρο τύπου να δέχεται μόνο Μπορείτε να περιορίσετε μια παράμετρο τύπου καθορίζοντας ένα άνω όριο, που είναι ένας τύπος που χρησιμεύει ως το ανώτερο όριο για τους τύπους που μπορούν να περάσουν ως ορίσματα πραγματικού τύπου. Καθορίστε το άνω όριο χρησιμοποιώντας την δεσμευμένη λέξη Για παράδειγμα, Μπορείτε να αντιστοιχίσετε περισσότερα από ένα άνω όρια σε μια παράμετρο τύπου. Ωστόσο, το πρώτο όριο πρέπει πάντα να είναι μια κλάση και τα πρόσθετα όρια πρέπει πάντα να είναι διασυνδέσεις. Κάθε όριο χωρίζεται από τον προκάτοχό του με ένα συμπλεκτικό σύμβολο ( Λίστα 2 ο ο Συλλογή καταχώρισης 2 ( Δεν μπορείτε να καθορίσετε ένα κατώτατο όριο για μια παράμετρο γενικού τύπου. Για να καταλάβω γιατί προτείνω να διαβάσετε τις Συχνές Ερωτήσεις της Java της Angelika Langer σχετικά με το θέμα των χαμηλότερων ορίων, την οποία λέει "θα ήταν συγκεχυμένη και όχι ιδιαίτερα χρήσιμη". Ας υποθέσουμε ότι θέλετε να εκτυπώσετε μια λίστα αντικειμένων, ανεξάρτητα από το αν αυτά τα αντικείμενα είναι χορδές, υπάλληλοι, σχήματα ή κάποιο άλλο τύπο. Η πρώτη σας προσπάθεια μπορεί να μοιάζει με αυτήν που εμφανίζεται στην καταχώριση 3. Φαίνεται λογικό ότι μια λίστα συμβολοσειρών ή μια λίστα ακεραίων είναι ένας υποτύπος μιας λίστας αντικειμένων, ωστόσο ο μεταγλωττιστής παραπονιέται όταν προσπαθείτε να συντάξετε αυτήν την καταχώριση. Συγκεκριμένα, σας λέει ότι μια λίστα-συμβολοσειρά δεν μπορεί να μετατραπεί σε λίστα-αντικειμένου και παρόμοια για μια λίστα-ακέραιου. Το μήνυμα σφάλματος που λάβατε σχετίζεται με τον θεμελιώδη κανόνα των γενικών:μι
για στοιχείο, κ
για κλειδί, Β
για τιμή, και Τ
για τον τύπο. Εάν είναι δυνατόν, αποφύγετε τη χρήση ενός χωρίς νόημα ονόματος Π
— java.util. Λίστα
σημαίνει μια λίστα στοιχείων, αλλά τι θα μπορούσατε να εννοείτε Λίστα
Σειρά
είναι ένας παράμετρος τύπου όπου Σειρά
είναι το πραγματικό όρισμα τύπου που αντικαθιστά την παράμετρο τύπου μι
.Λίστα
, Ζώο
μεταβιβάζεται στο μι
.Σειρά
, Λίστα
μεταβιβάζεται στο μι
.Χάρτης
, Σειρά
μεταβιβάζεται στο κ
και Σειρά[]
μεταβιβάζεται στο Β
.class Container {Ορισμός στοιχείων; }
, μι
μεταβιβάζεται στο μι
.?
) μεταφέρεται στην παράμετρο τύπου. Για παράδειγμα, στο Τάξη
, ?
μεταβιβάζεται στο Τ
.Τάξη
είναι ο πρώτος τύπος για Τάξη
. Σε αντίθεση με τους γενικούς τύπους, οι πρώτοι τύποι μπορούν να χρησιμοποιηθούν με οποιοδήποτε είδος αντικειμένου.Δήλωση και χρήση γενικών τύπων στην Java
Λίστα 1:
GenDemo.java
(έκδοση 1)class Container {private E [] στοιχεία; ιδιωτικός δείκτης int Κοντέινερ (μέγεθος int) {element = (E []) νέο αντικείμενο [μέγεθος]; ευρετήριο = 0; } άκυρη προσθήκη (στοιχείο E) {στοιχεία [index ++] = element; } E get (int index) {στοιχεία επιστροφής [index]; } int μέγεθος () {index index; }} δημόσια κλάση GenDemo {public static void main (String [] args) {Container con = new Container (5); con.add ("Βόρεια"); con.add ("Νότια"); con.add ("Ανατολή"); con.add ("Δύση"); για (int i = 0; i <con.size (); i ++) System.out.println (con.get (i)); }}
Δοχείο
κλάση δηλώνεται ότι είναι ένας γενικός τύπος καθορίζοντας το λίστα παραμέτρων τυπικού τύπου. Τύπος παραμέτρου
μι
χρησιμοποιείται για την αναγνώριση του τύπου των αποθηκευμένων στοιχείων, του στοιχείου που θα προστεθεί στον εσωτερικό πίνακα και του τύπου επιστροφής κατά την ανάκτηση ενός στοιχείου.Δοχείο (μέγεθος int)
ο κατασκευαστής δημιουργεί τον πίνακα μέσω στοιχεία = (E []) νέο αντικείμενο [μέγεθος];
. Αν αναρωτιέστε γιατί δεν το έκανα στοιχεία = νέο E [μέγεθος];
, ο λόγος είναι ότι δεν είναι δυνατόν. Κάτι τέτοιο θα μπορούσε να οδηγήσει σε α ClassCastException
.javac GenDemo.java
). ο (ΜΙ[])
Το cast κάνει τον μεταγλωττιστή να εμφανίσει μια προειδοποίηση σχετικά με το ότι το cast δεν είναι επιλεγμένο. Επισημαίνει την πιθανότητα απόκλισης από Αντικείμενο[]
προς την ΜΙ[]
μπορεί να παραβιάζει την ασφάλεια τύπου επειδή Αντικείμενο[]
μπορεί να αποθηκεύσει οποιοδήποτε είδος αντικειμένου.μι
αντικείμενο στον εσωτερικό πίνακα. Πρόθεμα του Δοχείο (μέγεθος int)
κατασκευαστής με @SuppressWarnings ("μη επιλεγμένο")
θα καταστείλει αυτό το προειδοποιητικό μήνυμα.java GenDemo
για να εκτελέσετε αυτήν την εφαρμογή. Πρέπει να παρατηρήσετε την ακόλουθη έξοδο:Βορράς Νότος Ανατολή Δύση
Οριακές παράμετροι τύπου στην Java
μι
σε Σειρά
είναι ένα παράδειγμα ενός μη περιορισμένη παράμετρος τύπου επειδή μπορείτε να μεταβιβάσετε οποιοδήποτε πραγματικό όρισμα τύπου μι
. Για παράδειγμα, μπορείτε να καθορίσετε Σειρά
, Σειρά
, ή Σειρά
.Υπάλληλος
και τις υποκατηγορίες του.εκτείνεται
ακολουθούμενο από το όνομα τύπου του άνω ορίου.Εργαζόμενοι στην τάξη
περιορίζει τους τύπους στους οποίους μπορεί να περάσει Υπαλλήλους
προς την Υπάλληλος
ή μια υποκατηγορία (π.χ. Λογιστής
). Καθορισμός νέοι υπάλληλοι
θα ήταν νόμιμο, ενώ νέοι υπάλληλοι
θα ήταν παράνομο.&
). Δείτε την καταχώριση 2.Λίστα 2:
GenDemo.java
(έκδοση 2)εισαγωγή java.math.BigDecimal; εισαγωγή java.util.Arrays; αφηρημένη τάξη Υπάλληλος {ιδιωτικό BigDecimal hourlySalary; ιδιωτικό όνομα συμβολοσειράς; Υπάλληλος (Όνομα συμβολοσειράς, BigDecimal hourlySalary) {this.name = name; this.hourlySalary = hourlySalary; } δημόσια BigDecimal getHourlySalary () {return hourlySalary; } δημόσια συμβολοσειρά getName () {return name; } δημόσια συμβολοσειρά toString () {return name + ":" + hourlySalary.toString (); }} class Accountant επεκτείνει υπαλλήλους υπαλλήλων συγκρίσιμα {Accountant (String name, BigDecimal hourlySalary) {super (name, hourlySalary) } public int membandingkanTo (Λογιστικός λογαριασμός) {return getHourlySalary (). membandingkanTo (acct.getHourlySalary ()); }} ταξινόμηση υπαλλήλων κατηγορίας
Υπάλληλος
Η τάξη αφαιρεί την έννοια ενός υπαλλήλου που λαμβάνει ωριαίο μισθό. Αυτή η τάξη υποκατηγορείται από Λογιστής
, το οποίο εφαρμόζει επίσης Συγκρίσιμος
να το δείξω αυτό Λογιστής
Το s μπορεί να συγκριθεί σύμφωνα με τη φυσική τους σειρά, η οποία συμβαίνει να είναι ωριαία αμοιβή σε αυτό το παράδειγμα.java.lang. Συγκρίσιμο
διεπαφή δηλώνεται ως γενικός τύπος με την ονομασία μιας παραμέτρου ενός τύπου Τ
. Αυτή η διεπαφή παρέχει ένα int membandingkanTo (T o)
μέθοδος που συγκρίνει το τρέχον αντικείμενο με το όρισμα (του τύπου Τ
), επιστρέφοντας αρνητικό ακέραιο, μηδέν ή θετικό ακέραιο, καθώς αυτό το αντικείμενο είναι μικρότερο από, ίσο ή μεγαλύτερο από το καθορισμένο αντικείμενο.Ταξινομημένοι υπάλληλοι
τάξη σας επιτρέπει να αποθηκεύσετε Υπάλληλος
υποκατηγορίες παρουσίες που εφαρμόζονται Συγκρίσιμος
σε έναν εσωτερικό πίνακα. Αυτός ο πίνακας ταξινομείται (μέσω του java.util.Arays
της τάξης κενή ταξινόμηση (Object [] a, int fromIndex, int toIndex)
μέθοδος τάξης) σε αύξουσα σειρά του ωριαίου μισθού μετά από Υπάλληλος
Προστίθεται η υποκατηγορία.javac GenDemo.java
) και εκτελέστε την εφαρμογή (java GenDemo
). Πρέπει να παρατηρήσετε την ακόλουθη έξοδο:Τζορτζ Σμιθ: 15,20 Τζέιν Τζόουνς: 25,60 Τζον Ντο: 35,40
Χαμηλότερα όρια και παράμετροι γενικού τύπου
Λαμβάνοντας υπόψη μπαλαντέρ
Λίστα 3:
GenDemo.java
(έκδοση 3)εισαγωγή java.util.ArrayList; εισαγωγή java.util.Iterator; εισαγωγή java.util.List; δημόσια τάξη GenDemo {public static void main (String [] args) {List direction = new ArrayList (); direction.add ("βόρεια"); direction.add ("νότος"); direction.add ("ανατολικά"); direction.add ("δυτικά"); printList (οδηγίες); Βαθμοί λίστας = νέο ArrayList (); grades.add (νέος ακέραιος (98)); grades.add (νέος ακέραιος (63)); grades.add (νέος ακέραιος (87)); printList (βαθμοί); } static void printList (Λίστα λιστών) {Iterator iter = list.iterator (); ενώ (iter.hasNext ()) System.out.println (iter.next ()); }}