This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
java:inner_classes [2016/02/11 14:38] gthanos [Δημιουργία αντικειμένων της εσωτερικής κλάσης από άλλες κλάσεις ή στατικές μεθόδους] |
java:inner_classes [2016/02/15 09:58] gthanos [Επαναορίζοντας (ή κρύβοντας..) τα πεδία της εξωτερικής κλάσης στην εσωτερική κλάση] |
||
---|---|---|---|
Line 147: | Line 147: | ||
</code> | </code> | ||
+ | |||
+ | Η διαδικασία δημιουργίας ενός αντικειμένου της εσωτερικής κλάσης θα μπορούσε να δημιουργηθεί σε μία στατική ή μη στατική μέθοδο άλλης κλάσης. Δείτε το παρακάτω παράδειγμα. | ||
<code java TestOuterClass.java> | <code java TestOuterClass.java> | ||
public class TestOuterClass { | public class TestOuterClass { | ||
- | public static void main(String args[]) { | + | public static void main(String []args) { |
- | OuterClass outer = new OuterClass(5); //line 3 | + | OuterClass outer = new OuterClass(10); |
- | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); //line 4 | + | System.out.println(outer); |
+ | OuterClass.InnerClass inner = outer.new InnerClass(4); //line 4 | ||
+ | System.out.println(inner.toString()); | ||
} | } | ||
} | } | ||
</code> | </code> | ||
- | Αρχικά, στην γραμμή 3 δείτε πως δημιουργούμε ένα αντικείμενο της κλάσης **OuterClass**. Στη συνέχεια με δεδομένο ότι έχουμε δημιουργήσει το αντικείμενο τύπου **OuterClass** στο οποίο δείχνει η μεταβλητή outer δημιουργούμε ένα νέο αντικείμενο της εσωτερικής κλάσης, όπως παρακάτω. Παρατηρήστε την ιδιαίτερη σύνταξη δημιουργίας αντικειμένων της εσωτερικής κλάσης. | + | Αρχικά, στην γραμμή 3 δημιουργούμε ένα αντικείμενο της κλάσης **OuterClass**. Στη συνέχεια με δεδομένο ότι έχουμε δημιουργήσει το αντικείμενο τύπου **OuterClass** στο οποίο δείχνει η μεταβλητή outer δημιουργούμε ένα νέο αντικείμενο της εσωτερικής κλάσης, όπως παρακάτω. Παρατηρήστε την ιδιαίτερη σύνταξη δημιουργίας αντικειμένων της εσωτερικής κλάσης. |
<code java> | <code java> | ||
- | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | + | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); |
</code> | </code> | ||
Line 171: | Line 175: | ||
} | } | ||
} | } | ||
+ | </code> | ||
+ | Σε αυτή την περίπτωση λαμβάνετε από τον μεταγλωττιστή ένα λάθος της μορφής | ||
+ | <code> | ||
+ | OuterClass.java:29: error: variable outer might not have been initialized | ||
+ | OuterClass.InnerClass inner = outer.new InnerClass(4); //line 4 | ||
+ | ^ | ||
+ | 1 error | ||
</code> | </code> | ||
Δοκιμάστε το. | Δοκιμάστε το. | ||
Line 246: | Line 257: | ||
Από το παραπάνω παράδειγμα, παρατηρούμε ότι η εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία και τις μεθόδους της εξωτερικής κλάσης, ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. | Από το παραπάνω παράδειγμα, παρατηρούμε ότι η εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία και τις μεθόδους της εξωτερικής κλάσης, ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. | ||
</WRAP> | </WRAP> | ||
- | ==== Κρύβοντας τα πεδία της εξωτερικής κλάσης ==== | ||
- | |||
- | Στο προηγούμενο παράδειγμα είδαμε την προσβασιμότητα στα πεδία και τις μεθόδους της εξωτερικής κλάσης. Τι γίνεται όμως όταν υπάρχει μία μέθοδος που καλεί μία άλλη μέθοδο η οποία υπάρχει τόσο στη εσωτερική όσο και στην εξωτερική κλάση. Σε αναλογία τι γίνεται όταν μία μέθοδος καλεί ένα πεδίο το οποίο υπάρχει στην εσωτερική και την εξωτερική κλάση; Το παρακάτω παράδειγμα απαντά στις παραπάνω απορίες. | ||
- | |||
- | <code java ShadowTest.java> | ||
- | public class ShadowTest { | ||
- | |||
- | public int x = 100; | ||
- | |||
- | class FirstLevel { | ||
- | |||
- | public int x = 200; | ||
- | |||
- | void methodInFirstLevel(int x) { | ||
- | System.out.println("x = " + x); | ||
- | System.out.println("this.x = " + this.x); | ||
- | System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); | ||
- | } | ||
- | | ||
- | String printX() { return "X in FirstLevel is "+x+" and "+ShadowTest.this.printX(); } | ||
- | } | ||
- | | ||
- | String printX() { return "X in ShadowTest is "+x; } | ||
- | |||
- | public static void main(String args[]) { | ||
- | ShadowTest st = new ShadowTest(); | ||
- | ShadowTest.FirstLevel fl = st.new FirstLevel(); | ||
- | fl.methodInFirstLevel(23); | ||
- | | ||
- | System.out.println(st.printX()); | ||
- | System.out.println(fl.printX()); | ||
- | } | ||
- | } | ||
- | </code> | ||
- | |||
- | ==== Χρήση προσδιοριστών πρόσβασης στην εσωτερική κλάση ==== | ||
- | |||
- | Στο προηγούμενο παράδειγμα δοκιμάστε να αλλάξετε τον προσδιοριστή πρόσβασης της κλάσης **InnerOuterClass** από package private σε private. Σε αυτή την περίπτωση θα παρατηρήσετε ότι η κλάση **TestOuterClass** δεν μεταγλωττίζεται. Συγκεκριμένα, o compiler εμφανίζει το παρακάτω μήνυμα λάθους, σημειώνοντας ότι ο προσδιοριστής πρόσβασης **private** δεν επιτρέπει τη πρόσβαση από μία άλλη κλάση στο συγκεκριμένο περιεχόμενο της **OuterClass**. Γενικότερα, ισχύουν οι κανόνες για τους προσδιοριστές πρόσβασης όπως αυτοί αναφέρονται [[java:access_modifiers|εδώ]]. | ||
- | |||
- | <code> | ||
- | TestOuterClass.java:6: error: OuterClass.InnerOuterClass has private access in OuterClass | ||
- | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | ||
- | ^ | ||
- | TestOuterClass.java:6: error: OuterClass.InnerOuterClass has private access in OuterClass | ||
- | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | ||
- | </code> | ||
- | |||
- | <WRAP tip 80% center round> | ||
- | Το παραπάνω εξηγεί ικανοποιήτικα τον λόγο που πιθανόν να θέλετε να βάλετε ένα "περιοριστικό" προσδιοριστή πρόσβασης σε μία εσωτερική κλάση (συνήθως //private//). Ο λόγος είναι ότι με τον εν λόγο προσδιοριστή πρόσβασης αποκλείετε τη πρόσβαση στην εσωτερική κλάση από άλλες κλάσεις, κρύβοντας τον κώδικα που αφορά μόνο την συγκεκριμένη εξωτερική κλάση. | ||
- | </WRAP> | ||
- | |||
===== Πρόσβαση από την εξωτερική κλάση σε πεδία της εσωτερικής κλάσης ===== | ===== Πρόσβαση από την εξωτερική κλάση σε πεδία της εσωτερικής κλάσης ===== | ||
Line 336: | Line 296: | ||
</code> | </code> | ||
- | Όπως θα παρατηρήσετε αν μεταγλωττίσετε και εκτελέσετε το πρόγραμμα η εξωτερική κλάση έχει απόλυτη πρόσβαση στα πεδία και τις μεθόδους της εσωτερικής κλάσης ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. | + | Όπως θα παρατηρήσετε αν μεταγλωττίσετε και εκτελέσετε το πρόγραμμα η εξωτερική κλάση έχει απόλυτη πρόσβαση στα πεδία και τις μεθόδους της εσωτερικής κλάσης ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. Η διαφορά ανάμεσα στην πρόσβαση της εξωτερικής κλάσης στα πεδία της εσωτερικής γίνεται μέσω ενός αντικειμένου της εξωτερικής κλάσης. |
<WRAP important 80% center round> | <WRAP important 80% center round> | ||
* H εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εξωτερικής κλάσης. | * H εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εξωτερικής κλάσης. | ||
- | * Η εξωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εσωτερικής κλάσης. | + | * Η εξωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εσωτερικής κλάσης. Η πρόσβαση στα πεδία αυτά γίνεται μέσω ενός αντικειμένου της εξωτερικής κλάσης. |
Οι προσδιοριστές πρόσβασης **δεν εισάγουν κανένα περιορισμό** στον προσδιορισμό της προσβασιμότητας των πεδίων και των μεθόδων της εσωτερικής κλάσης από την εξωτερική κλάση και αντίστροφα. | Οι προσδιοριστές πρόσβασης **δεν εισάγουν κανένα περιορισμό** στον προσδιορισμό της προσβασιμότητας των πεδίων και των μεθόδων της εσωτερικής κλάσης από την εξωτερική κλάση και αντίστροφα. | ||
</WRAP> | </WRAP> | ||
Line 351: | Line 311: | ||
public class OuterClass { | public class OuterClass { | ||
int outer; | int outer; | ||
- | InnerOuterClass innerObj; | + | InnerClass innerObj; |
public OuterClass(int o) { | public OuterClass(int o) { | ||
outer = o; | outer = o; | ||
- | innerObj = new InnerOuterClass(); | + | innerObj = new InnerClass(); |
innerObj.innerPriv = 10; | innerObj.innerPriv = 10; | ||
innerObj.innerProt = 20; | innerObj.innerProt = 20; | ||
Line 362: | Line 322: | ||
} | } | ||
- | class InnerOuterClass { | + | class InnerClass { |
private int innerPriv; | private int innerPriv; | ||
protected int innerProt; | protected int innerProt; | ||
Line 383: | Line 343: | ||
public static void main(String args[]) { | public static void main(String args[]) { | ||
OuterClass outer = new OuterClass(5); | OuterClass outer = new OuterClass(5); | ||
- | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(); | + | OuterClass.InnerClass inner = outer.new InnerClass(); |
inner.setInnerPriv(4); | inner.setInnerPriv(4); | ||
inner.setInnerProt(5); | inner.setInnerProt(5); | ||
Line 396: | Line 356: | ||
- Με την προϋπόθεση ότι ισχύει το **1.**, ισχύουν οι [[java:access_modifiers|κανόνες προσβασιμότητας]] που ορίζονται από προσδιοριστές πρόσβασης. | - Με την προϋπόθεση ότι ισχύει το **1.**, ισχύουν οι [[java:access_modifiers|κανόνες προσβασιμότητας]] που ορίζονται από προσδιοριστές πρόσβασης. | ||
+ | ==== Χρήση προσδιοριστών πρόσβασης στην εσωτερική κλάση ==== | ||
+ | |||
+ | Στο προηγούμενο παράδειγμα δοκιμάστε να αλλάξετε τον προσδιοριστή πρόσβασης της κλάσης **InnerClass** από package private σε private. Σε αυτή την περίπτωση θα παρατηρήσετε ότι η κλάση **TestOuterClass** δεν μεταγλωττίζεται. Συγκεκριμένα, o compiler εμφανίζει το παρακάτω μήνυμα λάθους, σημειώνοντας ότι ο προσδιοριστής πρόσβασης **private** δεν επιτρέπει τη πρόσβαση από μία άλλη κλάση στο συγκεκριμένο περιεχόμενο της **OuterClass**. Γενικότερα, ισχύουν οι κανόνες για τους προσδιοριστές πρόσβασης όπως αυτοί αναφέρονται [[java:access_modifiers|εδώ]]. | ||
+ | |||
+ | <code> | ||
+ | TestOuterClass.java:6: error: OuterClass.InnerOuterClass has private access in OuterClass | ||
+ | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | ||
+ | ^ | ||
+ | TestOuterClass.java:6: error: OuterClass.InnerOuterClass has private access in OuterClass | ||
+ | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | ||
+ | </code> | ||
+ | |||
+ | <WRAP tip 80% center round> | ||
+ | Το παραπάνω εξηγεί ικανοποιητικά τον τρόπο με τον οποίο μπορείτε να αποκλείσετε την πρόσβαση στην εσωτερική κλάση από άλλες κλάσεις πέραν της εξωτερικής. Ορίζοντας την εσωτερική κλάση ως **private** αυτή είναι προσβάσιμη μόνο από την εξωτερική της κλάση. | ||
+ | </WRAP> | ||
+ | |||
+ | ==== Επαναορίζοντας (ή κρύβοντας..) τα πεδία της εξωτερικής κλάσης στην εσωτερική κλάση ==== | ||
+ | |||
+ | Στο προηγούμενο παράδειγμα είδαμε την προσβασιμότητα στα πεδία και τις μεθόδους της εξωτερικής κλάσης. Τι γίνεται όμως όταν υπάρχει μία μέθοδος που καλεί μία άλλη μέθοδο η οποία υπάρχει τόσο στη εσωτερική όσο και στην εξωτερική κλάση. Σε αναλογία τι γίνεται όταν μία μέθοδος καλεί ένα πεδίο το οποίο υπάρχει στην εσωτερική και την εξωτερική κλάση; Το παρακάτω παράδειγμα απαντά στις παραπάνω απορίες. | ||
+ | |||
+ | <code java ShadowTest.java> | ||
+ | public class ShadowTest { | ||
+ | |||
+ | public int x = 100; | ||
+ | |||
+ | class FirstLevel { | ||
+ | |||
+ | public int x = 200; | ||
+ | |||
+ | void methodInFirstLevel(int x) { | ||
+ | System.out.println("x = " + x); | ||
+ | System.out.println("this.x = " + this.x); | ||
+ | System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); | ||
+ | } | ||
+ | | ||
+ | String printX() { return "X in FirstLevel is "+x+" and "+ShadowTest.this.printX(); } | ||
+ | } | ||
+ | | ||
+ | String printX() { return "X in ShadowTest is "+x; } | ||
+ | |||
+ | public static void main(String args[]) { | ||
+ | ShadowTest st = new ShadowTest(); | ||
+ | ShadowTest.FirstLevel fl = st.new FirstLevel(); | ||
+ | fl.methodInFirstLevel(23); | ||
+ | | ||
+ | System.out.println(st.printX()); | ||
+ | System.out.println(fl.printX()); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |Προηγούμενο: [[ :java:static_nested_classes| Στατικές εμφωλευμένες κλάσεις ]] | Επόμενο: [[ :java:local_inner_classes | Τοπικές εμφωλευμένες κλάσεις ]]| |