JAVA ΕΝΟΤΗΤΑ 13 – CLASSES AND OBJECTS

 


ΕΙΣΑΓΩΓΗ

Στο σημερινό δωρεάν μάθημα Java θα εξηγήσουμε τι είναι κλάση (class) και πως χρησιμοποιείται για την δημιουργία αντικειμένων (objects).

Όπως καταλαβαίνετε μόλις ξεκινάει το ταξίδι μας στον κόσμο του object-oriented programming.

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

CLASS STRUCTURE

Η Java έχει δημιουργηθεί εξ αρχής να λειτουργεί σαν αντικειμενοστραφής γλώσσα προγραμματισμού. Αυτό με απλά λόγια σημαίνει οτιδήποτε κώδικα και αν γράψουμε θα πρέπει να περιέχεται είτε σε μια class είτε μέσα σε ένα interface. Αλλά ας τα πάρουμε τα πράγματα από την αρχή και ας ξεκινήσουμε από τι πραγματικά είναι μια κλάση.

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

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

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

Ωραία, οπότε για να αντιπροσωπεύσουμε προγραμματιστικά τον εργαζόμενο για τον οποίο ξεκινήσαμε να μιλάμε στο σενάριο μας, χρειάζεται να δημιουργήσουμε μια κλάση. Και πως δημιουργούμε μια κλάση? Αυτό το έχετε κάνει ήδη σε όλα τα προγράμματα που έχετε γράψει μέχρι τώρα. Η γενική δομή μιας κλάσης είναι η εξής:

class classname {

}

Ο ορισμός της κλάσης απαιτεί να γράψουμε πρώτα την λέξη κλειδί class και αμέσως μετά το όνομα που θέλουμε να δώσουμε στην κλάση. Ο κώδικας που θα ανήκει στη κλάση ορίζεται από τα curly braces ( { } ).

Οπότε για αρχή χρειάζεται να δημιουργήσουμε μια κλάση με το όνομα Employee.

Employee.java

package com.example;

public class Employee {
   
}

Το όνομα του αρχείου που θα περιέχει την κλάση πρέπει να έχει το ίδιο όνομα με τη κλάση. Οπότε στο δικό μας παράδειγμα δημιουργήσουμε ένα αρχείο Employee.java που περιέχει τη κλάση Employee.

Έχουμε λοιπόν δημιουργήσει μια κλάση και την ονομάσαμε Employee αλλά δεν έχουμε ακόμα περιγράψει προγραμματιστικά την έννοια του εργαζόμενου.

Κάθε κλάση μπορεί να περιγράφει τα αντικείμενα της χρησιμοποιώντας δύο προγραμματιστικές προσεγγίσεις: μεταβλητές (variables) και μεθόδους (methods). Οι μεταβλητές περιγράφουν τα χαρακτηριστικά του αντικειμένου (age, salary, κτλ) ενώ οι μέθοδοι περιγράφουν τι μπορεί να εκτελεί σαν πράξη το αντικείμενο (calculateOvertime, VacationTimeLeft, κτλ). Στο δικό μας παράδειγμα, για αρχή, θα προσθέσουμε μόνο μεταβλητές. Όταν αργότερα μάθουμε για τις μεθόδους τότε θα τις προσθέσουμε και αυτές στην λογική του προγράμματος μας.

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

 Όπως ήδη έχουμε αναφέρει, θα πρέπει να ορίσουμε αυτά τα χαρακτηριστικά σαν μεταβλητές μέσα στην κλάση που έχουμε ορίσει. Η δήλωση των μεταβλητών είναι ίδια με αυτή ήδη γνωρίζετε με την επιπλέον πληροφορία της πρόσβασης ή όπως αλλιώς ονομάζεται access specifier. Για τη σωστή δήλωση μια μεταβλητής χρειαζόμαστε λοιπόν να ορίσουμε τρεις όρους:

·         access specifier – δηλώνει ποιες άλλες κλάσεις ή γενικότερα στοιχεία της Java έχουν πρόσβαση σε αυτές τις μεταβλητές. Η πρόσβαση δηλώνεται προσθέτοντας μπροστά από την μεταβλητή μια από τις εξής λέξεις κλειδιά: public, private, protected, ή τίποτα που θεωρείται σαν default. Εμείς για τώρα θα αφήσουμε την πρόσβαση να είναι public χωρίς να βάλουμε κανένα περιορισμό στο κάλεσμα των μεταβλητών.

