This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
java:objects [2015/02/05 10:01] gthanos |
java:objects [2018/02/16 16:03] gthanos |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Δημιουργώντας Αντικείμενα ====== | + | ====== Δημιουργία Αντικειμένων ====== |
Μέχρι τώρα αναφέραμε στην [[ oop:introduction | "Εισαγωγή στον Αντικειμενοστραφή Προγραμματισμό" ]] ότι η κλάση είναι το βασικό σχέδιο μέσα από το οποίο δημιουργούνται επιμέρους αντικείμενα που φέρουν τα χαρακτηριστικά της κλάσης. Επίσης, δείξαμε πως ορίζουμε μία κλάση μέσα από παραδείγματα, αλλά δεν δείξαμε πως δημιουργούμε αντικείμενα από τις κλάσεις που ορίσαμε. | Μέχρι τώρα αναφέραμε στην [[ oop:introduction | "Εισαγωγή στον Αντικειμενοστραφή Προγραμματισμό" ]] ότι η κλάση είναι το βασικό σχέδιο μέσα από το οποίο δημιουργούνται επιμέρους αντικείμενα που φέρουν τα χαρακτηριστικά της κλάσης. Επίσης, δείξαμε πως ορίζουμε μία κλάση μέσα από παραδείγματα, αλλά δεν δείξαμε πως δημιουργούμε αντικείμενα από τις κλάσεις που ορίσαμε. | ||
- | Παρακάτω δίνεται ένα πρόγραμμα που δημιουργεί συγκεκριμένα αντικείμενα και εκτυπώνει τα αποτελέσματα στην κονσόλα. | + | Η δημιουργία αντικειμένων γίνεται με χρήση του τελεστή **new**. Για παράδειγμα, για να δημιουργήσουμε ένα αντικείμενο της κλάσης **Point** αρκεί να γράψουμε |
+ | |||
+ | <code java> | ||
+ | /* δημιουργεί ένα αντικείμενο τύπου Point | ||
+ | * με συντεταγμένες 3,5 και το αναθέτει στη | ||
+ | * μεταβλητή p που είναι τύπου Point. | ||
+ | */ | ||
+ | Point p; // (a) | ||
+ | p = new Point(3,5); // (b) | ||
+ | </code> | ||
+ | |||
+ | Μπορείτε να σκεφτείτε τη μεταβλητή **p** ως ένα δείκτη σε αντικείμενα τύπου **Point**. Αρχικά ο δείκτης είναι μη αρχικοποιημένος δείχνοντας στην τιμή **null**. Στην επόμενη γραμμή καλείται ο κατασκευαστής ο οποίος δημιουργεί ένα αντικείμενο τύπου **Point** με συντεταγμένες 3,5 και αναθέτει το αντικείμενο αυτό στη μεταβλητή **p**. Τα παρακάτω σχήματα απεικονίζουν εποπτικά την διαδικασία. | ||
+ | |||
+ | {{ java:createobject.png }} | ||
+ | |||
+ | |||
+ | ===== Ένα πιο εκτεταμένο παράδειγμα ===== | ||
+ | |||
+ | Παρακάτω δίνεται η κλάση **CreateObjectDemo** που δημιουργεί συγκεκριμένα αντικείμενα του τύπου **Point** και **Rectangle** και εκτυπώνει τα αποτελέσματα στην κονσόλα. Οι κλάσεις **Point** και **Rectangle** δίνονται επίσης παρακάτω: | ||
<code java Point.java> | <code java Point.java> | ||
public class Point { | public class Point { | ||
- | private int xCoord, yCoord; | + | private int x; |
- | | + | private int y; |
- | public Point(int x, int y) { | + | |
- | xCoord = x; | + | public Point(int xPos, int yPos) { |
- | yCoord = y; | + | x = xPos; |
- | } | + | y = yPos; |
- | public void setX(int x) { | + | } |
- | xCoord = x; | + | |
- | } | + | public int getX() { |
- | public void setY(int y) { | + | return x; |
- | yCoord = y; | + | } |
- | } | + | |
- | public int getX() { | + | public void setX(int xPos) { |
- | return xCoord; | + | x = xPos; |
- | } | + | } |
- | public int getY() { | + | |
- | return yCoord; | + | public int getY() { |
- | } | + | return y; |
+ | } | ||
+ | |||
+ | public void setY(int yPos) { | ||
+ | y = yPos; | ||
+ | } | ||
} | } | ||
</code> | </code> | ||
Line 30: | Line 53: | ||
<code java Rectangle.java> | <code java Rectangle.java> | ||
public class Rectangle { | public class Rectangle { | ||
- | private int width, height; | + | |
- | private Point origin; | + | // fields |
- | | + | private int width; |
- | public Rectangle(Point p, int w, int h) { | + | private int height; |
- | origin = p; | + | private Point origin; |
- | width = w; | + | |
- | height = h; | + | // constructors |
- | } | + | public Rectangle(int initWidth, int initHeight, Point initOrigin) { |
- | | + | width = initWidth; |
- | public Rectangle(int w, int h) { | + | height = initHeight; |
- | width = w; | + | origin = initOrigin; |
- | height = h; | + | } |
- | } | + | |
- | | + | public Rectangle(int initWidth, int initHeight, int originX, int originY) { |
- | public void setOrigin(Point p) { | + | width = initWidth; |
- | origin = p; | + | height = initHeight; |
- | } | + | origin = new Point(originX,originY); |
- | | + | } |
- | public void setHeight(int h) { | + | |
- | height = h; | + | // methods |
- | } | + | public void setWidth(int newWidth ) { |
- | | + | width = newWidth; |
- | public void setWidth(int w) { | + | } |
- | width = w; | + | |
- | } | + | public int getWidth() { |
- | | + | return width; |
- | public Point getOrigin() { | + | } |
- | return origin; | + | |
- | } | + | public void setHeight(int newHeight ) { |
- | | + | height = newHeight; |
- | public int getHeight() { | + | } |
- | return height; | + | |
- | } | + | public int getHeight() { |
- | | + | return height; |
- | public int getWidth() { | + | } |
- | return width; | + | |
- | } | + | public void setOrigin(Point newOrigin) { |
- | | + | origin = newOrigin; |
- | // Move rectangle origin by x,y | + | } |
- | public void move(int x, int y) { | + | |
- | origin.setX( origin.getX() + x ); | + | public Point getOrigin() { |
- | origin.setY( origin.getY() + y ) | + | return origin; |
- | } | + | } |
+ | |||
+ | public int getArea() { | ||
+ | return width * height; | ||
+ | } | ||
+ | // Move rectangle origin by dx,dy | ||
+ | public void moveOrigin(int dx, int dy) { | ||
+ | origin.setX( origin.getX() + dx ); | ||
+ | origin.setY( origin.getY() + dy ); | ||
+ | } | ||
} | } | ||
</code> | </code> | ||
Line 80: | Line 112: | ||
public class CreateObjectDemo { | public class CreateObjectDemo { | ||
- | public static void main(String[] args) { | + | public static void main(String[] args) { |
- | + | | |
- | // Declare and create a point object and two rectangle objects. | + | // Declare variables |
- | Point originOne = new Point(23, 94); | + | Point originOne, originTwo; |
- | Rectangle rectOne = new Rectangle(originOne, 100, 200); | + | Rectangle rectOne, rectTwo; |
- | Rectangle rectTwo = new Rectangle(50, 100); | + | // Create objects |
- | + | originOne = new Point(23, 94); | |
- | // display rectOne's width, height, and area | + | originTwo = new Point(15, -33); |
- | System.out.println("Width of rectOne: " + rectOne.getWidth() ); | + | rectOne = new Rectangle(100, 200, originOne); |
- | System.out.println("Height of rectOne: " + rectOne.getHeight() ); | + | rectTwo = new Rectangle(50, 100, originTwo); |
- | System.out.println("Area of rectOne: " + rectOne.getArea()); | + | |
- | + | // display rectOne's width, height, and area | |
- | // set rectTwo's position | + | System.out.println("[rectOne] xPos: " + rectOne.getOrigin().getX() + ", yPos: " + rectOne.getOrigin().getY()); |
- | rectTwo.setOrigin(originOne); | + | System.out.println("[rectOne] width: " + rectOne.getWidth() + ", height: " + rectOne.getHeight()); |
- | + | ||
- | // display rectTwo's position | + | // set rectTwo's position |
- | System.out.println("X Position of rectTwo: " + rectTwo.getOrigin().getX()); | + | rectTwo.setOrigin(originOne); |
- | System.out.println("Y Position of rectTwo: " + rectTwo.getOrigin().getY()); | + | // display rectTwo's position |
- | + | System.out.println("[rectTwo] xPos: " + rectTwo.getOrigin().getX() + ", yPos: " + rectTwo.getOrigin().getY()); | |
- | // move rectTwo and display its new position | + | |
- | rectTwo.move(40, -20); | + | // move rectTwo and display its new position |
- | System.out.println("X Position of rectTwo: " + rectTwo.getOrigin().getX()); | + | rectTwo.moveOrigin(40, -20); |
- | System.out.println("Y Position of rectTwo: " + rectTwo.getOrigin().getY()); | + | System.out.println("[rectTwo] xPos: " + rectTwo.getOrigin().getX() + ", yPos: " + rectTwo.getOrigin().getY()); |
- | } | + | |
+ | // display rectOne's position | ||
+ | System.out.println("[rectOne] xPos: " + rectOne.getOrigin().getX()+", yPos: " + rectOne.getOrigin().getY()); | ||
+ | |||
+ | // assign originOne value to originTwo | ||
+ | originTwo = originOne; | ||
+ | } | ||
} | } | ||
</code> | </code> | ||
- | Το παραπάνω πρόγραμμα τυπώνει τα εξής στην κονσόλα. | + | Αποθηκεύστε και τα τρία αρχεία στον ίδιο κατάλογο. Για να μεταγλωττίσετε τα παραπάνω πρόγραμμα αρκεί να γράψετε |
<code> | <code> | ||
- | Width of rectOne: 100 | + | javac Point.java // μεταγλώττιση της κλάσης Point |
- | Height of rectOne: 200 | + | javac Rectange.java // μεταγλώττιση της κλάσης Rectangle |
- | Area of rectOne: 20000 | + | javac CreateObjectDemo.java // μεταγλώττιση της κλάσης CreateObjectDemo |
- | X Position of rectTwo: 23 | + | |
- | Y Position of rectTwo: 94 | + | |
- | X Position of rectTwo: 63 | + | |
- | Y Position of rectTwo: 74 | + | |
</code> | </code> | ||
- | Από τα πάραπάνω αξίζει να προσέξουμε τα εξής. | + | Για να το τρέξετε γράφετε |
- | - Η κλάση Rectangle έχει δύο κατασκευαστές οι οποίοι καλούνται εναλλάξ στη συνάρτηση **main** προκειμένου να αρχικοποιήσουν τα αντικείμενα (**objects**) ''rectOne'' και ''rectTwo''. | + | |
- | - H συνάρτηση ''System.out.println()'' εκτυπώνει ένα αλφαριθμητικό (string) ακολουθούμενο από χαρακτήρα αλλαγής γραμμής. | + | |
- | ===== Δήλωση Reference μεταβλητών και δημιουργία αντικειμένων ====== | + | <code> |
+ | java CreateObjectDemo | ||
+ | </code> | ||
- | Στο παραπάνω πρόγραμμα ορίζονται στη συνάρτηση ''main'' τα εξής | + | Το παραπάνω πρόγραμμα τυπώνει τα εξής στην κονσόλα. |
- | <code java> | + | |
- | Point originOne = new Point(23, 94); | + | <code> |
- | Rectangle rectOne = new Rectangle(originOne, 100, 200); | + | [rectOne] xPos: 23, yPos: 94 |
- | Rectangle rectTwo = new Rectangle(50, 100); | + | [rectOne] width: 100, height: 200 |
+ | [rectTwo] xPos: 23, yPos: 94 | ||
+ | [rectTwo] xPos: 63, yPos: 74 | ||
+ | [rectOne] xPos: 63, yPos: 74 | ||
</code> | </code> | ||
- | Τα παραπάνω μπορούν να γραφούν αναλυτικότερα ως εξής. | + | ==== Επεξήγηση του παραπάνω κώδικα ===== |
- | <code java> | + | |
- | Point originOne; | + | |
- | Rectangle rectOne, rectTwo; | + | |
- | originOne = new Point(23, 94); | + | Στο παραπάνω πρόγραμμα ορίζονται στη μέθοδο ''main'' τα εξής |
- | rectOne = new Rectangle(originOne, 100, 200); | + | <code java> |
- | rectTwo = new Rectangle(50, 100); | + | // Declare variables |
+ | Point originOne, originTwo; | ||
+ | Rectangle rectOne, rectTwo; | ||
+ | // Create objects | ||
+ | originOne = new Point(23, 94); | ||
+ | originTwo = new Point(15, -33); | ||
+ | rectOne = new Rectangle(100, 200, originOne); | ||
+ | rectTwo = new Rectangle(50, 100, originTwo); | ||
</code> | </code> | ||
- | Οι πρώτες δύο γραμμές ορίζουν τις μεταλητές ''originOne'', ''rectOne'', ''rectTwo''. Οι μεταβλητές δυνητικά δείχνουν σε τύπους δεδομένων Point, Rectange, Rectangle. Προς το παρόν όμως το περιεχόμενο των μεταβλητών αυτών είναι απροσδιόριστο (undefined). Σε αναλογία με την γλώσσα C φανταστείτε τις μεταβλητές αυτές ως pointers που δεν είναι αρχικοποιημένοι σε κάποια υφιστάμενη διεύθυνση μνήμης. Η τιμή τους είναι απροσδιόριστη και η προσπάθεια να γράψουμε στη διεύθυνση μνήμης που δείχνουν θα προκαλάσει Segmentation Fault. Η παρακάτω εικόνα δείχνει την ύπαρξη ενός μη αρχικοποιημένου δείκτη. | + | Οι πρώτες δύο γραμμές ορίζουν τις μεταβλητές ''originOne'', ''originTwo'',''rectOne'' και ''rectTwo''. Οι μεταβλητές δυνητικά δείχνουν σε τύπους δεδομένων **Point** και **Rectangle**. Προς το παρόν όμως το περιεχόμενο των μεταβλητών αυτών είναι απροσδιόριστο (στην πραγματικότητα ο compiler αρχικοποιεί τις μεταβλητές αυτές στην τιμή **null**). |
- | {{ :java:reference-variables-01.png |}} | + | <WRAP tip 80% center round> |
+ | __Σε αναλογία με την γλώσσα C__, φανταστείτε τις μεταβλητές αυτές ως pointers που δεν είναι αρχικοποιημένοι σε κάποια υφιστάμενη διεύθυνση μνήμης. Η τιμή τους είναι απροσδιόριστη και η προσπάθεια να γράψουμε στη διεύθυνση μνήμης όπου δείχνουν θα προκαλέσει τερματισμό του προγράμματος από το λειτουργικό σύστημα. | ||
+ | </WRAP> | ||
- | Προκειμένου να αρχικοποιηθούν οι μεταβλητές αυτές απαιτούνται δύο βήματα: | + | Η παρακάτω εικόνα δείχνει την ύπαρξη των τεσσάρων μη αρχικοποιημένων δεικτών. Όλοι αρχικά δείχνουν στην τιμή **null**. |
- | - Η δέσμευση της απαραίτητης μνήμης, ώστε να μπορούμε να αποθηκεύσουμε τα δεδομένα που προδιαγράφονται απο τον συγκεκριμένο τύπο (κλάση). | + | |
- | - Η αρχικοποίηση των επιμέρους μεταβλητών των αντικειμένων που ορίζονται απο την εκάστοτε κλάση. | + | |
- | Η παρακάτω εικόνα δείχνει τον δείκτη μετά την δέσμευση της απαιτούμενης μνήμης και την αρχικοποίηση των δεδομένων (μεταβλητών) του αντικειμένου ''originOne''. | + | {{:java:createobjectdemoreference1.png|}} |
- | {{ :java:reference-variables-02.png ?400 |}} | + | Αμέσως μετά τις δηλώσεις των μεταβλητών ακολουθούν οι κλήσεις των κατασκευαστών των αντίστοιχων κλάσεων. Όπως προαναφέραμε, ο κατασκευαστής όταν καλείται δεσμεύει την απαραίτητη μνήμη για το αντικείμενο, αρχικοποιεί τα πεδία του αντικειμένου και επιστρέφει μία αναφορά προς το αντικείμενο που δημιούργησε. |
- | Ο παρακάτω κώδικας | + | Η παρακάτω εικόνα δείχνει τις μεταβλητές ''originOne'', ''originTwo'', ''rectOne'', ''rectTwo'' μετά την αρχικοποίηση τους από τους αντίστοιχους κατασκευαστές. |
- | <code java>rectOne = new Rectangle(originOne, 100, 200);</code> | + | {{:java:createobjectdemoreference2.png|}} |
- | δηλώνει την δέσμευση μνήμης για ένα αντικείμενο τύπου ''Rectangle'' όπου το σημείο της αρχής του είναι το σημείο ''originOne''. Επίσης ορίζονται οι τιμές των **width** και **height** σε 100 και 200 αντίστοιχα. O παραπάνω ορισμός σημαίνει ένα αρχικοποιημένο αντικείμενο μπορεί να έχει πολλούς δείκτες προς αυτό, όπως δείχνει το παρακάτω σχήμα. | + | Στη συνέχεια ακολουθούν οι εξής γραμμές κώδικα: |
- | {{ :java:reference-variables-03.png ?500 | }} | + | <code java> |
+ | // set rectTwo's position | ||
+ | rectTwo.setOrigin(originOne); | ||
+ | // display rectTwo's position | ||
+ | System.out.println("[rectTwo] xPos: " + rectTwo.getOrigin().getX() + ", yPos: " + rectTwo.getOrigin().getY()); | ||
+ | |||
+ | // move rectTwo and display its new position | ||
+ | rectTwo.moveOrigin(40, -20); | ||
+ | System.out.println("[rectTwo] xPos: " + rectTwo.getOrigin().getX() + ", yPos: " + rectTwo.getOrigin().getY()); | ||
+ | |||
+ | // display rectOne's position | ||
+ | System.out.println("[rectOne] xPos: " + rectOne.getOrigin().getX()+", yPos: " + rectOne.getOrigin().getY()); | ||
+ | </code> | ||
- | ===== Ο τελεστής new ===== | + | Στις γραμμές αυτές συμβαίνουν τα εξής: |
+ | - Το αντικείμενο ''rectTwo'' επιλέγει ως πεδίο origin to ''originOne''. Στη συνέχεια, μέσω του ''rectTwo'' μεταβάλλονται οι συντεταγμένες του αντικειμένου ''originOne''. | ||
+ | - Εκτυπώνονται οι αλλαγές για το ''rectTwo'' στην κονσόλα. | ||
+ | - Εκτυπώνονται οι αλλαγές για το ''rectOne'' στην κονσόλα. Παρατηρούμε ότι οι συντεταγμένες του πεδίου **origin** άλλαξαν και για το αντικείμενο ''rectOne''. | ||
+ | |||
+ | Tα παρακάτω δύο σχήματα αποτυπώνουν α) την αλλαγή του πεδίου **origin** του ''rectTwo'', ώστε να δείχνει στο αντικείμενο ''rectOne'' και β) την αλλαγή των περιεχομένων του ''originOne'' μέσω του αντικειμένου ''rectTwo''. Οι αλλαγές αυτές επηρεάζουν και το πεδίο **origin** του ''rectOne'' που δείχνει στο κοινό αντικείμενο ''origineOne''. | ||
+ | |||
+ | Παρατηρείστε ότι πλέον μόνο η μεταβλητή ''originTwo'' δείχνει στο αντικείμενο τύπου **Point** με συντεταγμένες 15, -33. | ||
+ | |||
+ | | **(a)** | | **(b)** | | ||
+ | | {{:java:createobjectdemoreference3.png|}} | |{{:java:createobjectdemoreference4.png|}} | | ||
+ | |||
+ | Τέλος το πρόγραμμα τελειώνει με την γραμμή κώδικα: | ||
+ | <code java> | ||
+ | // assign originOne value to originTwo | ||
+ | originTwo = originOne; | ||
+ | </code> | ||
+ | |||
+ | Μετά την γραμμή αυτή η μεταβλητή ''originTwo'' δείχνει στο αντικείμενο που δείχνει και η μεταβλητή ''originOne''. Πλέον δεν υπάρχει καμία μεταβλητή ή αναφορά που να δείχνει στο αντικείμενο τύπου **Point** με συντεταγμένες 15, -33. Το αντικείμενο αυτό θα διαγραφεί αυτόματα από την λειτουργία **[[#garbage_collection|Garbage Collection]]** του JVM. | ||
+ | |||
+ | {{:java:createobjectdemoreference5.png|}} | ||
+ | ===== Επεξήγηση της χρήσης του τελεστή new ===== | ||
Προκειμένου να δημιουργηθούν νέα αντικείμενα χρησιμοποιείται ο τελεστής **new**. O τελεστής **new** χρησιμοποιείται συνήθως με τον κατασκευαστή μίας κλάσης προκειμένου να κάνει τα εξής: | Προκειμένου να δημιουργηθούν νέα αντικείμενα χρησιμοποιείται ο τελεστής **new**. O τελεστής **new** χρησιμοποιείται συνήθως με τον κατασκευαστή μίας κλάσης προκειμένου να κάνει τα εξής: | ||
- Δέσμευση της απαραίτητης μνήμης και δημιουργία του αντικειμένου. Η αρχικά ορισμένη μεταβλητή δείχνει πλέον στην περιοχή μνήμης που έχει δεσμευτεί. | - Δέσμευση της απαραίτητης μνήμης και δημιουργία του αντικειμένου. Η αρχικά ορισμένη μεταβλητή δείχνει πλέον στην περιοχή μνήμης που έχει δεσμευτεί. | ||
- | - Αρχικοποίηση των εσωτερικών μεταβλητών (πεδίων) του αντικειμένου με κλήση του κατάλληλου κατασκευαστή της κλάσης. Εάν δεν έχει οριστεί κατασκευαστής τότε ο τελεστής new καλείται με χρήση του default κατασκευαστή (default constructor) που δεν έχει ορίσματα (π.χ. ''MyObject obj = new MyObject();'', όπου για την κλάση ''MyObject'' δεν έχει οριστεί κανένας κατασκευατής). | + | - Αρχικοποίηση των εσωτερικών μεταβλητών (πεδίων) του αντικειμένου με κλήση του κατάλληλου κατασκευαστή της κλάσης. Εάν δεν έχει οριστεί κατασκευαστής τότε ο τελεστής **new** καλείται με χρήση του default κατασκευαστή (default constructor) που δεν έχει ορίσματα (π.χ. ''MyObject obj = new MyObject();'', όπου για την κλάση ''MyObject'' δεν έχει οριστεί κανένας κατασκευατής). |
+ | |||
+ | <WRAP tip 80% center round> | ||
+ | Κατά την χρήση **primitive** τύπων δεδομένων σε ένα πρόγραμμα (int, float, double) δεν απαιτείται η χρήση του τελεστή **new**. Ο λόγος που συμβαίνει αυτό είναι ότι για τους συγκεκριμένους τύπους δεδομένων, η διαδικασία δέσμευσης της μνήμης είναι στατική, καθώς είναι γνωστό εκ των προτέρων το εύρος μνήμης που απαιτούν. Οι **primitive** τύποι δεδομένων αποθηκεύονται πάντοτε στο **stack** της μεθόδου μέσα στην οποία δηλώνονται. | ||
- | <WRAP tip> | + | Αντίθετα, για τα αντικείμενα των κλάσεων ο compiler δεν μπορεί να γνωρίζει εκ των προτέρων το μέγεθος τους, καθώς με την σειρά τους αυτά μπορεί να περιέχουν άλλα αντικείμενα, τα οποία με την σειρά τους μπορεί να περιέχουν άλλα αντικείμενα κ.ο.κ. Για τον λόγο αυτό, για τα αντικείμενα δεσμεύεται πάντοτε η απαραίτητη μνήμη δυναμικά, στην περιοχή δυναμικής δέσμευσης μνήμης που παραδοσιακά ονομάζεται **heap**. |
- | Κατά την χρήση **primitive** τύπων δεδομένων (int, float, double) δεν απαιτείται η χρήση του τελεστή **new** διότι η απαραίτητη μνήμη δεσμεύεται στο stack της μεθόδου που εκτελείται. | + | |
</WRAP> | </WRAP> | ||
===== Πολλαπλοί κατασκευαστές σε μία κλάση ===== | ===== Πολλαπλοί κατασκευαστές σε μία κλάση ===== | ||
- | Μία κλάση μπορεί να έχει πολλούς διαφορετικούς. Κάθε κατασκευαστής ορίζει μία διαφορετική αρχικοποίηση των εσωτερικών μεταβλητών των αντικειμένων που δημιουργούντια με βάση το "σχέδιο" της κλάσης. Το ποιός κατασκευαστής θα κληθεί εξαρτάται από τον τύπο, τη σειρά και τον αριθμό των ορισμάτων σε αναλογία με την υπερφόρτωση συναρτήσεων. Έτσι στη συνάρτηση main του παραδείγματος μας καλούνται δύο διαφορετικοί κατασκευαστές για δύο διαφορετικά αντικείμενα της ίδιας κλάσης. | + | Μία κλάση μπορεί να έχει πολλούς διαφορετικούς κατασκευαστές. Κάθε κατασκευαστής ορίζει μία διαφορετική αρχικοποίηση των εσωτερικών μεταβλητών των αντικειμένων που δημιουργούνται με βάση το "σχέδιο" της κλάσης. Το ποιoς κατασκευαστής θα κληθεί εξαρτάται από τον τύπο, τη σειρά και τον αριθμό των ορισμάτων σε αναλογία με την υπερφόρτωση μεθόδων. Ας υποθέσουμε την παρακάτω μέθοδο **main**, στην οποία καλούνται δύο διαφορετικοί κατασκευαστές για δύο διαφορετικά αντικείμενα της ίδιας κλάσης **Rectangle**. Παρατηρήστε ότι η μεταβλητή **rectOne** αρχικοποιείται από την 1ο κατασκευαστή της κλάσης και η μεταβλητή **rectTwo** από τον 2ο κατασκευαστή. |
<code java> | <code java> | ||
- | rectOne = new Rectangle(originOne, 100, 200); | + | public class CreateRectangleObjects { |
- | rectTwo = new Rectangle(50, 100); | + | public static void main(String []args) { |
+ | Point originOne = new Point(10,5); | ||
+ | rectOne = new Rectangle(100, 200, originOne); | ||
+ | rectTwo = new Rectangle(50, 100, -40, 80); | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
+ | |||
===== Χρήση Αντικειμένων ===== | ===== Χρήση Αντικειμένων ===== | ||
Line 190: | Line 272: | ||
<code java> | <code java> | ||
- | // cadence, speed, gear | + | // fields are width, height |
- | Bicycle bicycle = new Bicycle(10, 20, 30); | + | Rectangle rect = new Rectangle(10,20, -5, 22); |
- | System.out.println("Bicycle speed is " + bicycle.speed); | + | System.out.println("Rectangle dimensions are " + rect.width + ", " + rect.height); |
</code> | </code> | ||
- | <WRAP important> | + | <WRAP important 80% center round> |
- | Απαραίτητη προϋπόθεση για να δουλέψει ο παραπάνω κώδικας είναι το πεδίο speed να είναι προσβάσιμο, δηλαδή να μην έχει προσδιοριστή τύπου **private**. | + | Απαραίτητη προϋπόθεση για να δουλέψει ο παραπάνω κώδικας είναι τα πεδία width και height να είναι προσβάσιμα, δηλαδή να μην έχουν προσδιοριστή πρόσβασης τύπου **private**. |
</WRAP> | </WRAP> | ||
- | <WRAP tip> | + | <WRAP tip 80% center round> |
- | Όπως προείπαμε μία καλή προγραμματιστική πρακτική είναι η απόκρυψη των πεδίων κάθε κλάσης και η δήλωση συναρτήσεων για την πρόσβαση στα δεδομένα της. Σε αυτή την περίπτωση η πρόσβαση στα πεδία των αντικειμένων είναι μη επιτρεπτή (ο compiler δεν μεταγλωττίζει το πρόγραμμα). | + | Όπως προείπαμε μία καλή προγραμματιστική πρακτική είναι η απόκρυψη των πεδίων κάθε κλάσης και η δήλωση συναρτήσεων για την πρόσβαση στα δεδομένα της. Σε αυτή την περίπτωση η απευθείας πρόσβαση στα πεδία των αντικειμένων είναι μη επιτρεπτή (ο compiler δεν μεταγλωττίζει το πρόγραμμα). Η πρόσβαση σε μεταβλητές που έχουν τον προσδιοριστή **private** μπορεί να γίνει μόνο μέσω βοηθητικών συναρτήσεων (set/get) που έχουν τον προσδιοριστή **public**. |
</WRAP> | </WRAP> | ||
==== Χρήση των μεθόδων ενός αντικειμένου ==== | ==== Χρήση των μεθόδων ενός αντικειμένου ==== | ||
- | Σε αναλογία με τα πεδία οι μέθοδοι ενός αντικειμένου είναι προσβάσιμες μέσω του ονόματος του αντικειμένου, μία τελεία '.' και το όνομα του πεδίου. Για παράδειγμα, | + | Σε αναλογία με τα πεδία οι μέθοδοι ενός αντικειμένου είναι προσβάσιμες μέσω του ονόματος του αντικειμένου, μία τελεία '.' και το όνομα της μεθόδου. Για παράδειγμα, |
<code java> | <code java> | ||
- | // cadence, speed, gear | + | Rectangle rect = new Rectangle(10,20, -5, 22); |
- | Bicycle bicycle = new Bicycle(10, 20, 30); | + | System.out.println("Rectangle dimensions are " + rect.getWidth() + ", " + rect.getHeight() ); |
- | System.out.println("Bicycle speed is " + bicycle.getSpeed() ); | + | |
</code> | </code> | ||
- | <WRAP important> | + | <WRAP important 80% center round> |
Ισχύουν και για τις μεθόδους όσα αναφέρονται για τους προσδιοριστές τύπου **public**, **private** των πεδίων. | Ισχύουν και για τις μεθόδους όσα αναφέρονται για τους προσδιοριστές τύπου **public**, **private** των πεδίων. | ||
</WRAP> | </WRAP> | ||
Line 219: | Line 300: | ||
===== Garbage Collection ===== | ===== Garbage Collection ===== | ||
- | Οι γλώσσες υψηλού επιπέδου που μέχρι τώρα έχετε γνωρίσει (**C**) αναθέτουν την ευθύνη δέσμευση μνήμης στον προγραμματιστή μέσω των συναρτήσεων **malloc()** και **free()**. Σε αντιδιαστολή, η **JAVA** αφήνει τον προγραμματιστεί να ορίσει όσα αντικείμενα επιθυμεί και δεσμεύει την μνήμη για αυτά μέσω του τελεστή **new**. | + | Οι γλώσσες προγραμματισμού που μέχρι τώρα έχετε γνωρίσει (βλέπε **C**) αναθέτουν την ευθύνη δέσμευσης μνήμης στον προγραμματιστή μέσω των συναρτήσεων **malloc()** και **free()**. Σε αντιδιαστολή, η **JAVA** αφήνει τον προγραμματιστεί να ορίσει όσα αντικείμενα επιθυμεί και δεσμεύει την μνήμη για αυτά μέσω του τελεστή **new**. |
- | + | ||
- | Περιοδικά το **JVM** κοιτάει εάν υπάρχουν αντικείμενα για τα οποία δεν υπάρχουν πλέον μεταβλητές που δείχνουν σε αυτά. Σε αυτές τις περιπτώσεις ελευθερώνει την μνήμη που έχει δεσμευτεί για τα αντικείμενα που εντόπισε. Ο μηχανισμός αυτός ονομάζεται **Garbage Collection** και απαντάται σε αρκετές γλώσσες υψηλού επιπέδου απελευθερώνοντας τον προγραμματιστή από την ευθύνη αποδέσμευσης της μνήμης που δεσμέυτηκε. | + | |
- | + | ||
- | Περισσότερα για την λειτουργία του Garbage Collector μπορείτε να βρείτε [[http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html|εδώ]]. | + | |
- | + | ||
- | + | ||
- | |Προηγούμενο: [[:java:class_methods | Μέθοδοι της Κλάσης ]] | Επόμενο: [[:java:this_operator | Oι τελεστές this και super ]]| | + | |
+ | Πώς όμως αποδεσμεύεται η μνήμη που δεσμεύτηκε προηγούμενα από το πρόγραμμα μας, αλλά δεν την χρειαζόμαστε πλέον; Περιοδικά το **JVM** κοιτάει εάν υπάρχει δεσμευμένη μνήμη για αντικείμενα στα οποία δεν υφίστανται πλέον αναφορές/references που δείχνουν σε αυτά. Σε αυτές τις περιπτώσεις, ελευθερώνεται η μνήμη που έχει δεσμευτεί για τα αντικείμενα αυτής της κατηγορίας. Παράλληλα η αποδέσμευση της μνήμης και η διαγραφή των αντικειμένων πιθανόν συνεπάγεται ότι και άλλα αντικείμενα δεν διαθέτουν πια αναφορές προς αυτά κ.ο.κ. Η διαδικασία συνεχίζεται μέχρι να αποδεσμευτεί όλη η δυναμικά δεσμευμένη μνήμη. | ||
+ | Ο μηχανισμός **Garbage Collection** απαντάται σε αρκετές γλώσσες υψηλού επιπέδου, απελευθερώνοντας τον προγραμματιστή από την ευθύνη αποδέσμευσης της μνήμης που δεσμεύτηκε προηγούμενα. Η ευθύνη της δεύσμευσης/αποδέσμευσης μνήμης δεν επαφίεται στον προγραμματιστή, πράγμα που κάνει λιγότερο επίπονο τον προγραμματισμό. | ||
+ | Περισσότερα για την λειτουργία του Garbage Collector και τις εναλλακτικές υλοποιήσεις μπορείτε να βρείτε [[http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html|εδώ]]. | ||
+ | |Προηγούμενο: [[:java:class_constructors | Κατασκευαστές της κλάσης ]] | [[:toc | Περιεχόμενα ]] | Επόμενο: [[:java:arrays | Πίνακες | ||
+ | ]]| | ||