java:objects

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Next revision Both sides next revision
java:objects [2015/01/22 08:30]
gthanos created
java:objects [2017/02/16 10:53]
gthanos [Garbage Collection]
Line 1: Line 1:
-====== Δημιουργώντας Αντικείμενα ======+====== Δημιουργία Αντικειμένων ======
  
-Μέχρι τώρα αναφέραμε ότι η κλάση είναι το βασικό σχέδιο μέσα από το οποίο δημιουργούνται επιμέρους αντικείμενα που φέρουν τα χαρακτηριστικά της κλάσης. Επίσης,​ δείξαμε πως ορίζουμε μία κλάση μέσα απο παραδείγματα,​ αλλά δεν δείξαμε πως δημιουργούμε αντικείμενα από τις κλάσεις που ορίσαμε. ​+Μέχρι τώρα αναφέραμε ​στην [[ oop:​introduction | "​Εισαγωγή στον Αντικειμενοστραφή Προγραμματισμό"​ ]] ότι η κλάση είναι το βασικό σχέδιο μέσα από το οποίο δημιουργούνται επιμέρους αντικείμενα που φέρουν τα χαρακτηριστικά της κλάσης. Επίσης,​ δείξαμε πως ορίζουμε μία κλάση μέσα από παραδείγματα,​ αλλά δεν δείξαμε πως δημιουργούμε αντικείμενα από τις κλάσεις που ορίσαμε. ​
  
-Παρακάτω δίνεται ​ένα πρόγραμμα ​που δημιουργεί συγκεκριμένα αντικείμενα και εκτυπώνει τα αποτελέσματα στην κονσόλα.+Παρακάτω δίνεται ​η κλάση **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; +      = xPos
-   ​+      = 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 35:
 <code java Rectangle.java>​ <code java Rectangle.java>​
 public class Rectangle { public class Rectangle {
-   private int widthheight; +     
-   ​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) { 
-   ​public void setOrigin(Point p) { +    width = initWidth
-      ​origin ​p+    height = initHeight
-   ​+    ​origin = new Point(0,​0);​ 
-   ​ +  ​
-   ​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 move(int dx, int dy) {
 +    origin.setX( origin.getX() + dx );
 +    origin.setY( origin.getY() + dy );
 +  }
 } }
 </​code>​ </​code>​
Line 84: Line 98:
         // Declare and create a point object and two rectangle objects.         // Declare and create a point object and two rectangle objects.
         Point originOne = new Point(23, 94);         Point originOne = new Point(23, 94);
-        Rectangle rectOne = new Rectangle(originOne, ​100, 200);+        Rectangle rectOne = new Rectangle(100,​ 200, originOne);
         Rectangle rectTwo = new Rectangle(50,​ 100);         Rectangle rectTwo = new Rectangle(50,​ 100);
   
Line 105: Line 119:
     }     }
 } }
 +</​code>​
 +
 +Για να μεταγλωτίσουμε τα παραπάνω πρόγραμμα αρκεί να γράψουμε
 +
 +<​code>​
 +javac Point.java ​             // μεταγλώττιση της κλάσης Point
 +javac Rectange.java ​          // μεταγλώττιση της κλάσης Rectangle
 +javac CreateObjectDemo.java ​  // μεταγλώττιση της κλάσης CreateObjectDemo
 +</​code>​
 +
 +και για να το τρέξουμε γράφουμε
 +
 +<​code>​
 +java CreateObjectDemo
 </​code>​ </​code>​
  
Line 119: Line 147:
 </​code>​ </​code>​
  