·         data type – όπως σε κάθε δήλωση μεταβλητής έτσι και στις μεταβλητές που ανήκουν σε μια κλάση θα πρέπει να δηλώσουμε εξ αρχής το είδος των τιμ΄βν που θα δέχονται.

·         name – είναι το όνομα που θα δώσουμε στη μεταβλητή.

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

Employee.java

package com.example;

public class Employee {
    public String name;
    public int AFM;
    public int employeeId;
    public double salary;
    public String department;
}

Όταν οι μεταβλητές ορίζονται σε επίπεδο κλάσης όπως στο παραπάνω παράδειγμα, και όχι μέσα σε μια μέθοδο όπως πχ. στη main( ), ονομάζονται instance variables γιατί κάθε αντικείμενο (instance)  που θα δημιουργηθεί από την κλάση θα περιέχει όλη τη λίστα των μεταβλητών και η διαχείριση τους είναι ευθύνη του εκάστοτε αντικειμένου.

Εξ αρχής όλες οι μεταβλητές έχουν μηδέν τιμές με βάση τους κανόνες της Java.



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

Η κλάση Employee είναι έτοιμη. Όμως, όπως ήδη γνωρίζεται, κανένα πρόγραμμα στην java δεν εκτελείται αν δεν υπάρχει η main() μέθοδο. Οπότε έχουμε δημιουργήσει το καλούπι που θα δημιουργήσει αντικείμενα Employee αλλά ακόμα δεν έχουμε δυνατότητα να εκτελέσουμε τίποτα. Πως το κάνουμε αυτό?

Ο καλύτερος τρόπος είναι να δημιουργήσουμε μια ακόμα κλάση που θα περιέχει την main( ) μέθοδο από την οποία θα καλέσουμε όλες τις άλλες κλάσεις που έχουμε δημιουργήσει και από τις οποίες θα δημιουργήσουμε αντικείμενα. Ας δημιουργήσουμε στο ίδιο πακέτο μια ακόμα κλάση με το όνομα EmployeeDemo με τον εξής κώδικα:

EmployeeDemo.java

package com.example;

public class EmployeeDemo {
    public static void main(String[] args) {
       
 }
}


Ο κώδικας της main( ) ακόμα δεν δημιουργεί ούτε χειρίζεται κάποιο αντικείμενο. Τι παραπάνω χρειάζεται να γράψουμε για να δημιουργήσουμε το πρώτο μας αντικείμενο? Ας γράψουμε πρώτα τον κώδικα και μετά θα τον εξηγήσουμε.

Employee michail = new Employee();

Εδώ κρύβεται όλη η θεωρία και η έννοια του object-oriented programming. Ας δούμε όμως τι ακριβώς συμβαίνει.

Κάθε φορά που δημιουργούμε μια απλή κλάση, η java μας προσφέρει έναν μηχανισμό που ονομάζεται constructor για να μπορούμε να δημιουργήσουμε αντικείμενα από αυτή την κλάση. Ο constructor μοιάζει σαν μέθοδο γιατί έχει όνομα και ακολουθείται από παρένθεση αλλά με μια μεγάλη διαφορά – το όνομα του constructor είναι πάντα ίδιο με το όνομα της κλάσης. Με αυτό τον τρόπο ξέρει η java από ποια κλάση να δημιουργήσει το αντικείμενο που χρειαζόμαστε. Για να ολοκληρωθεί όμως η διαδικασία πρέπει να προσθέσουμε μπροστά από τον constructor την λέξη κλειδί new. Οπότε αυτό που έχουμε καταφέρει μέχρι τώρα είναι να δημιουργήσουμε ένα καινούργιο αντικείμενο στην μνήμη του υπολογιστή μας. Η εντολή που το έχει πραγματοποιήσει αυτό είναι ο κώδικας που βρίσκεται στην δεξιά πλευρά του ίσον συμβόλου

new Employee();

