JAVA ΕΝΟΤΗΤΑ 28 – METHOD OVERRIDING AND SUPER

 

Δωρέαν μαθήματα Java

ΕΙΣΑΓΩΓΗ

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

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

INHERITANCE EXAMPLE 

Επειδή υπάρχει κληρονομικότητα ανάμεσα στις κλάσεις του παραδείγματος μας, μπορούμε να δημιουργήσουμε ένα αντικείμενο Salary είτε ένα αντικείμενο Manager. Για να δούμε τον μισθό του αντικειμένου Salary θα πρέπει να καλέσουμε την payment( ) μέθοδο, ενώ για να δούμε τον μισθό του Manager θα πρέπει να καλέσουμε την μέθοδο bonus( ) αντίστοιχα. Ας δούμε λοιπόν τι έχουμε μέχρι τώρα.

Employee.java

package com.example;

class Employee {
    public String name;
    public int AFM;
    public String department;
    public int employeeId;

    public void mailCheck() {
        System.out.println("Mailing a check to " + this.name);
    }
}


Salary.java

package com.example;

public class Salary extends Employee {

    public float salary;

    public double payment() {
        return this.salary / 52.0;
    }
}

 

Manager.java

package com.example;

public class Manager extends Salary {

    public double bonus() {
        return this.payment() + 1000;

    }
}


EmployeeDemo.java

package com.example;

public class EmployeeDemo {
    public static void main(String[] args) {
        Manager m1 = new Manager();
        m1.name = "Michail";
        m1.department = "Development";
        m1.salary = 20000;
        System.out.println("Hello " + m1.name);
        System.out.println("Your payment plus your bonus is: " + m1.bonus());

    }
}


Output

Hello Michail

Your payment plus your bonus is: 1384.6153846153848

 

Αν και το πρόγραμμα μας δουλεύει για το σκοπό που δημιουργήθηκε (έχουμε παραλείψει έξτρα κώδικα όπως getter και setter μεθόδους), κάπως μπερδεύει τον προγραμματιστή όταν μέσα στην EmployeeDemo κλάση πρέπει να καλέσει ένα όνομα μεθόδου για να δει τον μισθό του Salary και διαφορετικό όνομα μεθόδου για να δει τον μισθό του Manager. Σε μια αρκετά μεγάλη εφαρμογή με εκατοντάδες κλάσεις αυτό θα είναι λίγο δύσκολο να το ακολουθήσει κάποιος. Το επιθυμητό θα ήταν να υπάρχει μια κοινή μέθοδο για όλες τις κλάσεις, όπως για παράδειγμα payment( ). Μέσα σε κάθε κλάση η payment( ) θα περιέχει τον αντίστοιχο κώδικα που αντιπροσωπεύει την σωστή πληροφορία είτε είναι για τον Salary είτε για τον Manager. Το τελικό αποτέλεσμα θα είναι να υπάρχει μια μέθοδος με το ίδιο όνομα (αλλά διαφορετικό κώδικα) σε όλες τις κλάσεις. Με αυτό τον τρόπο από όποια κλάση και αν κάνουμε αντικείμενο θα γνωρίζουμε ότι καλώντας την payment( ) μέθοδο θα πάρουμε τον μισθό του αντίστοιχου αντικειμένου. 


 

METHOD OVERRIDING

Στην Java, ο πρακτικός τρόπος να δώσουμε αυτή την δομή στο πρόγραμμα μας είναι να ξαναγράψουμε τον κώδικα για μεθόδους που κληρονομούμε. Αυτή την διαδικασία την ονομάζουμε method overriding γιατί πολύ απλά γράφεις ξανά τον κώδικα της μεθόδου που κληρονομείς κρατώντας ίδιο το signature. Αυτή την δυνατότητα την έχουμε λόγω της κληρονομικότητας.

Όταν όμως κάνουμε override μια μέθοδο, η java θέλει να ακολουθήσουμε τρεις απλούς κανόνες:

  • Το signature της μεθόδου, δηλαδή το return type, method name και parameter list πρέπει να παραμείνουν τα ίδια
  • Ο access specifier πρέπει να είναι τουλάχιστον ίδιος, ή πιο χαλαρός με εκείνον της κλάσης από την οποία κληρονόμησες την μέθοδο. Δηλαδή αν έχουμε κληρονομήσει μια μέθοδο που έχει access specifier protected, τότε στην δική μας κλάση μπορούμε να δώσουμε είτε τον ίδιο access specifier στην μέθοδο ή πιο χαλαρό όπως public, όχι όμως private. Με την ίδια λογική εάν κληρονομήσουμε μια μέθοδο με public access specifier τότε θα πρέπει και εμείς να κρατήσουμε το public.
  • Τέλος, δεν επιτρέπεται από την java, η δική μας μέθοδο να επιστρέφει περισσότερα exceptions από την αρχική. Για τα exceptions θα μιλήσουμε σε μελλοντική ενότητα.