-Από τα πάραπάνω αξίζει να προσέξουμε τα εξής.+Από τα παραπάνω αξίζει να προσέξουμε τα εξής. 
 +  - Εκτελούμε την κλάση η οποία περιέχει την μέθοδο **main** η οποία εκκινεί την εκτέλεση του προγράμματος <​code>​public static void main(String[] args) { .... } </​code>​
   - Η κλάση Rectangle έχει δύο κατασκευαστές οι οποίοι καλούνται εναλλάξ στη συνάρτηση **main** προκειμένου να αρχικοποιήσουν τα αντικείμενα (**objects**) ''​rectOne''​ και ''​rectTwo''​.   - Η κλάση Rectangle έχει δύο κατασκευαστές οι οποίοι καλούνται εναλλάξ στη συνάρτηση **main** προκειμένου να αρχικοποιήσουν τα αντικείμενα (**objects**) ''​rectOne''​ και ''​rectTwo''​.
 +  - Κάθε κατασκευαστής φροντίζει να αρχικοποιεί όλα τα πεδία, ακόμη και αυτά για τα οποία δεν υπάρχει αντίστοιχη παράμετρος.
   - H συνάρτηση ''​System.out.println()''​ εκτυπώνει ένα αλφαριθμητικό (string) ακολουθούμενο από χαρακτήρα αλλαγής γραμμής.   - H συνάρτηση ''​System.out.println()''​ εκτυπώνει ένα αλφαριθμητικό (string) ακολουθούμενο από χαρακτήρα αλλαγής γραμμής.
  
Line 128: Line 158:
 <code java> <code java>
 Point originOne = new Point(23, 94); Point originOne = new Point(23, 94);
-Rectangle rectOne = new Rectangle(originOne, ​100, 200);+Rectangle rectOne = new Rectangle(100,​ 200, originOne);
 Rectangle rectTwo = new Rectangle(50,​ 100); Rectangle rectTwo = new Rectangle(50,​ 100);
 </​code>​ </​code>​
Line 138: Line 168:
  
 originOne = new Point(23, 94); originOne = new Point(23, 94);
-rectOne = new Rectangle(originOne, ​100, 200);+rectOne = new Rectangle(100,​ 200, originOne);
 rectTwo = new Rectangle(50,​ 100); rectTwo = new Rectangle(50,​ 100);
 </​code>​ </​code>​
  
-Οι πρώτες δύο γραμμές ορίζουν τις μεταλητές ''​originOne'',​ ''​rectOne'',​ ''​rectTwo''​. Οι μεταβλητές δυνητικά δείχνουν σε τύπους δεδομένων Point, ​Rectange, Rectangle. Προς το παρόν όμως το περιεχόμενο των μεταβλητών αυτών είναι απροσδιόριστο (undefined). Σε αναλογία με την γλώσσα ​φανταστείτε τις μεταβλητές αυτές ως pointers που δεν είναι αρχικοποιημένοι σε κάποια υφιστάμενη διεύθυνση μνήμης. Η τιμή τους είναι απροσδιόριστη και η προσπάθεια να γράψουμε στη διεύθυνση μνήμης που δείχνουν θα προκαλάσει Segmentation Fault. Η παρακάτω εικόνα δείχνει την ύπαρξη ενός μη αρχικοποιημένου δείκτη.+Οι πρώτες δύο γραμμές ορίζουν τις μεταλητές ''​originOne'',​ ''​rectOne'',​ ''​rectTwo''​. Οι μεταβλητές δυνητικά δείχνουν σε τύπους δεδομένων Point, ​Rectangle, Rectangle. Προς το παρόν όμως το περιεχόμενο των μεταβλητών αυτών είναι απροσδιόριστο (στην πραγματικότητα ο compiler αρχικοποεί τις μεταβλητές αυτές στην τιμή **null**).  
 + 
 +//__Σε αναλογία με την γλώσσα ​C__, φανταστείτε τις μεταβλητές αυτές ως pointers που δεν είναι αρχικοποιημένοι σε κάποια υφιστάμενη διεύθυνση μνήμης. Η τιμή τους είναι απροσδιόριστη και η προσπάθεια να γράψουμε στη διεύθυνση μνήμης ​όπου δείχνουν θα προκαλέσει Segmentation Fault.//  
 + 
 +Η παρακάτω εικόνα δείχνει την ύπαρξη ενός μη αρχικοποιημένου δείκτη.
  
 {{ :​java:​reference-variables-01.png |}} {{ :​java:​reference-variables-01.png |}}
  
 Προκειμένου να αρχικοποιηθούν οι μεταβλητές αυτές απαιτούνται δύο βήματα:​ Προκειμένου να αρχικοποιηθούν οι μεταβλητές αυτές απαιτούνται δύο βήματα:​
