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

Πολυμορφισμός και κληρονομιά στην Ιάβα

Σύμφωνα με τον μύθο Venkat Subramaniam, ο πολυμορφισμός είναι η πιο σημαντική έννοια στον αντικειμενοστρεφή προγραμματισμό. Πολυμορφισμός--ή η ικανότητα ενός αντικειμένου να εκτελεί εξειδικευμένες ενέργειες με βάση τον τύπο του - είναι αυτό που κάνει τον κώδικα Java ευέλικτο. Σχεδιαστικά μοτίβα όπως Command, Observer, Decorator, Strategy και πολλά άλλα που δημιουργήθηκαν από το Gang Of Four, όλα χρησιμοποιούν κάποια μορφή πολυμορφισμού. Η γνώση αυτής της ιδέας βελτιώνει σημαντικά την ικανότητά σας να σκέφτεστε λύσεις για προκλήσεις προγραμματισμού

Λάβετε τον κωδικό

Μπορείτε να λάβετε τον πηγαίο κώδικα για αυτήν την πρόκληση και να εκτελέσετε τις δικές σας δοκιμές εδώ: //github.com/rafadelnero/javaworld-challengers

Διεπαφές και κληρονομιά στον πολυμορφισμό

Με αυτό το Java Challenger, εστιάζουμε στη σχέση μεταξύ πολυμορφισμού και κληρονομιάς. Το κύριο πράγμα που πρέπει να θυμάστε είναι ότι απαιτείται πολυμορφισμός εφαρμογή κληρονομιάς ή διεπαφής. Μπορείτε να το δείτε στο παρακάτω παράδειγμα, με τους Duke και Juggy:

 δημόσια αφηρημένη τάξη JavaMascot {public abstract void executeAction (); } η δημόσια τάξη Duke επεκτείνει το JavaMascot {@Override public void executeAction () {System.out.println ("Punch!"); }} Η δημόσια τάξη Juggy επεκτείνει το JavaMascot {@Override public void executeAction () {System.out.println ("Fly!"); }} δημόσια τάξη JavaMascotTest {public static void main (String ... args) {JavaMascot dukeMascot = νέο Duke (); JavaMascot juggyMascot = νέο Juggy (); dukeMascot.executeAction (); juggyMascot.executeAction (); }} 

Η έξοδος από αυτόν τον κωδικό θα είναι:

 Γροθιά! Πετώ! 

Λόγω των συγκεκριμένων εφαρμογών τους, και τα δύο Δούκας και JuggyΟι ενέργειες θα εκτελεστούν.

Είναι η μέθοδος υπερφόρτωσης του πολυμορφισμού;

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

Ποιος είναι ο σκοπός του πολυμορφισμού;

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

Για να κατανοήσετε καλύτερα τον σκοπό του πολυμορφισμού, ρίξτε μια ματιά στο SweetCreator:

 δημόσια αφηρημένη τάξη SweetProducer {public abstract void productsSweet (); } το δημόσιο μάθημα CakeProducer επεκτείνει το SweetProducer {@Override public void menghasilkanSweet () {System.out.println ("Cake made"); }} Η δημόσια τάξη ChocolateProducer επεκτείνει το SweetProducer {@Override public voidprodesweet () {System.out.println ("Chocolate dihasilkan"); }} Το δημόσιο μάθημα CookieProducer επεκτείνει το SweetProducer {@Override public void menghasilkanSweet () {System.out.println ("Cookie made"); }} δημόσια τάξη SweetCreator {private List sweetProducer; Δημόσιο SweetCreator (Λίστα sweetProducer) {this.sweetProducer = sweetProducer; } public void createSweets () {sweetProducer.forEach (sweet -> sweet.produceSweet ()); }} δημόσια τάξη SweetCreatorTest {public static void main (String ... args) {SweetCreator sweetCreator = new SweetCreator (Arrays.asList (new CakeProducer (), new ChocolateProducer (), new CookieProducer ())); sweetCreator.createSweets (); }} 