Εδώ αρχίζουμε να βλέπουμε πως η Java διαφέρει από άλλες γλώσσες προγραμματισμού όπως πχ. C και C++. Όταν δημιουργείται ένα αντικείμενο η Java δεν μας αφήνει να έχουμε άμεση πρόσβαση στο αντικείμενο γιατί θέλει εκείνη να έχει την ευθύνη διαχείρισης της μνήμης και κυρίως την δημιουργία και διαγραφή των αντικειμένων από την μνήμη για να αποφεύγονται τυχόν memory leaks. Αυτό είναι ένα μεγάλο πλεονέκτημα για μας γιατί αν γράφαμε σε άλλη γλώσσα προγραμματισμού θα έπρεπε να ακολουθούμε το αντικείμενο από την στιγμή της δημιουργίας του μέχρι και την διαγραφή του. Αυτό θα απαιτούσε πολύ κώδικα και πολύ προσπάθεια από εμάς. Ευτυχώς όμως η java μας απαλλάσσει από αυτή την διαδικασία με έναν δικό της εσωτερικό μηχανισμό που ονομάζεται garbage collector και είναι ενεργοποιημένος από την στιγμή που εγκαταστήσαμε το JDK της java στον υπολογιστή μας. Αν όμως η java δεν μας αφήνει να έχουμε πρόσβαση στο αντικείμενο που μόλις δημιουργήσαμε πως θα μπορέσουμε να δώσουμε τιμές στα χαρακτηριστικά του εργαζόμενου? Η απάντηση είναι απλή – η δημιουργία ενός reference που δείχνει στο αντικείμενο. Εδώ επεμβαίνει η αριστερή πλευρά του ίσον συμβόλου στον κώδικα που έχουμε γράψει νωρίτερα.

Employee michail

Η java λοιπόν δεν μας αφήνει να έχουμε απευθείας αλληλεπίδραση με την μνήμη και την διαχείριση των αντικειμένων. Μας επιτρέπει όμως, για πρακτικούς λόγους, να δημιουργήσουμε ένα reference που θα δείχνει στο αντικείμενο που έχουμε δημιουργήσει. Στο δικό μας παράδειγμα αυτό το reference είναι το όνομα michail. Ενώ εμείς λοιπόν διαχειριζόμαστε το reference (michail), η java διαχειρίζεται το αντικείμενο στο οποίο αναφέρεται το reference. Τι σημαίνει όμως το Employee πριν το reference?

Κάθε μεταβλητή που δημιουργούμε στην java έχει και ένα data type, το ίδιο πρέπει να κάνουμε και με τα references. Μόνο που εδώ δεν θα ορίσουμε κάποιο primitive data type (όπως int double, κτλ) αλλά data type είδος κλάσης. Στην ουσία, και με πολύ απλά λόγια δηλώνουμε ότι το reference michail θα συμπεριφέρεται σαν Employee δηλαδή θα έχει όλες τις ιδιότητες που έχουμε ορίζει σαν μεταβλητές στην κλάση. Γιατί, θα υπήρχε περίπτωση να δημιουργήσουμε ένα αντικείμενο από μια κλάση αλλά να συμπεριφέρεται σαν να είναι δημιουργημένο από μια άλλη? Ναι, υπάρχει και ονομάζεται πολυμορφισμός. Όμως είναι πολύ νωρίς να μιλήσουμε για αυτό ακόμα.

Ας γυρίσουμε πίσω στην γραμμή κώδικα που γράψαμε και ας ανακεφαλαιώσουμε όσα είπαμε μέχρι τώρα. Έχουμε καλέσει τον constructor της κλάσης Employee να δημιουργήσουμε ένα καινούργιο αντικείμενο. Μετά δηλώσαμε ένα reference που να αναφέρεται σε αυτό το αντικείμενο και μάλιστα είπαμε ότι το reference θα συμπεριφέρεται σαν Employee. Τι σημαίνει αυτό? Σημαίνει ότι όταν τώρα στην επόμενη γραμμή του προγράμματος μας γράψουμε michail και τελεία ( . ) θα εμφανιστεί η λίστα με τις μεταβλητές στις οποίες μπορούμε να καθορίσουμε τις τιμές τους για το συγκεκριμένο αντικείμενο. Ορίζουμε λοιπόν για το συγκεκριμένο αντικείμενο τις εξής τιμές:

EmployeeDemo.java

package com.example;

public class EmployeeDemo {
    public static void main(String[] args) {
        Employee michail = new Employee();
        michail.AFM = 12345;
        michail.department = "IT";
        michail.employeeId = 100;
        michail.name = "Michail Kassapoglou";
        michail.salary = 10000;
    }
}