-  - Η δέσμευση της απαραίτητης μνήμης,​ ώστε να μπορούμε να αποθηκεύσουμε τα δεδομένα που προδιαγράφονται απο τον συγκεκριμένο τύπο (κλάση).+  - Η δέσμευση της απαραίτητης μνήμης,​ ώστε να μπορούμε να αποθηκεύσουμε τα δεδομένα που προδιαγράφονται από τον συγκεκριμένο τύπο (κλάση).
   - Η αρχικοποίηση των επιμέρους μεταβλητών των αντικειμένων που ορίζονται απο την εκάστοτε κλάση.   - Η αρχικοποίηση των επιμέρους μεταβλητών των αντικειμένων που ορίζονται απο την εκάστοτε κλάση.
  
Line 156: Line 190:
 Ο παρακάτω κώδικας Ο παρακάτω κώδικας
  
-<code java>​rectOne = new Rectangle(originOne, ​100, 200);</​code> ​+<code java>​rectOne = new Rectangle(100,​ 200, originOne);</​code> ​
  
 δηλώνει την δέσμευση μνήμης για ένα αντικείμενο τύπου ''​Rectangle''​ όπου το σημείο της αρχής του είναι το σημείο ''​originOne''​. Επίσης ορίζονται οι τιμές των **width** και **height** σε 100 και 200 αντίστοιχα. O παραπάνω ορισμός σημαίνει ένα αρχικοποιημένο αντικείμενο μπορεί να έχει πολλούς δείκτες προς αυτό, όπως δείχνει το παρακάτω σχήμα. δηλώνει την δέσμευση μνήμης για ένα αντικείμενο τύπου ''​Rectangle''​ όπου το σημείο της αρχής του είναι το σημείο ''​originOne''​. Επίσης ορίζονται οι τιμές των **width** και **height** σε 100 και 200 αντίστοιχα. O παραπάνω ορισμός σημαίνει ένα αρχικοποιημένο αντικείμενο μπορεί να έχει πολλούς δείκτες προς αυτό, όπως δείχνει το παρακάτω σχήμα.
Line 168: Line 202:
   - Αρχικοποίηση των εσωτερικών μεταβλητών (πεδίων) του αντικειμένου με κλήση του κατάλληλου κατασκευαστή της κλάσης. Εάν δεν έχει οριστεί κατασκευαστής τότε ο τελεστής new καλείται με χρήση του default κατασκευαστή (default constructor) που δεν έχει ορίσματα (π.χ. ''​MyObject obj = new MyObject();'',​ όπου για την κλάση ''​MyObject''​ δεν έχει οριστεί κανένας κατασκευατής).   - Αρχικοποίηση των εσωτερικών μεταβλητών (πεδίων) του αντικειμένου με κλήση του κατάλληλου κατασκευαστή της κλάσης. Εάν δεν έχει οριστεί κατασκευαστής τότε ο τελεστής new καλείται με χρήση του default κατασκευαστή (default constructor) που δεν έχει ορίσματα (π.χ. ''​MyObject obj = new MyObject();'',​ όπου για την κλάση ''​MyObject''​ δεν έχει οριστεί κανένας κατασκευατής).
  
-<WRAP tip>+<WRAP tip 80% center round>
 Κατά την χρήση **primitive** τύπων δεδομένων (int, float, double) δεν απαιτείται η χρήση του τελεστή **new** διότι η απαραίτητη μνήμη δεσμεύεται στο stack της μεθόδου που εκτελείται. ​ Κατά την χρήση **primitive** τύπων δεδομένων (int, float, double) δεν απαιτείται η χρήση του τελεστή **new** διότι η απαραίτητη μνήμη δεσμεύεται στο stack της μεθόδου που εκτελείται. ​
 </​WRAP>​ </​WRAP>​
Line 174: Line 208:
 ===== Πολλαπλοί κατασκευαστές σε μία κλάση ===== ===== Πολλαπλοί κατασκευαστές σε μία κλάση =====
  
