Εισαγωγή στον αντικειμενοστραφή προγραμματισμό Κλάσεις και αντικείμενα Κλάσεις και αντικείμενα Κατασκευαστές κλάσεων (constructors) Κατασκευαστές κλάσεων (constructors) Πακέτα (packages) Πακέτα (packages) Προσδιοριστές πρόσβασης (access specifiers) Κληρονομικότητα (inheritance) Κληρονομικότητα (inheritance) Τροποποιητές (modifiers) Τροποποιητές (modifiers)
Κλάσεις και αντικείμενα int, float, double, char: πρωτογενείς τύποι δεδομένων Σε αντικειμενοστραφείς γλώσσες προγραμματισμού δίνεται η δυνατότητα σχεδιάσης νέων και σύνθετων τύπων δεδομένων Κλάση: σύνθετη δομή δεδομένων σχεδιασμένη από τον προγραμματιστή Μια κλάση περιέχει ως μέλη της μεταβλητές (member variables) και συναρτήσεις (member functions) Ορισμός κλάσης: class myClass class myClass{ Δήλωση μεθόδων και μεταβλητών... Δήλωση μεθόδων και μεταβλητών... }
Ένα παράδειγμα (μητρώο εργαζομένων) class EmployeeRecord { String name; String name; String address; int salary; public void setSalary (int employeeSalary ) public void setSalary (int employeeSalary ) { salary = employeeSalary; } { salary = employeeSalary; } public int getSalary ( ) public int getSalary ( ) { return salary; } { return salary; }} Πρότυπο δημιουργίας μητρώου: Ονοματεπώνυμο Διεύθυνση Μηνιαίες αποδοχές Το πρότυπο (κλάση)καθορίζει τη δομή του μητρώου (αντικείμενο) κάθε εργαζομένου
Σχέση κλάσεων-αντικειμένων int a int Ορισμός μεταβλητής αντίστοιχου τύπου Τύπος Δεδομένων Employee John=new Employee( ) Class Employee{…..} Αρχικοποίηση αντικειμένου κλάσης Ορισμός κλάσης Κλάση: σύνθετος τύπος δεδομένων Αντικείμενο: στιγμιότυπο (instance) μιας κλάσης
Κατασκευαστές (Constructors) Συναρτήσεις που εκτελούνται κατά την αρχικοποίηση του αντικειμένου μιας κλάσης. Χρησιμοποιούνται για την απόδοση τιμών στις μεταβλητές-μέλη ενός αντικειμένου κατά τη δημιουργία του. Έχουν το ίδιο όνομα με την κλάση την οποία αρχικοποιούν. Οι κατασκευαστές ΔΕΝ ΕΠΙΣΤΡΕΦΟΥΝ ΤΙΜΗ.
Παραδείγματα κατασκευαστών class Rectangle { int height; int height; int width; int width; public Rectangle ( ) public Rectangle ( ) { height = 1; height = 1; width = 1; width = 1; }} class Rectangle { int height; int height; int width; int width; public Rectangle (int rectHeight, int rectWidth) public Rectangle (int rectHeight, int rectWidth) { height = rectHeight; height = rectHeight; width = rectWidth; width = rectWidth; }}
Πολλαπλοί κατασκευαστές Για μια κλάση μπορούν να οριστούν περισσότεροι του ενός κατασκευαστές και να επιλεγεί ένας από αυτούς κατά την αρχικοποίηση (constructor overloading) Για μια κλάση μπορούν να οριστούν περισσότεροι του ενός κατασκευαστές και να επιλεγεί ένας από αυτούς κατά την αρχικοποίηση (constructor overloading) Αν ο προγραμματιστής δεν ορίσει κατασκευαστή, υφίσταται ο default constructor (κατασκευαστής χωρίς ορίσματα). Υλοποίηση ενός κατασκευαστή από τον προγραμματιστή αυτομάτως αναιρεί τον default constructor. Αν ο προγραμματιστής δεν ορίσει κατασκευαστή, υφίσταται ο default constructor (κατασκευαστής χωρίς ορίσματα). Υλοποίηση ενός κατασκευαστή από τον προγραμματιστή αυτομάτως αναιρεί τον default constructor.
Παράδειγμα πολλαπλών κατασκευαστών class myClass { int a; int a; int b; int b; myClass() myClass() { a = 0; a = 0; b = 0; b = 0; } myClass( int alpha, int beta ) myClass( int alpha, int beta ) { a = alpha; a = alpha; b=beta; b=beta; }} myClass Test1 = new myClass( ); Καλείται ο constructor χωρίς ορίσματα (default constructor), συνεπώς: a = 0 b = 0 myClass Test2 = new myClass( 2, 3 ); a = 2 b = 3 α) β)
Πρόσβαση σε δεδομένα και μεθόδους αντικειμένων κλάσεων (που έχουν δηλωθεί public) Πρόσβαση σε public μεταβλητές μέλη:. Π.χ. someEmployeeRecord.salary = 1500; ( ανάθεση της τιμής 1500 στη μεταβλητή salary ) Κλήση μεθόδων:. Π.χ. 1. income=someEmployeeRecord.getSalary( ); ( Η μεταβλητή income λαμβάνει την τιμή που επιστρέφει η getSalary ( ) ) 2. someEmployeeRecord.setSalary(1500); (εκτέλεση της μεθόδου setSalary περνώντας ως όρισμα την τιμή 1500)
Παράδειγμα class Employee { int salary; int salary; public void setSalary (int employeeSalary ) public void setSalary (int employeeSalary ) { salary = employeeSalary } { salary = employeeSalary } int getSalary ( ) int getSalary ( ) { return salary; } { return salary; }} Employee John=new Employee ( ); John.setSalary (1200); int someSalary =John.getSalary ( );
Η δεσμευμένη λέξη this Η δεσμευμένη λέξη this αποτελεί έναν τρόπο αναφοράς στο τρέχον αντικείμενο. Χρήσιμη για τον διαχωρισμό μεταβλητών-μελών από ορίσματα συναρτήσεων σε περίπτωση που τα ονόματά τους ταυτίζονται. class EmployeeRecord { int salary; public void setInt (int salary) { this.salary = salary; } }
Πακέτα (packages) Kλάσεις συναφούς λειτουργικότητας ομαδοποιούνται σε πακέτα (packages) Κλάσεις του ίδιου πακέτου βρίσκονται στο ίδιο directory Η δήλωση του πακέτου στο οποίο ανήκει μια κλάση γίνεται στην αρχή του πηγαίου κώδικα package ; package ; Ένα πακέτο έχει το ίδιο όνομα με το όνομα του directory στο οποίο αποθηκεύονται οι κλάσεις του. Κλάσεις ενσωματωμένες σα packages προσαρτώνται στον κώδικα άλλων κλάσεων με τη δήλωση import. ;
Παράδειγμα A11.java: package Folder1; class A11 { Class Implementation…..} A12.java: package Folder1; class A12 { class implementation……} A21.java: package Folder2; class A21 { Class implementation} A22.java: package Folder2; import Folder1.A11; class A22 { Class implementation} Folder 1 A11.java A12.java Folder 2 A21.java A22.java
Προσδιοριστές πρόσβασης Καθορίζουν τα δικαιώματα πρόσβασης στις μεταβλητές και στις μεθόδους της κλάσης public: ορατά από οποιασδήποτε κλάση private: ορατά μόνο από την κλάση στην οποία ανήκουν ανήκουν protected: ορατά από την κλάση στην οποια ανήκουν και από υποκλάσεις της ανήκουν και από υποκλάσεις της Χωρίς δήλωση: ορατά από κλάσεις που ανήκουν στο ίδιο package στο ίδιο package
Παράδειγμα class A { private int a; private int a; public int getInt() public int getInt() {return a;} {return a;}} class B { private int b; private int b; void foo() void foo() { A myA = new A(); A myA = new A(); b = myA.a; ΛΑΘΟΣ b = myA.a; ΛΑΘΟΣ b = myA.getInt(); ΣΩΣΤΟ b = myA.getInt(); ΣΩΣΤΟ }} Παρατηρήσεις: Αν και η μεταβλητή a είναι private, η τιμή της μπορεί να παραληφθεί από την κλάση B μέσω της public συνάρτησης getInt (). Συνήθως οι μεταβλητές δηλώνονται private και οι όποιες τροποποιήσεις των τιμών τους επιτελούνται από μεθόδους που ορίζονται public. Δηλ. οι public μέθοδοι ορίζουν ένα interface, αποκρύπτοντας την εσωτερική δομή της κλάσης
Προσδιοριστές πρόσβασης σε κλάσεις public: κλάση ορατή απο οποιαδήποτε άλλη κλάση Χωρίς δήλωση: κλάση ορατή μόνο από κλάσεις που ανήκουν στο ίδιο package
Κληρονομικότητα (inheritance) Συχνά δημιουργούμε κλάσεις που εμπεριέχουν δεδομένα και μεθόδους που έχουν οριστεί σε προϋπάρχουσες κλάσεις Βολική η δημιουργία μιας νέας κλάσης (υποκλάση) που εμπεριέχει τη λειτουργικότητα μιας της προϋπάρχουσας κλάσης (υπερκλάση) Ορισμός μιας υποκλάσης: με τη χρήση της δεσμευμένης λέξης extends
Ένα παράδειγμα κληρονομικότητας class Parent { int a; int a; public void foo () {…..} public void foo () {…..}} class Child extends Parent { int b; int b; public void test( ); public void test( );} Child myChild; myChild.foo(); myChild.a = someInteger ; Έγκυρες κλήσεις, εφόσον η κλάση Child κληρονομεί μεταβλητές και μεθόδους της κλάσης Parent Parent Child
Διαδικασία αρχικοποίησης υποκλάσης Επιτελείται διαδοχική εκτέλεση των κατασκευαστών με τρόπο ιεραρχικό (από τις υπερκλάσεις προς τις υποκλάσεις). class Parent class Parent { Parent( ) {………} Parent( ) {………} } class Child extends Parent class Child extends Parent { Child( ) {……..} Child( ) {……..} } Parent ( ) Child ( ) Κατά τη δημιουργία ενός νέου αντικειμένου εκτελείται αρχικά πάντα ο default constructor της υπερκλάσης (εκτός κι αν ο προγραμματιστής αλλάξει τη συμπεριφορά του constructor της υποκλάσης)
Παράκαμψη μεταβλητών και μεθόδων (overriding) class Parent { public void foo() public void foo() { ……. } { ……. }} class Child extends Parent { public void foo() public void foo() { διαφοροποιημένος κώδικας } { διαφοροποιημένος κώδικας }} Child myChild = new Child(); myChild.foo(); Εκτελείται η συνάρτηση foo() που ορίστηκε στο σώμα της υποκλάσης Child. Η συνάρτηση foo() που ορίστηκε στην κλάση Parent παρακάμπτεται. Πώς καλούμε μέσα από την κλάση Child τη foo() της κλάσης Parent;
Η λέξη super Η δεσμευμένη λέξη super προσφέρει πρόσβαση σε μεταβλητές και μεθόδους της υπερκλάσης Η δεσμευμένη λέξη super προσφέρει πρόσβαση σε μεταβλητές και μεθόδους της υπερκλάσης class Parent { public void foo( ) {……..} } class Child extends Parent { public void foo( ) {……} Παράκαμψη της foo( ) της υπερκλάσης public void someChildFunction( ) { super.foo( ); Εκτελείται ο κώδικας της foo( ) της κλάσης Parent }
Αρχικοποίηση υποκλάσεων (πολλαπλοί κατασκευαστές) class Parent { int a; int a; int b; int b; Parent ( ) Parent ( ) { a = 0; a = 0; b = 0; b = 0; } Parent(int alpha, int beta) Parent(int alpha, int beta) { a = alpha; a = alpha; b = beta; b = beta; }} class Child extends Parent { Child( ) { } Child (int alpha, int beta) { super (alpha,beta); } } Child myChild = new Child(); Καλεί τον default constructor του Parent, άρα α = b = 0 Child myChild = new Child ( 1, 2 ); a = 1, b = 2
Ο τροποποιητής final α) Για μεταβλητές: Δεν αλλάζει η τιμή τους μετά την αρχικοποίησή τους αρχικοποίησή τους β) Για μεθόδους: Δεν παρακάμπτονται σε υποκλάσεις γ) Για κλάσεις: Δεν κληρονομούνται
Παραδείγματα private final int a = 5; a = 6 ; ΛΑΘΟΣ a = 6 ; ΛΑΘΟΣ class A { public final void foo(); public final void foo(); } class B extends A class B extends A { public void foo( ) {...} ΛΑΘΟΣ public void foo( ) {...} ΛΑΘΟΣ } final class A { ….. } class B extends A { …} ΛΑΘΟΣ class B extends A { …} ΛΑΘΟΣ
Ο τροποποιητής abstract Σε κλάσεις που κληρονομούνται (παρέχουν κοινό εννοιολογικό υπόβαθρο στις υποκλάσεις τους), συχνά ορίζουμε κενές συναρτήσεις που υλοποιούνται στις υποκλάσεις abstract methodName( ) ; abstract methodName( ) ; Οι abstract συναρτήσεις παρακάμπτονται σε υποκλάσεις Κλάσεις μέσα στις οποίες δηλώνεται έστω και μία abstract μέθοδος, χαρακτηρίζονται επίσης abstract. abstract public class A { abstract public void foo ( ); abstract public void foo ( ); } ΔΕΝ μπορούμε να αρχικοποιήσουμε abstract κλάσεις.
Παράδειγμα abstract public class Shape { abstract public void Draw ( ); abstract public void Draw ( ); } public class Circle extends Shape { public void Draw ( ) public void Draw ( ) { κώδικας σχεδίασης κύκλου} { κώδικας σχεδίασης κύκλου} } public class Rectangle extends Shape { public void Draw ( ) public void Draw ( ) { κώδικας σχεδίασης ορθογωνίου} { κώδικας σχεδίασης ορθογωνίου} }
Interfaces Πολλαπλή κληρονομικότητα: Σχηματισμός μιας υποκλάσης χρησιμοποιώντας περισσότερες από μία υπερκλάσεις. ΔΕΝ ΥΠΟΣΤΗΡΙΖΕΤΑΙ ΣΤΗ JAVA class Child extrends Parent1 extends Parent2 ΛΑΘΟΣ Εναλλακτική προσέγγιση: η χρήση των interfaces ( κλάσεις που περιέχουν μόνο abstract μεθόδους ) Οι abstract μέθοδοι των interfaces υλοποιούνται στις υποκλάσεις που τα υλοποιούν. Ορισμός ενός interface: interface myInterface interface myInterface { functionOne( ); Δεν είναι αναγκαίο να functionTwo( ); δηλωθούν ρητά ως abstract. functionOne( ); Δεν είναι αναγκαίο να functionTwo( ); δηλωθούν ρητά ως abstract. } Ορισμός υποκλάσης που υλοποιεί ένα interface: class myClass extends someParentClass implements myInterface class myClass extends someParentClass implements myInterface Υποκλάση που υλοποιεί ένα interface πρέπει να ολοποιεί όλες τις μεθόδους που ορίζονται σε αυτό.
Interfaces - Παράδειγμα public interface myInterface { public void foo( ); public void foo( ); public void foo2( String str ); public void foo2( String str ); } public class Test extends someParentClass implements myInterface public class Test extends someParentClass implements myInterface { public void foo ( ) public void foo ( ) { Function code here…} { Function code here…} public void foo2 ( String str ) public void foo2 ( String str ) { Function code here…} { Function code here…} }
Ο τροποποιητής static Κάθε αντικείμενο έχει τις δικές του μεταβλητές και μεθόδους ΟΜΩΣ: Μεταβλητές και μέθοδοι που δηλώνονται ως static είναι κοινές για όλα τα αντικείμενα της ίδιας κλάσης Για τη χρήση static μεταβλητών και μεθόδων ΔΕ χρειάζεται η δημιουργία στιγμιοτύπου κλάσης. Μέθοδοι που έχουν δηλωθεί static βλέπουν και τροποποιούν ΜΟΝΟ static μεταβλητές.
Παράδειγμα class myClass { public static int a = 1; public static int a = 1;} myClass first = new myClass ( ); myClass second = new myClass ( ); first.a = 2 ; Η μεταβλητή a παίρνει την τιμή 2 και στα δύο αντικείμενα δηλ. ισχύει first.a = 2 KAI second.a = 2
Καταστροφή αντικειμένων Σε αντίθεση με τη γλώσσα C, στη Java η κατάργηση αντικειμένων δεν επιτελείται από το χρήστη αλλά από το rutime system της Java. Garbage collector: Εντοπίζει αντικείμενα που δεν πρόκειται να ξαναχρησιμοποιηθούν στο μέλλον και τα καταργεί, αποδεσμεύοντας τη μνήμη που καταλαμβάνουν.