Σε αυτό το παράδειγμα, μπορείτε να δείτε ότι το SweetCreator η τάξη γνωρίζει μόνο το  SweetProducer τάξη. Δεν γνωρίζει την εφαρμογή του καθενός Γλυκός. Αυτός ο διαχωρισμός μας δίνει ευελιξία για ενημέρωση και επαναχρησιμοποίηση των τάξεων μας και καθιστά τον κώδικα πολύ πιο εύκολο να διατηρηθεί. Κατά το σχεδιασμό του κωδικού σας, αναζητήστε πάντα τρόπους για να τον κάνετε όσο το δυνατόν πιο ευέλικτο και διατηρήσιμο. Ο πολυμορφισμός είναι μια πολύ ισχυρή τεχνική για χρήση για αυτούς τους σκοπούς.

Υπόδειξη: Ο @Καταπατώ Ο σχολιασμός υποχρεώνει τον προγραμματιστή να χρησιμοποιεί την ίδια υπογραφή μεθόδου που πρέπει να παρακαμφθεί. Εάν η μέθοδος δεν παρακαμφθεί, θα υπάρξει σφάλμα συλλογής.

Συνδυαστικοί τύποι επιστροφής στην παράκαμψη μεθόδου

Είναι δυνατόν να αλλάξετε τον τύπο επιστροφής μιας μεθόδου που παρακάμπτεται εάν είναι συνδιαλλακτικός τύπος. ΕΝΑ συνδυαστικός τύπος είναι βασικά μια υποκατηγορία του τύπου επιστροφής. Εξετάστε ένα παράδειγμα:

 δημόσια αφηρημένη τάξη JavaMascot {abstract JavaMascot getMascot (); } η δημόσια τάξη Duke επεκτείνει το JavaMascot {@Override Duke getMascot () {return new Duke (); }} 

Επειδή Δούκας είναι ένα JavaMascot, μπορούμε να αλλάξουμε τον τύπο επιστροφής κατά την παράκαμψη.

Πολυμορφισμός με τις βασικές τάξεις Java

Χρησιμοποιούμε τον πολυμορφισμό όλη την ώρα στις βασικές τάξεις Java. Ένα πολύ απλό παράδειγμα είναι όταν δημιουργούμε το Λίστα Array τάξη που δηλώνει τοΛίστα διεπαφή ως τύπος:

 Λίστα λιστών = νέο ArrayList (); 