-Μία κλάση μπορεί να έχει πολλούς διαφορετικούς. Κάθε κατασκευαστής ορίζει μία διαφορετική αρχικοποίηση των εσωτερικών μεταβλητών των αντικειμένων που δημιουργούντια με βάση το "​σχέδιο"​ της κλάσης. Το ποιός κατασκευαστής θα κληθεί εξαρτάται από τον τύπο, τη σειρά και τον αριθμό των ορισμάτων σε αναλογία με την υπερφόρτωση ​συναρτήσεων. Έτσι στη συνάρτηση main του παραδείγματος μας καλούνται δύο διαφορετικοί κατασκευαστές για δύο διαφορετικά αντικείμενα της ίδιας κλάσης.+Μία κλάση μπορεί να έχει πολλούς διαφορετικούς κατασκευαστές. Κάθε κατασκευαστής ορίζει μία διαφορετική αρχικοποίηση των εσωτερικών μεταβλητών των αντικειμένων που δημιουργούνται με βάση το "​σχέδιο"​ της κλάσης. Το ποιός κατασκευαστής θα κληθεί εξαρτάται από τον τύπο, τη σειρά και τον αριθμό των ορισμάτων σε αναλογία με την υπερφόρτωση ​μεθόδων. Έτσι στη συνάρτηση ​**main** του παραδείγματος μας καλούνται δύο διαφορετικοί κατασκευαστές για δύο διαφορετικά αντικείμενα της ίδιας κλάσης.
  
 <code java> <code java>
-rectOne = new Rectangle(originOne, ​100, 200);+rectOne = new Rectangle(100,​ 200, originOne);
 rectTwo = new Rectangle(50,​ 100); rectTwo = new Rectangle(50,​ 100);
 </​code>​ </​code>​
Line 190: Line 224:
  
 <code java> <code java>
-                          ​// cadencespeed, gear +   // fields are widthheight 
-   Bicycle bicycle ​= new Bicycle(10, 20, 30); +   Rectangle rect = new Rectangle(10,20); 
-   ​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>​
  
Line 208: Line 242:
  
 <code java> <code java>
-                          ​// cadencespeed, gear +   // fields are widthheight 
-   Bicycle bicycle ​= new Bicycle(10, 20, 30); +   Rectangle rect = new Rectangle(10,20); 
-   ​System.out.println("​Bicycle speed is " + bicycle.getSpeed() );+   ​System.out.println("​Rectangle dimensions are " + rect.getWidth() + ", ​" + rect.getHeight() );
 </​code>​ </​code>​
  
-<WRAP important>​+<WRAP important ​80% center round>
 Ισχύουν και για τις μεθόδους όσα αναφέρονται για τους προσδιοριστές τύπου **public**, **private** των πεδίων. Ισχύουν και για τις μεθόδους όσα αναφέρονται για τους προσδιοριστές τύπου **public**, **private** των πεδίων.
 </​WRAP>​ </​WRAP>​
Line 219: Line 253:
 ===== Garbage Collection ===== ===== Garbage Collection =====
  
