Sobes.tech
Junior

Πώς οργανώνεται η κληρονομικότητα και ο πολυμορφισμός στο Kotlin;

sobes.tech AI

Απάντηση από AI

Στην Kotlin, η κληρονομικότητα υλοποιείται μέσω μηχανισμού κλάσεων και διεπαφών. Οι κλάσεις μπορούν να κληρονομήσουν μόνο μια άλλη κλάση (μονογονική κληρονομικότητα), αλλά μπορούν να υλοποιούν πολλές διεπαφές.

Κατά κανόνα, όλες οι κλάσεις στην Kotlin είναι 'τελικές', δηλαδή δεν μπορούν να κληρονομηθούν. Για να επιτραπεί η κληρονομικότητα, η κλάση πρέπει να σημειωθεί ρητά με τη λέξη-κλειδί open.

Κληρονομικότητα κλάσεων:

open class Shape { // Βασική κλάση, σημειωμένη ως open
    open fun draw() { // Μέθοδος που μπορεί να υπερισχύσει
        println("Drawing a shape")
    }
}

class Circle : Shape() { // Κληρονομεί από το Shape
    override fun draw() { // Υπερισχύει τη μέθοδο
        println("Drawing a circle")
    }
}

Στη constructor της υποκείμενης κλάσης πρέπει να καλέσετε τον constructor της βασικής κλάσης, ρητά ή άμεσα.

Διεπαφές:

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

interface Drawable {
    fun draw() // Αφηρημένη μέθοδος
    fun description() { // Μέθοδος με προεπιλεγμένη υλοποίηση
        println("This is a drawable object")
    }
}

class Square : Drawable {
    override fun draw() { // Υλοποίηση της αφηρημένης μεθόδου
        println("Drawing a square")
    }
    // Η description() μπορεί να υπερισχύσει, αλλά δεν είναι υποχρεωτικό
}

Πολυμορφισμός:

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

fun render(drawable: Drawable) {
    drawable.draw() // Κλήση της μεθόδου draw() ανάλογα με τον πραγματικό τύπο του αντικειμένου
    drawable.description()
}

fun main() {
    val circle: Shape = Circle() // Το αντικείμενο Circle αντιμετωπίζεται ως Shape
    circle.draw() // Κλήση της draw() από το Circle λόγω πολυμορφισμού

    val square: Drawable = Square() // Το αντικείμενο Square αντιμετωπίζεται ως Drawable
    render(square) // Κλήση των draw() και description() από το Square
}

Σε αυτό το παράδειγμα, η render λειτουργεί με οποιοδήποτε αντικείμενο υλοποιεί το Drawable. Η κλήση drawable.draw() θα εκτελέσει την υλοποίηση της μεθόδου draw για τον συγκεκριμένο τύπο αντικειμένου (Square σε αυτή την περίπτωση).

Διαφορά μεταξύ κληρονομικότητας κλάσεων και υλοποίησης διεπαφών:

  • Κληρονομικότητα κλάσης: Ορίζει τη σχέση "είναι" (is-a). Η υποκείμενη κλάση κληρονομεί την κατάσταση και τη συμπεριφορά της βασικής κλάσης.
  • Υλοποίηση διεπαφής: Ορίζει "ικανότητα" ή "συμβόλαιο". Η κλάση υπόσχεται να παρέχει υλοποίηση για όλες τις αφηρημένες μεθόδους της διεπαφής.

Πίνακας σύγκρισης:

Χαρακτηριστικό Κληρονομικότητα κλάσης Υλοποίηση διεπαφής
Τύπος σχέσης is-a Ικανότητα / Συμβόλαιο
Πολλαπλότητα Μονογονική Πολλαπλή
Κατάσταση Κληρονομεί την κατάσταση της βασικής κλάσης Δεν κληρονομεί κατάσταση
Υλοποίηση μεθόδων Μπορεί να περιέχει υλοποίηση Μπορεί να περιέχει προεπιλεγμένη υλοποίηση (από Java 8)