Για να προχωρήσετε περαιτέρω, εξετάστε αυτό το δείγμα κώδικα χρησιμοποιώντας το Java Συλλογές API χωρίς πολυμορφισμός:

 public class ListActionWithoutPolymorphism {// Παράδειγμα χωρίς πολυμορφισμό void executeVectorActions (Vector vector) {/ * Επανάληψη κώδικα εδώ * /} void executeArrayListActions (ArrayList arrayList) {/ * Επανάληψη κώδικα εδώ * /} void executeLinkedListActions (LinkedList LinkedListition) εδώ * /} void executeCopyOnWriteArrayListActions (CopyOnWriteArrayList copyOnWriteArrayList) {/ * Επανάληψη κώδικα εδώ * /}} δημόσια τάξη ListActionInvokerWithoutPolymorphism {listAction.executeVectorActions (νέο Vector ()); listAction.executeArrayListActions (νέο ArrayList ()); listAction.executeLinkedListActions (νέο LinkedList ()); listAction.executeCopyOnWriteArrayListActions (νέο CopyOnWriteArrayList ()); } 

Άσχημος κώδικας, έτσι δεν είναι; Φανταστείτε να προσπαθείτε να το διατηρήσετε! Τώρα κοιτάξτε το ίδιο παράδειγμα με πολυμορφισμός:

 public static void main (String… πολυμορφισμός) {ListAction listAction = new ListAction (); listAction.executeListActions (); } δημόσια τάξη ListAction {void executeListActions (Λίστα λίστας) {// Εκτελέστε ενέργειες με διαφορετικές λίστες}} δημόσια τάξη ListActionInvoker {public static void main (String ... masterPolymorphism) {ListAction listAction = new ListAction (); listAction.executeListActions (νέο διάνυσμα ()); listAction.executeListActions (νέο ArrayList ()); listAction.executeListActions (νέο LinkedList ()); listAction.executeListActions (νέο CopyOnWriteArrayList ()); }} 

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

Επίκληση συγκεκριμένων μεθόδων σε μια κλήση πολυμορφικής μεθόδου

Είναι δυνατόν να επικαλεστούν συγκεκριμένες μεθόδους σε μια πολυμορφική κλήση, αλλά το να επιφέρει κόστος ευελιξίας. Ακολουθεί ένα παράδειγμα:

 δημόσια αφηρημένη κλάση MetalGearCharacter {abstract void useWeapon (String όπλο); } η δημόσια τάξη BigBoss επεκτείνει το MetalGearCharacter {@Override void useWeapon (String όπλο) {System.out.println ("Το Big Boss χρησιμοποιεί ένα όπλο" +); } άκυρο giveOrderToTheArmy (String orderMessage) {System.out.println (orderMessage); }} Η δημόσια τάξη SolidSnake επεκτείνει το MetalGearCharacter {void useWeapon (String όπλο) {System.out.println ("Το Solid Snake χρησιμοποιεί ένα όπλο" +). }} δημόσια τάξη UseSpecificMethod {public static void executeActionWith (MetalGearCharacter metalGearCharacter) {metalGearCharacter.useWeapon ("SOCOM"); // Η παρακάτω γραμμή δεν θα λειτουργούσε // metalGearCharacter.giveOrderToTheArmy ("Attack!"); if (metalGearCharacter instanceof BigBoss) {((BigBoss) metalGearCharacter) .giveOrderToTheArmy ("Επίθεση!"); }} δημόσιος στατικός κενός κενός (String ... specificPolymorphismInvocation) {executeActionWith (νέο SolidSnake ()); executeActionWith (νέο BigBoss ()); }} 

Η τεχνική που χρησιμοποιούμε εδώ είναι χύσιμο, ή σκόπιμα να αλλάξετε τον τύπο αντικειμένου κατά το χρόνο εκτέλεσης.

Λάβετε υπόψη ότι είναι δυνατό να επικαλεστεί μια συγκεκριμένη μέθοδο μόνο κατά τη μετάδοση του γενικού τύπου στον συγκεκριμένο τύπο. Μια καλή αναλογία θα έλεγε ρητά στον μεταγλωττιστή, "Γεια, ξέρω τι κάνω εδώ, οπότε πρόκειται να μεταφέρω το αντικείμενο σε έναν συγκεκριμένο τύπο και να χρησιμοποιήσω μια συγκεκριμένη μέθοδο."

Αναφερόμενος στο παραπάνω παράδειγμα, υπάρχει ένας σημαντικός λόγος που ο μεταγλωττιστής αρνείται να δεχτεί επίκληση συγκεκριμένης μεθόδου: η κλάση που περνά θα μπορούσε να είναι SolidSnake. Σε αυτήν την περίπτωση, δεν υπάρχει τρόπος για τον μεταγλωττιστή να διασφαλίσει κάθε υποκατηγορία του MetalGearCharacter έχει το giveOrderToTheArmy δηλωθεί η μέθοδος.

ο παράδειγμα δεσμευμένη λέξη-κλειδί

Δώστε προσοχή στην αποκλειστική λέξη παράδειγμα. Πριν επικαλεστούμε τη συγκεκριμένη μέθοδο, ρωτήσαμε εάν MetalGearCharacter είναι "παράδειγμαΜεγάλο αφεντικό. Αν αυτο δεν ήταν ένα Μεγάλο αφεντικό για παράδειγμα, θα λάβουμε το ακόλουθο μήνυμα εξαίρεσης:

 Εξαίρεση στο νήμα "main" java.lang.ClassCastException: com.javaworld.javachallengers.polymorphism.specificinvocation.SolidSnake δεν μπορεί να μεταφερθεί στο com.javaworld.javachallengers.polymorphism.specificinvocation.BigBoss 

ο σούπερ δεσμευμένη λέξη-κλειδί

Τι γίνεται αν θέλουμε να αναφέρουμε ένα χαρακτηριστικό ή μια μέθοδο από ένα superclass Java; Σε αυτήν την περίπτωση θα μπορούσαμε να χρησιμοποιήσουμε το σούπερ δεσμευμένη λέξη. Για παράδειγμα:

 δημόσια τάξη JavaMascot {void executeAction () {System.out.println ("Το Java Mascot πρόκειται να εκτελέσει μια ενέργεια!"); }} η δημόσια τάξη Duke επεκτείνει το JavaMascot {@Override void executeAction () {super.executeAction (); System.out.println ("Ο Duke πρόκειται να τρυπήσει!"); } δημόσιος στατικός κενός κενός (String ... superReserveWord) {new Duke (). executeAction (); }} 

Χρήση της δεσμευμένης λέξης σούπερ σε Δούκας'μικρό executeAction Η μέθοδος επικαλείται τη μέθοδο superclass. Στη συνέχεια εκτελούμε τη συγκεκριμένη ενέργεια από Δούκας. Γι 'αυτό μπορούμε να δούμε και τα δύο μηνύματα στην έξοδο παρακάτω:

 Το Java Mascot πρόκειται να εκτελέσει μια ενέργεια! Ο Δούκας θα τρυπήσει! 

Πάρτε την πρόκληση του πολυμορφισμού!

Ας δοκιμάσουμε τι έχετε μάθει για τον πολυμορφισμό και την κληρονομιά. Σε αυτήν την πρόκληση, σας δίνεται μια χούφτα μεθόδων από το The Simpsons του Matt Groening και η πρόκλησή σας είναι να συμπεράνετε ποιο θα είναι το αποτέλεσμα για κάθε τάξη. Για να ξεκινήσετε, αναλύστε προσεκτικά τον ακόλουθο κώδικα:

 δημόσια τάξη PolymorphismChallenge {static abstract class Simpson {void talk () {System.out.println ("Simpson!"); } προστατευμένη άκυρη φάρσα (String prank) {System.out.println (φάρσα); }} η στατική τάξη Bart επεκτείνει τον Simpson {String prank; Bart (String prank) {this.prank = φάρσα; } προστατευμένη άκυρη ομιλία () {System.out.println ("Φάτε τα σορτς μου!"); } προστατευμένη άκυρη φάρσα () {super.prank (φάρσα); System.out.println ("Knock Homer down"); }} η στατική τάξη Lisa επεκτείνει τον Simpson {void talk (String toMe) {System.out.println ("I love Sax!"); }} Δημόσιο στατικό κενό (String ... doYourBest) {new Lisa (). talk ("Sax :)"); Simpson simpson = νέο Bart ("D'oh"); simpson.talk (); Λίζα Λίζα = νέα Λίζα (); lisa.talk (); ((Bart) simpson). Φάρσα (); }} 

Τι νομίζετε; Ποια θα είναι η τελική παραγωγή; Μην χρησιμοποιείτε IDE για να το καταλάβετε! Το θέμα είναι να βελτιώσετε τις δεξιότητες ανάλυσης κώδικα, οπότε προσπαθήστε να προσδιορίσετε το αποτέλεσμα για τον εαυτό σας.

Επιλέξτε την απάντησή σας και θα μπορείτε να βρείτε τη σωστή απάντηση παρακάτω.

 Α) Μου αρέσει ο Sax! Ντο Σίμπσον! D'oh B) Sax :) Φάτε τα σορτς μου! Λατρεύω τον Sax! D'oh Knock Homer down C) Sax :) D'oh Simpson! Knock Homer down D) Μου αρέσει ο Sax! Φάτε τα σορτς μου! Σίμπσον! D'oh Knock Homer κάτω 

Τι συνέβη μόλις τώρα? Κατανόηση του πολυμορφισμού

Για την ακόλουθη επίκληση μεθόδου:

 νέα Lisa (). talk ("Sax :)"); 

η έξοδος θα είναι «Λατρεύω τον Sax!Αυτό συμβαίνει επειδή περνάμε ένα Σειρά στη μέθοδο και Λίζα έχει τη μέθοδο.

Για την επόμενη επίκληση:

 Simpson simpson = νέο Bart ("D'oh");

simpson.talk ();

Η έξοδος θα είναι "Φάτε τα σορτς μου!Αυτό συμβαίνει επειδή δημιουργούμε το Σίμπσον πληκτρολογήστε με Μπαρτ.

Τώρα ελέγξτε αυτό, το οποίο είναι λίγο πιο δύσκολο:

 Lisa lisa = νέα Lisa (); lisa.talk (); 

Εδώ, χρησιμοποιούμε μέθοδο υπερφόρτωσης με κληρονομιά. Δεν μεταφέρουμε τίποτα στη μέθοδο ομιλίας, γι 'αυτό το λόγο Σίμπσον ΜΙΛΑ ρε καλείται μέθοδος. Σε αυτήν την περίπτωση η έξοδος θα είναι:

 "Σίμπσον!" 

Ακολουθεί ένα ακόμη:

 ((Bart) simpson). Φάρσα (); 

Σε αυτήν την περίπτωση, το φάρσα String πέρασε όταν δημιουργήσαμε το Μπαρτ τάξη με νέο Bart ("D'oh"). Σε αυτήν την περίπτωση, πρώτα το σούπερ. φάρσα θα χρησιμοποιηθεί η μέθοδος, ακολουθούμενη από το συγκεκριμένο φάρσα μέθοδο από Μπαρτ. Η έξοδος θα είναι:

 "D'oh" "Knock Homer down" 

Πρόκληση βίντεο! Εντοπισμός σφαλμάτων Java πολυμορφισμού και κληρονομιάς

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

Συνηθισμένα λάθη με τον πολυμορφισμό

Είναι κοινό λάθος να πιστεύετε ότι είναι δυνατό να επικαλεστείτε μια συγκεκριμένη μέθοδο χωρίς να χρησιμοποιήσετε το cast.

Ένα άλλο λάθος είναι να μην είμαστε σίγουροι ποια μέθοδος θα επικαλεστεί όταν δημιουργείται μια τάξη πολυμορφικά. Να θυμάστε ότι η μέθοδος που θα καλείται είναι η μέθοδος της δημιουργούμενης παρουσίας.

Να θυμάστε επίσης ότι η μέθοδος παράκαμψης δεν είναι μέθοδος υπερφόρτωσης.

Είναι αδύνατο να παρακάμψετε μια μέθοδο εάν οι παράμετροι είναι διαφορετικές. Το είναι δυνατόν για να αλλάξετε τον τύπο επιστροφής της μεθόδου που παρακάμπτεται εάν ο τύπος επιστροφής είναι υποκατηγορία της μεθόδου superclass.

Τι να θυμάστε για τον πολυμορφισμό

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

Κλειδί απάντησης

Η απάντηση σε αυτόν τον αμφισβητία Java είναι ρε. Η έξοδος θα ήταν:

 Λατρεύω τον Sax! Φάτε τα σορτς μου! Σίμπσον! D'oh Knock Homer κάτω 

Αυτή η ιστορία, "Πολυμορφισμός και κληρονομιά στην Java" δημοσιεύθηκε αρχικά από το JavaWorld.