Σε αυτό το άρθρο, θα μάθετε για την κληρονομιά. Πιο συγκεκριμένα, τι είναι η κληρονομιά και πώς να την εφαρμόσετε στο Kotlin (με τη βοήθεια παραδειγμάτων).
Το κληρονομικό είναι ένα από τα βασικά χαρακτηριστικά του αντικειμενοστρεφούς προγραμματισμού. Επιτρέπει στο χρήστη να δημιουργήσει μια νέα κλάση (κλάση που προέρχεται) από μια υπάρχουσα τάξη (βασική κλάση).
Η παράγωγη κλάση κληρονομεί όλες τις δυνατότητες από τη βασική κατηγορία και μπορεί να έχει πρόσθετα χαρακτηριστικά από μόνη της.
Πριν εξετάσετε λεπτομέρειες σχετικά με την κληρονομιά του Kotlin, σας συνιστούμε να ελέγξετε αυτά τα δύο άρθρα:
- Κατηγορία και αντικείμενα Kotlin
- Πρωταρχικός κατασκευαστής Kotlin
Γιατί κληρονομιά;
Ας υποθέσουμε, στην αίτησή σας, θέλετε τρεις χαρακτήρες - έναν καθηγητή μαθηματικών , έναν ποδοσφαιριστή και έναν επιχειρηματία .
Επειδή, όλοι οι χαρακτήρες είναι πρόσωπα, μπορούν να περπατήσουν και να μιλήσουν. Ωστόσο, έχουν επίσης κάποιες ειδικές δεξιότητες. Ένας καθηγητής μαθηματικών μπορεί να διδάξει μαθηματικά , ένας ποδοσφαιριστής μπορεί να παίξει ποδόσφαιρο και ένας επιχειρηματίας μπορεί να διευθύνει μια επιχείρηση .
Μπορείτε να δημιουργήσετε μεμονωμένα τρία μαθήματα που μπορούν να περπατήσουν, να μιλήσουν και να εκτελέσουν την ειδική τους ικανότητα.
Σε κάθε ένα από τα μαθήματα, θα αντιγράφατε τον ίδιο κωδικό για τα πόδια και τη συζήτηση για κάθε χαρακτήρα.
Αν θέλετε να προσθέσετε μια νέα δυνατότητα - φάτε, πρέπει να εφαρμόσετε τον ίδιο κωδικό για κάθε χαρακτήρα. Αυτό μπορεί εύκολα να γίνει επιρρεπές σε σφάλματα (κατά την αντιγραφή) και διπλούς κωδικούς.
Θα ήταν πολύ πιο εύκολο αν είχαμε μια Person
τάξη με βασικά χαρακτηριστικά όπως ομιλία, περίπατο, φαγητό, ύπνο και προσθήκη ειδικών δεξιοτήτων σε αυτά τα χαρακτηριστικά σύμφωνα με τους χαρακτήρες μας. Αυτό γίνεται χρησιμοποιώντας κληρονομιά.
Χρησιμοποιώντας κληρονομιά, τώρα που δεν εφαρμόζουν τον ίδιο κωδικό για walk()
, talk()
και eat()
για κάθε κατηγορία. Απλά πρέπει να τα κληρονομήσετε .
Έτσι, για την MathTeacher
(παράγωγη κλάση), κληρονομείτε όλες τις δυνατότητες μιας Person
(βασικής κλάσης) και προσθέτετε μια νέα δυνατότητα teachMath()
. Ομοίως, για την Footballer
τάξη, κληρονομείτε όλες τις δυνατότητες της Person
τάξης και προσθέτετε μια νέα δυνατότητα playFootball()
και ούτω καθεξής.
Αυτό καθιστά τον κώδικα καθαρότερο, κατανοητό και επεκτάσιμο.
Είναι σημαντικό να θυμάστε: Όταν εργάζεστε με κληρονομιά, κάθε παράγωγη τάξη πρέπει να πληροί την προϋπόθεση εάν "είναι" βασική τάξη ή όχι. Στο παραπάνω παράδειγμα, MathTeacher
είναι α Person
, Footballer
είναι α Person
. Δεν μπορείς να έχεις κάτι σαν, Businessman
είναι Business
.
Κληρονομιά του Κότλιν
Ας προσπαθήσουμε να εφαρμόσουμε την παραπάνω συζήτηση σε κώδικα:
ανοιχτή τάξη Πρόσωπο (ηλικία: Int) (// κωδικός για φαγητό, ομιλία, περπάτημα) μάθημα MathTeacher (ηλικία: Int): Πρόσωπο (ηλικία) (// άλλα χαρακτηριστικά του καθηγητή μαθηματικών) τάξη Ποδοσφαιριστής (ηλικία: Int): Πρόσωπο ( age) (// άλλα χαρακτηριστικά του ποδοσφαιριστή) τάξη Επιχειρηματίας (ηλικία: Int): Άτομο (ηλικία) (// άλλα χαρακτηριστικά του επιχειρηματία)
Εδώ, Person
είναι μια βασική κλάση, και τάξεις MathTeacher
, Footballer
και Businessman
προέρχονται από την κλάση Person.
Ανακοίνωση, η λέξη-κλειδί open
πριν από την κλάση βάσης, Person
. Είναι σημαντικό.
Από προεπιλογή, τα μαθήματα στο Kotlin είναι οριστικά. Εάν είστε εξοικειωμένοι με την Java, γνωρίζετε ότι δεν είναι δυνατή η υποκατηγορία μιας τελικής τάξης. Χρησιμοποιώντας τον ανοιχτό σχολιασμό σε μια τάξη, ο μεταγλωττιστής σάς επιτρέπει να αντλείτε νέες τάξεις από αυτήν.
Παράδειγμα: Κληρονομικότητα Kotlin
open class Person(age: Int, name: String) ( init ( println("My name is $name.") println("My age is $age") ) ) class MathTeacher(age: Int, name: String): Person(age, name) ( fun teachMaths() ( println("I teach in primary school.") ) ) class Footballer(age: Int, name: String): Person(age, name) ( fun playFootball() ( println("I play for LA Galaxy.") ) ) fun main(args: Array) ( val t1 = MathTeacher(25, "Jack") t1.teachMaths() println() val f1 = Footballer(29, "Christiano") f1.playFootball() )
Όταν εκτελείτε το πρόγραμμα, η έξοδος θα είναι:
Το όνομα μου είναι τζάκ. Η ηλικία μου είναι 25 διδάσκω στο δημοτικό σχολείο. Το όνομά μου είναι Cristiano. Η ηλικία μου είναι 29, παίζω για το LA Galaxy.
Εδώ, δύο τάξεις MathTeacher
και Footballer
προέρχονται από την Person
τάξη.
Ο κύριος κατασκευαστής της Person
κλάσης δήλωσε δύο ιδιότητες: ηλικία και όνομα και έχει ένα μπλοκ αρχικοποιητή. Το μπλοκ initilizer (και οι λειτουργίες μέλους) της κατηγορίας βάσης Person
μπορεί να προσεγγιστεί από τα αντικείμενα των παραγόμενων κλάσεων ( MathTeacher
και Footballer
).
Παράγονται τάξεις MathTeacher
και Footballer
έχουν τις δικές τους λειτουργίες μελών teachMaths()
και playFootball()
αντίστοιχα Αυτές οι λειτουργίες είναι προσβάσιμες μόνο από τα αντικείμενα της αντίστοιχης κατηγορίας τους.
Όταν δημιουργείται το αντικείμενο t1 της MathTeacher
κλάσης,
val t1 = MathTeacher (25, "Τζακ")
Οι παράμετροι μεταβιβάζονται στον κύριο κατασκευαστή. Στο Kotlin, το init
μπλοκ καλείται όταν δημιουργείται το αντικείμενο. Δεδομένου ότι MathTeacher
προέρχεται από την Person
κλάση, αναζητά μπλοκ αρχικοποιητή στην βασική κλάση (Πρόσωπο) και το εκτελεί. Εάν το MathTeacher
μπλοκ init, ο μεταγλωττιστής θα είχε επίσης εκτελέσει το μπλοκ init της προερχόμενης κλάσης.
Στη συνέχεια, η teachMaths()
συνάρτηση για αντικείμενο t1
καλείται χρησιμοποιώντας t1.teachMaths()
δήλωση.
Το πρόγραμμα λειτουργεί με παρόμοιο τρόπο, όταν αντικείμενο f1
της Footballer
δημιουργείται τάξη. Εκτελεί το μπλοκ init της βασικής κλάσης. Στη συνέχεια, η playFootball()
μέθοδος της Footballer
τάξης καλείται χρησιμοποιώντας δήλωση f1.playFootball()
.
Σημαντικές σημειώσεις: Kotlin Inheritance
- Εάν η κλάση έχει έναν αρχικό κατασκευαστή, η βάση πρέπει να αρχικοποιηθεί χρησιμοποιώντας τις παραμέτρους του πρωτεύοντος κατασκευαστή. Στο παραπάνω πρόγραμμα, και οι δύο παράγωγες κλάσεις έχουν δύο παραμέτρους
age
καιname
, και οι δύο αυτές παράμετροι αρχικοποιούνται στον πρωτογενή κατασκευαστή στην κατηγορία βάσης.
Εδώ είναι ένα άλλο παράδειγμα:open class Person(age: Int, name: String) ( // some code ) class Footballer(age: Int, name: String, club: String): Person(age, name) ( init ( println("Football player $name of age $age and plays for $club.") ) fun playFootball() ( println("I am playing football.") ) ) fun main(args: Array) ( val f1 = Footballer(29, "Cristiano", "LA Galaxy") )
- Σε περίπτωση που δεν υπάρχει πρωτεύων κατασκευαστής, κάθε βασική κλάση πρέπει να προετοιμάσει τη βάση (χρησιμοποιώντας σούπερ λέξη-κλειδί) ή να αναθέσει σε άλλο κατασκευαστή που το κάνει. Για παράδειγμα,
fun main(args: Array) ( val p1 = AuthLog("Bad Password") ) open class Log ( var data: String = "" var numberOfData = 0 constructor(_data: String) ( ) constructor(_data: String, _numberOfData: Int) ( data = _data numberOfData = _numberOfData println("$data: $numberOfData times") ) ) class AuthLog: Log ( constructor(_data: String): this("From AuthLog -> + $_data", 10) ( ) constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) ( ) )
Παράκαμψη λειτουργιών και ιδιοτήτων μελών
If the base class and the derived class contains a member function (or property) with the same name, you can need to override the member function of the derived class using override
keyword, and use open
keyword for the member function of the base class.
Example: Overriding Member Function
// Empty primary constructor open class Person() ( open fun displayAge(age: Int) ( println("My age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )
When you run the program, the output will be:
My fake age is 26.
Here, girl.displayAge(31)
calls the displayAge()
method of the derived class Girl
.
You can override property of the base class in similar way.
Visit how Kotlin getters and setters work in Kotlin before you check the example below.
// Empty primary constructor open class Person() ( open var age: Int = 0 get() = field set(value) ( field = value ) ) class Girl: Person() ( override var age: Int = 0 get() = field set(value) ( field = value - 5 ) ) fun main(args: Array) ( val girl = Girl() girl.age = 31 println("My fake age is $(girl.age).") )
When you run the program, the output will be:
My fake age is 26.
As you can see, we have used override
and open
keywords for age property in derived class and base class respectively.
Calling Members of Base Class from Derived Class
Μπορείτε να καλέσετε συναρτήσεις (και ιδιότητες πρόσβασης) της βασικής κλάσης από μια παράγωγη κλάση χρησιμοποιώντας super
λέξη-κλειδί. Δείτε πώς:
open class Person() ( open fun displayAge(age: Int) ( println("My actual age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( // calling function of base class super.displayAge(age) println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )
Όταν εκτελείτε το πρόγραμμα, η έξοδος θα είναι:
Η ηλικία μου είναι 31. Η ψεύτικη ηλικία μου είναι 26.