-Οι γλώσσες υψηλού επιπέδου ​που μέχρι τώρα έχετε γνωρίσει ​(**C**) ​αναθέτους ​την ευθύνη δέσμευση μνήμης στον προγραμματιστή μέσω των συναρτήσεων **malloc()** και **free()**. Σε αντιδιαστολή,​ η **JAVA** αφήνει τον προγραμματιστεί να ορίσει όσα αντικείμενα επιθυμεί και δεσμεύει την μνήμη για αυτά μέσω του τελεστή **new**.+Η γλώσσα **C** που μέχρι τώρα έχετε γνωρίσει αναθέτει την ευθύνη δέσμευσης μνήμης στον προγραμματιστή μέσω των συναρτήσεων **malloc()** και **free()**. Σε αντιδιαστολή,​ η **JAVA** αφήνει τον προγραμματιστεί να ορίσει όσα αντικείμενα επιθυμεί και δεσμεύει την μνήμη για αυτά μέσω του τελεστή **new**
 + 
 +Πώς όμως αποδεσμεύεται η μνήμη που δεσμεύτηκε προηγούμενα από το πρόγραμμα μας, αλλά δεν την χρειαζόμαστε πλέον; Αν η μνήμη δεν αποδεσμεύεται και το πρόγραμμα μας τρέξει για αρκετή ώρα δεσμεύοντας διαρκώς μνήμη, τότε είναι σίγουρο ότι θα το τερματίσει το λειτουργικό σύστημα. Η απάντηση,​ όσον αφορά την αποδέσμευση μνήμης στη Java γίνεται μέσω του μηχανισμού **Garbage Collection** και επεξηγείται εν συντομία παρακάτω. 
 + 
 +Περιοδικά το **JVM** κοιτάει εάν υπάρχει δεσμευμένη μνήμη για αντικείμενα στα οποία δεν υφίστανται πλέον μεταβλητές που δείχνουν σε αυτά, δηλαδή δεν υφίστανται αναφορές (//​references//​) προς αυτά. Σε αυτές τις περιπτώσεις,​ ελευθερώνεται η μνήμη που έχει δεσμευτεί για τα αντικείμενα αυτή της κατηγορίας. Παράλληλα η αποδέσμευση της μνήμης και η διαγραφή των αντικειμένων πιθανόν συνεπάγεται ότι και άλλα αντικείμενα δεν διαθέτουν πια αναφορές προς αυτά κ.ο.κ. Η διαδικασία συνεχίζεται μέχρι να αποδεσμευτεί όλη η δυναμικά δεσμευμένη μνήμη
  
-Περιοδικά το **JVM** κοιτάει εάν υπάρχουν αντικείμενα για τα οποία δεν υπάρχουν πλέον μεταβλητές που δείχνουν σε αυτά. Σε αυτές τις περιπτώσεις ελευθερώνει την μνήμη που έχει δεσμευτεί για τα αντικείμενα που εντόπισε. ​Ο μηχανισμός ​αυτός ονομάζεται ​**Garbage Collection** ​και ​απαντάται σε αρκετές γλώσσες υψηλού επιπέδου απελευθερώνοντας τον προγραμματιστή από την ευθύνη αποδέσμευσης της μνήμης που δεσμέυτηκε.+Ο μηχανισμός **Garbage Collection** απαντάται σε αρκετές γλώσσες υψηλού επιπέδουαπελευθερώνοντας τον προγραμματιστή από την ευθύνη αποδέσμευσης της μνήμης που δεσμεύτηκε προηγούμενα. Η ευθύνη της αποδέσμευσης μνήμης επαφίεται στο Garbage Collector, πράγμα που ​κάνει λιγότερο επίπονο τον προγραμματισμό
  
-Περισσότερα για την λειτουργία του Garbage Collector μπορείτε να βρείτε [[http://​www.oracle.com/​webfolder/​technetwork/​tutorials/​obe/​java/​gc01/​index.html|εδώ]].+Φυσικά η δυνατότητα του **Garbage Collection** συνεπάγεται ότι ένα παράλληλο νήμα, τρέχει περιοδικά και ελευθερώνει την μνήμη, πράγμα που πιθανόν να εισάγει καθυστερήσεις σε συγκεκριμένες εφαρμογές. Σε προγράμματα που απαιτούν πολύ υψηλές επιδόσεις ή έχουν ​αυστηρούς περιορισμούς ως προς τον χρόνο εκτέλεσης ​τους, η παράλληλη εκτέλεση ​του Garbage Collector μπορεί να εισάγει μη αποδεκτή καθυστέρηση.
  
 +Περισσότερα για την λειτουργία του Garbage Collector και τις εναλλακτικές υλοποιήσεις μπορείτε να βρείτε [[http://​www.oracle.com/​webfolder/​technetwork/​tutorials/​obe/​java/​gc01/​index.html|εδώ]].
  
-|Προηγούμενο:​ [[:java:class_methods ​Μέθοδοι ​της ​Κλάσης ]] | Επόμενο:​ [[:​java:​this_operator | Oι τελεστές this και super ]]|+|Προηγούμενο:​ [[:java:class_constructors ​Κατασκευαστές της ​κλάσης ​]] |  [[:toc | Περιεχόμενα ​]] | Επόμενο:​ [[:​java:​this_operator | O τελεστής this ]]|
  
  
java/objects.txt · Last modified: 2018/02/16 16:03 by gthanos