Εδώ θα πρέπει να αναφερθούμε σε δύο στοιχεία. Πρώτον είναι το γεγονός ότι πολλοί προγραμματιστές αναφέρονται στον προφορικό τους λόγο κυρίως όταν συνομιλούν με συναδέλφους στην μεταβλητή michail σαν αντικείμενο. Με άλλα λόγια μπορείτε να ακούσετε “δημιουργώ ένα αντικείμενο michail”. Αυτό στην πραγματικότητα είναι λάθος όμως επειδή γνωρίζουν την θεωρία, όπως και εσείς τώρα για λόγους συντομίας το εκφράζουν έτσι. Δεύτερον, είναι το γεγονός ότι και η κλάση Employee και η κλάση EmployeeDemo βρίσκονται στο ίδιο πακέτο οπότε ο constructor της κλάσης Employee ψάχνει εξ ορισμού στο ίδιο πακέτο στο οποίο καλείται και βρίσκει ότι στο ίδιο πακέτο βρίσκεται και η κλάση Employee από την οποία θα δημιουργήσει ένα ή περισσότερα αντικείμενα. Δεν είναι όμως ανάγκη να βρίσκονται στο ίδιο πακέτο. Αυτή την επιλογή θα την δούμε σε μελλοντικές ενότητες.

 Το πρόγραμμα μας είναι σχεδόν έτοιμο, αυτό που μας λείπει είναι να εκτυπώσουμε τις πληροφορίες για τον εργαζόμενο michail που μόλις δημιουργήσαμε. Η τελική μορφή λοιπόν του κώδικα μας είναι η εξής:

EmployeeDemo.java

package com.example;

public class EmployeeDemo {
    public static void main(String[] args) {
        Employee michail = new Employee();
        michail.AFM = 12345;
        michail.department = "IT";
        michail.employeeId = 100;
        michail.name = "Michail Kassapoglou";
        michail.salary = 10000;

        System.out.println("Your name is " + michail.name +" and your employee number is " + michail.employeeId);
    }
}

Output

Your name is Michail Kassapoglou and your employee number is 100

Τέλεια! Έχουμε δημιουργήσει το πρώτο μας ολοκληρωμένο object oriented πρόγραμμα που χρησιμοποιεί αντικείμενα! Μια τελευταία ερώτηση που θέλω να απαντήσω γιατί μπορεί να το έχετε ήδη αναρωτηθεί είναι πότε ο garbage collector διαγράφει τα αντικείμενα. Εμείς τα δημιουργούμε όμως πότε διαγράφονται? Βασικά, αυτό που ελέγχει σε γενικές γραμμές ο garbage collector είναι να δει αν υπάρχουν αντικείμενα στην μνήμη στα οποία δεν υπάρχουν references. Αν βρει ότι υπάρχουν αντικείμενα χωρίς references τότε μέσα σε ένα μικρό χρονικό διάστημα θα καθαρίσει αυτά τα αντικείμενα. Εμείς μπορούμε να προκαλέσουμε μια τέτοια πράξη αν πολύ απλά αναθέσουμε την τιμή null στο reference, δηλαδή να γράψουμε:

michail = null;

Τέλος αν θέλουμε να αλλάξουμε την τιμή σε οποιαδήποτε μεταβλητή δεν έχουμε παρά να γράψουμε το reference.nameofvariable = new value. Για παράδειγμα:

michail.salary=20000

Ας δούμε ένα τελευταίο πρόγραμμα με όλα όσα μιλήσαμε μέχρι τώρα:

EmployeeDemo.java

package com.example;

public class EmployeeDemo {
    public static void main(String[] args) {
        Employee michail = new Employee();
        michail.AFM = 12345;
        michail.department = "IT";
        michail.employeeId = 100;
        michail.name = "Michail Kassapoglou";
        michail.salary = 10000;

        System.out.println("Your name is " + michail.name +" and your salary is " + michail.salary);
        michail.salary = 20000;
        System.out.println("Your name is " + michail.name +" and your new salary is " + michail.salary);
        michail = null;
    }
}

Output

Your name is Michail Kassapoglou and your salary is 10000.0

Your name is Michail Kassapoglou and your new salary is 20000.0


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


full-width

Post a Comment

0 Comments