Προσέξτε με τους δύο όρους override και overload. Το overload όπως έχουμε ήδη εξηγήσει σε προηγούμενη ενότητα, σημαίνει ότι αλλάζω τον αριθμό και είδος των παραμέτρων (parameter list) σε μια μέθοδο ενώ κρατάω ίδιο μόνο το όνομα της. Το override σημαίνει ότι αφήνω τον ορισμό της μεθόδου αυτούσιο και απλά αλλάζω τον κώδικα που περιέχει ή προσθέτω επιπλέον κώδικα σε αυτόν που ήδη περιέχει.

Στο δικό μας παράδειγμα λοιπόν, θα μπορούσαμε αντί να γράψουμε μια καινούργια μέθοδο bonus( ) μέσα στην κλάση Manager, να κάναμε override την μέθοδο payment που κληρονομούμε από την Salary και να αλλάξουμε τον κώδικα της έτσι ώστε να δείχνει τον σωστό κώδικα για την κλάση Manager. Το τελικό αποτέλεσμα είναι ότι όταν πάμε στην κλάση EmployeeDemo να δημιουργήσουμε αντικείμενο είτε από κλάση Salary είτε από την κλάση Manager, η μέθοδος payment( ) θα σας δώσει το σωστό αποτέλεσμα για το αντίστοιχο αντικείμενο. Ας δούμε λοιπόν πως αλλάζει ο κώδικας μας. Αυτή η αλλαγή θα γίνει κυρίως στην Manager (μέσα στην οποία θα κάνουμε το override).

Manager.java

package com.example;

public class Manager extends Salary {

    @Override
    public double payment() {
        return this.salary / 52.0 + 1000;
    }
}


EmployeeDemo.java

package com.example;

public class EmployeeDemo {
    public static void main(String[] args) {
        Manager m1 = new Manager();
        m1.name = "Michail";
        m1.department = "Development";
        m1.salary = 20000;
        System.out.println("Hello " + m1.name);
        System.out.println("Your payment plus your bonus is: " + m1.payment());

    }
}

 

Output

Hello Michail

Your payment plus your bonus is: 1384.6153846153848

 

CALLING SUPER

Αν και στην κλάση Manager κάναμε override την μέθοδο payment γράφοντας τον δικό μας κώδικα, για ακόμη μια φορά δεν είμαστε ικανοποιημένοι γιατί πολύ απλά γράψαμε όλο τον κώδικα της payment από την αρχή και στο τέλος προσθέσαμε το bonus. Το ιδανικό σενάριο θα ήταν να καλούσαμε την μέθοδο payment όπως έχει γραφτεί στην Salary και απλά να προσθέσουμε τον έξτρα κώδικα. Αυτό ακριβώς μας επιτρέπει να κάνουμε η λέξη super. Με την super μπορούμε να καλέσουμε μεταβλητές ή μεθόδους από την κλάση την οποία κληρονομούμε. Προσέξτε, αναφερόμαστε στην αμέσως προηγούμενη κλάση από την οποία κληρονομούμε και όχι οποιαδήποτε κλάση στο δέντρο κληρονομικότητας το οποίο ίσως αποτελείται από πολλαπλές κλάσεις. 


 

Με αυτή την λογική λοιπόν μπορούμε να αλλάξουμε τον κώδικα της payment μεθόδου μέσα στην κλάση Manager ως εξής:

Manager.java

package com.example;

public class Manager extends Salary {

    @Override
    public double payment() {
        return super.payment() + 1000;
    }
}

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

Μην ξεχάσετε να κάνετε ένα μικρό donation έτσι ώστε αυτό το blog να μεγαλώσει ακόμα πιο πολύ και να έχει περισσότερες δυνατότητες στην online παράδοση δωρεάν μαθημάτων.

full-width

Post a Comment

1 Comments

  1. μπράβο σου για αυτήν την προσπάθεια.

    θα σου πρότεινα μία σχεδόν ασήμαντη διόρθωση:

    - συνήθως χρησιμοποιούμε ρήματα στις μεθόδους, διότι κάθε μέθοδος εκφράζεται ως μία ενέργεια. Για αυτόν τον λόγο συνήθως έχουμε τους "getters" και "setters" σε μία κλάση.

    Πιστεύω θα ήταν καλύερα αν στο παράδειγμα είχαμε είτε την μέθοδος "getPayment()" είτε "calculatePayment()" από το σκέτο "payment" που υποδεικνύει περισσότερο property μίας κλάσης

    ReplyDelete

Η γνώμη σας είναι σημαντική.