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:28] gthanos |
java:inner_classes [2016/02/15 09:58] gthanos [Επαναορίζοντας (ή κρύβοντας..) τα πεδία της εξωτερικής κλάσης στην εσωτερική κλάση] |
||
---|---|---|---|
Line 83: | Line 83: | ||
InnerClass ic; | InnerClass ic; | ||
- | public OuterInnerClass(int field) { | + | public OuterClass(int field) { |
outerClassField = field; | outerClassField = field; | ||
ic = new InnerClass(field*2); | ic = new InnerClass(field*2); | ||
Line 96: | Line 96: | ||
} | } | ||
| | ||
- | String toString() { | + | public String toString() { |
return "outerClassField: "+outerClassField+", innerClassField: "+ic.innerClassField; | return "outerClassField: "+outerClassField+", innerClassField: "+ic.innerClassField; | ||
} | } | ||
Line 102: | Line 102: | ||
public static void main(String []args) { | public static void main(String []args) { | ||
OuterClass outer = new OuterClass(10); | OuterClass outer = new OuterClass(10); | ||
+ | System.out.println(outer); | ||
} | } | ||
} | } | ||
+ | |||
</code> | </code> | ||
==== Δημιουργία αντικειμένων της εσωτερικής κλάσης από άλλες κλάσεις ή στατικές μεθόδους ==== | ==== Δημιουργία αντικειμένων της εσωτερικής κλάσης από άλλες κλάσεις ή στατικές μεθόδους ==== | ||
- | Κατ' αρχήν, το πρώτο το οποίο θα πρέπει να σημειώσουμε είναι ότι ένα αντικείμενο της εσωτερικής κλάσης μπορεί να δημιουργηθεί **ΜΟΝΟ ΕΦΟΣΟΝ** υπάρχει ένα αντικείμενο της εξωτερικής κλάσης. Επομένως, για να δημιουργήσετε ένα αντικείμενο της εσωτερικής κλάσης θα πρέπει να έχετε ήδη ένα αντικείμενο της εξωτερικής κλάσης. Δείτε το παρακάτω παράδειγμα. | + | Προηγούμενα αναφέρθηκε ότι για να δημιουργηθεί ένα αντικείμενο της εσωτερικής κλάσης θα πρέπει να υπάρχει ένα αντικείμενο της εξωτερικής κλάσης. Δείτε πως μπορείτε να δημιουργήσετε σε μία στατική μέθοδο (//όπως είναι η μέθοδος **main**//) ένα αντικείμενο της εσωτερικής κλάσης με βάση την εξωτερική κλάση. |
<code java OuterClass.java> | <code java OuterClass.java> | ||
public class OuterClass { | public class OuterClass { | ||
- | int outer; | + | int outerClassField; |
+ | InnerClass ic; | ||
- | public OuterClass(int o) { | + | public OuterClass(int field) { |
- | outer = o; | + | outerClassField = field; |
+ | ic = new InnerClass(field*2); | ||
} | } | ||
- | + | | |
- | class InnerOuterClass { | + | class InnerClass { |
- | int inner; | + | int innerClassField; |
+ | |||
+ | public InnerClass(int field) { | ||
+ | innerClassField = field; | ||
+ | } | ||
| | ||
- | public InnerOuterClass(int o) { | + | public String toString() { |
- | inner = o; | + | return "[innerClassField: "+innerClassField+"]"; |
} | } | ||
} | } | ||
| | ||
+ | public String toString() { | ||
+ | return "outerClassField: "+outerClassField+" "+ic.toString(); | ||
+ | } | ||
+ | | ||
+ | public static void main(String []args) { | ||
+ | OuterClass outer = new OuterClass(10); | ||
+ | System.out.println(outer); | ||
+ | OuterClass.InnerClass inner = outer.new InnerClass(4); //line 4 | ||
+ | System.out.println(inner.toString()); | ||
+ | } | ||
} | } | ||
+ | |||
</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 152: | 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 227: | 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 317: | Line 296: | ||
</code> | </code> | ||
- | Όπως θα παρατηρήσετε αν μεταγλωττίσετε και εκτελέσετε το πρόγραμμα η εξωτερική κλάση έχει απόλυτη πρόσβαση στα πεδία και τις μεθόδους της εσωτερικής κλάσης ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. | + | Όπως θα παρατηρήσετε αν μεταγλωττίσετε και εκτελέσετε το πρόγραμμα η εξωτερική κλάση έχει απόλυτη πρόσβαση στα πεδία και τις μεθόδους της εσωτερικής κλάσης ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. Η διαφορά ανάμεσα στην πρόσβαση της εξωτερικής κλάσης στα πεδία της εσωτερικής γίνεται μέσω ενός αντικειμένου της εξωτερικής κλάσης. |
<WRAP important 80% center round> | <WRAP important 80% center round> | ||
* H εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εξωτερικής κλάσης. | * H εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εξωτερικής κλάσης. | ||
- | * Η εξωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εσωτερικής κλάσης. | + | * Η εξωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εσωτερικής κλάσης. Η πρόσβαση στα πεδία αυτά γίνεται μέσω ενός αντικειμένου της εξωτερικής κλάσης. |
Οι προσδιοριστές πρόσβασης **δεν εισάγουν κανένα περιορισμό** στον προσδιορισμό της προσβασιμότητας των πεδίων και των μεθόδων της εσωτερικής κλάσης από την εξωτερική κλάση και αντίστροφα. | Οι προσδιοριστές πρόσβασης **δεν εισάγουν κανένα περιορισμό** στον προσδιορισμό της προσβασιμότητας των πεδίων και των μεθόδων της εσωτερικής κλάσης από την εξωτερική κλάση και αντίστροφα. | ||
</WRAP> | </WRAP> | ||
Line 332: | 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 343: | Line 322: | ||
} | } | ||
- | class InnerOuterClass { | + | class InnerClass { |
private int innerPriv; | private int innerPriv; | ||
protected int innerProt; | protected int innerProt; | ||
Line 364: | 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 377: | 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 | Τοπικές εμφωλευμένες κλάσεις ]]| |