JAVA ΕΝΟΤΗΤΑ 29 – USING SUPER WITH CONSTRUCTORS

 


ΕΙΣΑΓΩΓΗ

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

WHAT WE KNOW SO FAR

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

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;
    }
}


EmployeeDemo.java

package com.example;

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


Output

Hello Michail

Your payment is: 384.61538461538464

 

Με βάση τη θεωρία που έχουμε καλύψει μέχρι τώρα, και λόγω της κληρονομικότητας που υπάρχει, το Salary αντικείμενο περιέχει όλα τα στοιχεία του Employee και φυσικά και του ίδιου του Salary. Το γεγονός ότι το αντικείμενο Salary περιέχει όλα τα στοιχεία και από τις δύο κλάσεις οφείλεται στην κληρονομικότητα. Αλλά ποιος είναι ο μηχανισμός που δημιουργεί το αντικείμενο Salary και του δίνει όλες αυτές τις ιδιότητες? Η απάντηση είναι ο constructor. Ναι άλλα ο constructor του Salary δημιουργεί μόνο Salary αντικείμενα, ενώ το δικό μας αντικείμενο περιέχει περισσότερες ιδιότητες από αυτές που προσφέρει η κλάση Salary. Η απάντηση πάλι είναι ο constructor που το κάνει αυτό, αλλά όχι μόνο ο constructor της κλάσης Salary αλλά ο constructor της κάθε κλάσης που ανήκει στο δέντρο της κληρονομικότητας.

Με πιο απλά λόγια, όταν στο παράδειγμα μας δημιουργείτε ένα αντικείμενο είδος Salary, η Java ξεκινάει από την κορυφή της κληρονομικότητας που είναι η κλάση Object (για την οποία θα μιλήσουμε στο επόμενο δωρεάν μάθημα Java) και εκτελεί τον no-argument constructor της. Μετά, πηγαίνει στην κλάση Employee και εκτελεί τον no-argument constructor της κλάσης Employee και τέλος εκτελεί τον no-argument constructor της κλάσης Salary. Εκτελούνται όλοι οι no-argument constructors από την αρχή της κληρονομικότητας μέχρι την κλάση από την οποία επιθυμούμε να δημιουργήσουμε το δικό μας αντικείμενο.


Για να το αποδείξουμε αυτό, ας δημιουργήσουμε τους δικούς μας no-argument constructors μέσα στην κλάση Employee και μέσα στην κλάση Salary. Σας θυμίζω ότι ένας no-argument constructor είναι εκείνος ο οποίος δεν δέχεται παραμέτρους στην παρένθεση του και είναι διαθέσιμος για κάθε κλάση από την ίδια την Java εφόσον δεν έχουμε γράψει εμείς τους δικούς μας constructors. Ας βάλουμε επίσης ένα απλό μήνυμα μέσα σε κάθε constructor για να γνωρίζουμε πότε εκτελείται. Επειδή δεν έχουμε πρόσβαση στην Object κλάση, δεν μπορούμε να γράψουμε τον δικό μας no-argument constructor εκεί. Αλλάζουμε λοιπόν τις κλάσεις μας ως εξής:

Employee.java

package com.example;

class Employee{

    public Employee(){
        System.out.println("Employee constructor");
    }

    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 Salary(){
        System.out.println("Salary Constructor");
    }

    public float salary;

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


Output

Employee constructor

Salary Constructor

Hello Michail

Your payment is: 384.61538461538464

 

Τέλεια! Επιβεβαιώνεται η θεωρία μας και τώρα γνωρίζουμε τον τρόπο με τον οποίο δημιουργούνται τα αντικείμενα όταν υπάρχει κληρονομικότητα.

Τώρα ας κάνουμε μια αλλαγή στο σενάριο μας. Θεωρούμε λοιπόν ότι ένα αντικείμενο είδος Employee χωρίς αρχικές τιμές δεν έχει και πολύ λογική και θέλουμε να το αποφύγουμε. Δηλαδή, θέλουμε να δημιουργήσουμε έναν δικό μας constructor μέσα στην κλάση Employee που να ζητάει τουλάχιστον το όνομα και το ΑΦΜ του εργαζόμενου. Αν δεν είναι γνωστά αυτά τα στοιχεία τότε δεν θα δημιουργείται το αντικείμενο. Επίσης, για να αποφύγουμε την δημιουργία κενών από στοιχεία αντικειμένων, διαγράφουμε και τον no-argument constructor που μόλις δημιουργήσαμε. Μέχρι αυτό το σημείο, αν έχετε διαβάσει τα προηγούμενα δωρεάν μαθήματα Java θα πρέπει να σας είναι γνώριμη η όλη διαδικασία. Ο κώδικας της Employee αλλάζει ως εξής:

Employee.java

package com.example;

class Employee {

    public String name;
    public int AFM;
    public String department;
    public int employeeId;

    public Employee(String name, int AFM) {
        this.name = name;
        this.AFM = AFM;
        System.out.println("Employee constructor");
    }

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


Με το που γράψετε τον παραπάνω κώδικα, η κλάση Salary μας εμφανίζει μήνυμα λάθους και δεν μπορούμε να κάνουμε compile το πρόγραμμα μας.



Τι σημαίνει αυτό το μήνυμα? Και πως μπορούμε να το διορθώσουμε? Μάθαμε λοιπόν ότι όταν υπάρχει κληρονομικότητα, εκτελούνται όλοι οι constructors από την κορυφή μέχρι την κλάση από την οποία δημιουργούμε το αντικείμενο. Στο δικό μας παράδειγμα αυτή ήταν η κλάση Salary. Για να μπορέσει λοιπόν η Java να εκτελέσει όλους τους no-argument constructors θα πρέπει ο ένας no-argument constructor να μπορεί να βρει τον άλλον αρχίζοντας από κάτω προς τα πάνω. Δηλαδή, ο no-argument constructor της κλάσης Salary ψάχνει να βρει τον no-argument constructor της κλάσης Employee. Όταν το βρει, τότε ο no-argument constructor της κλάσης Employee ψάχνει να βρει τον no-argument constructor της κλάσης Object. Όταν βρεθεί και αυτός τότε αρχίζει από πάνω προς τα κάτω η εκτέλεση όλων των no-argument constructors.

Αυτό που κάναμε εμείς τώρα στην κλάση Employee, είναι να εξαφανίσουμε τον no-argument constructor από την κλάση. Αυτό συμβαίνει αυτόματα από την ίδια την Java. Όταν δημιουργούμε δικούς μας constructors η Java αποσύρει τον no-argument constructor της κλάσης. Και αυτό είναι λογικό γιατί από την στιγμή που γράψαμε έναν δικό μας constructor σημαίνει ότι δεν επιθυμούμε να παρέχουμε και την εύκολη λύση του no-argument constructor αλλά κυρίως να μην δημιουργούνται αντικείμενα χωρίς να περιέχουν χρήσιμες πληροφορίες. Με άλλα λόγια, “σπάσαμε” την προκαθορισμένη αλυσίδα που υπάρχει ανάμεσα στους no-argument constructors. Από την στιγμή λοιπόν που η Salary κλάση δεν μπορεί να βρει τον no-argument constructor της κλάσης Employee παρουσιάζει λάθος και δεν μας αφήνει να προχωρήσουμε.

Για να λύσουμε αυτό το πρόβλημα υπάρχουν δύο τρόποι. Ο πρώτος είναι να γράψουμε μέσα στην κλάση Employee έναν no-argument constructor όπως είχαμε στο προηγούμενο παράδειγμα. Αυτό όμως μας αναγκάζει να έχουμε δύο constructors διαθέσιμους οπότε μπορεί ο προγραμματιστής να επιλέγει τον no-argument αντί εκείνου που θέλουμε πραγματικά να χρησιμοποιήσει. Οπότε απορρίπτουμε αυτό τον τρόπο.

Ο δεύτερος είναι να δείξουμε στην Salary που βρίσκεται ο καινούργιος constructor έτσι ώστε να μην υπάρχει πια λάθος στην εύρεση του.

USING SUPER WITH CONSTRUCTORS

Για να το πετύχουμε αυτό χρησιμοποιούμε την λέξη κλειδί super μέσα στον constructor της Salary. Ας δούμε πως αλλάζει ο κώδικας της Salary τώρα και θα επιστρέψουμε να εξηγήσουμε τι πραγματικά συμβαίνει.

Salary.java

package com.example;

public class Salary extends Employee {

    public Salary(String name, int AFM) {
        super(name, AFM);
        System.out.println("Salary Constructor");
    }

    public float salary;

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


EmployeeDemo.java

package com.example;

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

Output

Employee constructor

Salary Constructor

Hello Michail

Your payment is: 384.61538461538464

 

Πήγαμε λοιπόν στον constructor της κλάσης Salary και προσθέσαμε την λέξη κλειδί super. Μέσα στην παρένθεση προσθέσαμε δύο μεταβλητές. Ολόκληρο το statement super(name, AFM) ειδοποιεί τον constructor της κλάσης Salary να βρει εκείνον τον constructor από την κλάση Employee ο οποίος δέχεται δύο παραμέτρους αφού δεν υπάρχει πια ο no-argument constructor. Η λέξη super πρέπει να είναι το πρώτο statement μέσα στον constructor.

Τώρα αφού με το super θα περάσουμε δύο τιμές στον constructor της κλάσης Employee που δέχεται δύο τιμές, ορίζουμε στον constructor της Salary ότι για την δημιουργία του αντικειμένου Salary θα πρέπει να δηλωθούν εξ αρχής το όνομα και το ΑΦΜ. Φυσικά η Salary μπορεί να περιέχει περισσότερους από έναν constructor όμως μέσα τους όλοι πρέπει να έχουν την δήλωση super. Επίσης, εάν η κλάση Employee περιέχει περισσότερους από έναν constructor, τότε πρέπει να επιλέξουμε σε ποιόν constructor της Emplotyee θέλουμε να κατευθύνουμε τον constructor της Salary.


Τέλος, αλλάξαμε την δήλωση δημιουργίας αντικειμένου στην EmployeeDemo γιατί η Salary δεν περιέχει no-argument constructor οπότε δηλώνουμε εξ αρχής τις δύο πληροφορίες που χρειάζεται για να τις περάσει στον constructor του Employee.

Πριν κλείσουμε αυτό το δωρεάν μάθημα Java θα ήθελα να σκεφτείτε λίγο, τώρα που γνωρίζετε όλη την θεωρία, τι πραγματικά συμβαίνει όταν έχουμε no-argument constructors. Στην πραγματικότητα, η Java χρησιμοποιεί την δήλωση super( ) για να καλέσει τον no-argument constructor της προηγούμενης κλάσης από την οποία κληρονομεί. Το συμπέρασμα είναι ότι με το this μπορούμε να καλέσουμε constructors μέσα στην ίδια κλάση, ενώ με το super καλούμε constructors από διαφορετικές κλάσεις.

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

full-width

Post a Comment

0 Comments