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 21:30] gthanos [Κρύβοντας τα πεδία της εξωτερικής κλάσης στην εσωτερική κλάση] |
java:inner_classes [2019/04/02 20:20] gthanos |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== Μη στατικές εμφωλευμένες κλάσεις ====== | ====== Μη στατικές εμφωλευμένες κλάσεις ====== | ||
| - | Οι μη στατικές εμφωλευμένες κλάσεις ή εσωτερικές κλάσεις (inner classes) αποτελούν την γενικότερη περίπτωση εμφώλευσης μίας κλάσης μέσα σε μία άλλη κλάση. | + | Οι μη στατικές εμφωλευμένες κλάσεις ή εσωτερικές κλάσεις (inner classes) αποτελούν την γενικότερη περίπτωση εμφώλευσης μίας κλάσης μέσα σε μία άλλη κλάση. |
| + | Η λίστα θα χρειαστεί | ||
| + | - την κλάση που περιγράφει τον κόμβο της λίστας και | ||
| + | - μία κλάση τύπου // | ||
| + | Οι δύο παραπάνω κλάσεις εξυπηρετεί να δηλωθούν ως εσωτερικές κλάσεις αποκρύπτοντας την | ||
| - | <code java DataStructure.java> | + | <code java LinkedList.java> |
| - | public class DataStructure | + | public class LinkedList< |
| + | private Node< | ||
| | | ||
| - | | + | public |
| - | private final static int SIZE = 15; | + | |
| - | private int[] arrayOfInts = new int[SIZE]; | + | |
| - | + | | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | arrayOfInts[i] = i; | + | |
| - | | + | |
| } | } | ||
| | | ||
| - | | + | |
| - | | + | |
| - | // Print out values of even indices of the array | + | |
| - | DataStructureIterator iterator = this.new EvenIterator(); | + | |
| - | while (iterator.hasNext()) { | + | |
| - | System.out.print(iterator.next() + " "); | + | |
| - | | + | |
| - | System.out.println(); | + | |
| - | } | + | |
| | | ||
| - | interface DataStructureIterator extends java.util.Iterator<Integer> { } | + | public Node(Node<E> nxt, Node<E> prv, E elem) { |
| - | + | | |
| - | // Inner class implements the DataStructureIterator interface, | + | |
| - | // which extends the Iterator<Integer> interface | + | |
| - | + | ||
| - | private class EvenIterator implements DataStructureIterator { | + | |
| - | + | ||
| - | // Start stepping through the array from the beginning | + | |
| - | private int nextIndex = 0; | + | |
| - | + | ||
| - | public boolean hasNext() { | + | |
| - | | + | |
| - | // Check if the current element is the last in the array | + | |
| - | return (nextIndex <= SIZE - 1); | + | |
| - | } | + | |
| - | + | ||
| - | public Integer next() { | + | |
| - | | + | |
| - | // Record a value of an even index of the array | + | |
| - | Integer retValue | + | |
| - | | + | |
| - | // Get the next even element | + | |
| - | nextIndex += 2; | + | |
| - | return retValue; | + | |
| } | } | ||
| | | ||
| - | public void remove() { } | + | |
| + | public void setNext(Node< | ||
| + | public Node< | ||
| + | public void setPrev(Node< | ||
| + | public E getElement() { return e; } | ||
| + | | ||
| } | } | ||
| | | ||
| - | | + | |
| - | + | | |
| - | // Fill the array with integer values and print out only | + | public |
| - | // values of even indices | + | |
| - | DataStructure ds = new DataStructure(); | + | |
| - | ds.printEven(); | + | |
| - | } | + | |
| - | } | + | |
| - | </code> | + | |
| - | + | ||
| - | <WRAP todo center 80% round> Σε αναλογία, | + | |
| - | </ | + | |
| - | + | ||
| - | ===== Δημιουργία αντικειμένων της εσωτερικής κλάσης ===== | + | |
| - | + | ||
| - | ==== Δημιουργία αντικειμένων της εσωτερικής κλάσης στην εξωτερική κλάση ==== | + | |
| - | + | ||
| - | Απαραίτητη προϋπόθεση για να δημιουργηθεί ένα αντικείμενο της εσωτερικής κλάσης είναι να υπάρχει ένα αντικείμενο της εξωτερικής κλάσης. Δεν μπορείτε να έχετε δηλαδή οποιαδήποτε αντικείμενο της εσωτερικής κλάσης χωρίς αυτό να συνδυαστεί με ένα αντικείμενο της εξωτερικής κλάσης. | + | |
| - | + | ||
| - | Δείτε το παρακάτω παράδειγμα δημιουργίας ενός αντικειμένου της εσωτερικής κλάσης μέσα στον κατασκευαστή της εξωτερικής κλάσης | + | |
| - | + | ||
| - | <code java OuterClass.java> | + | |
| - | public class OuterClass { | + | |
| - | + | ||
| - | int outerClassField; | + | |
| - | InnerClass ic; | + | |
| - | + | ||
| - | public OuterClass(int field) | + | |
| - | | + | |
| - | ic = new InnerClass(field*2); | + | |
| - | } | + | |
| - | + | ||
| - | class InnerClass { | + | |
| - | int innerClassField; | + | |
| - | | + | |
| - | public | + | |
| - | | + | |
| } | } | ||
| - | } | + | |
| - | + | if(curr.getNext() != tail) | |
| - | | + | |
| - | | + | |
| - | } | + | |
| - | + | ||
| - | public static void main(String []args) { | + | |
| - | OuterClass outer = new OuterClass(10); | + | |
| - | System.out.println(outer); | + | |
| - | } | + | |
| - | } | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | ==== Δημιουργία αντικειμένων της εσωτερικής κλάσης από άλλες κλάσεις ή στατικές μεθόδους ==== | + | |
| - | + | ||
| - | Προηγούμενα αναφέρθηκε ότι για να δημιουργηθεί ένα αντικείμενο της εσωτερικής κλάσης θα πρέπει να υπάρχει ένα αντικείμενο της εξωτερικής κλάσης. Δείτε πως μπορείτε να δημιουργήσετε σε μία στατική μέθοδο (//όπως είναι η μέθοδος **main**//) ένα αντικείμενο της εσωτερικής κλάσης με βάση την εξωτερική κλάση. | + | |
| - | + | ||
| - | <code java OuterClass.java> | + | |
| - | public class OuterClass { | + | |
| - | int outerClassField; | + | |
| - | InnerClass ic; | + | |
| - | + | ||
| - | public OuterClass(int field) { | + | |
| - | outerClassField = field; | + | |
| - | ic = new InnerClass(field*2); | + | |
| - | } | + | |
| - | + | ||
| - | class InnerClass { | + | |
| - | int innerClassField; | + | |
| - | + | ||
| - | public InnerClass(int field) { | + | |
| - | | + | |
| } | } | ||
| - | + | | |
| - | public | + | curr = curr.getNext(); |
| - | | + | return curr.getElement(); |
| + | } | ||
| + | public | ||
| + | | ||
| + | curr.getNext().setPrev(curr.getPrev()); | ||
| + | curr = null; | ||
| } | } | ||
| } | } | ||
| | | ||
| - | | + | |
| - | return | + | return |
| } | } | ||
| | | ||
| - | | + | // append in the end |
| - | OuterClass outer = new OuterClass(10); | + | public void add(E elem) { |
| - | System.out.println(outer); | + | |
| - | OuterClass.InnerClass inner = outer.new InnerClass(4); | + | |
| - | System.out.println(inner.toString()); | + | |
| - | | + | |
| - | } | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | Η διαδικασία δημιουργίας ενός αντικειμένου της εσωτερικής κλάσης θα μπορούσε να δημιουργηθεί σε μία στατική ή μη στατική μέθοδο άλλης κλάσης. Δείτε το παρακάτω παράδειγμα. | + | |
| - | + | ||
| - | <code java TestOuterClass.java> | + | |
| - | public | + | |
| - | public static | + | |
| - | | + | |
| - | | + | |
| - | OuterClass.InnerClass inner = outer.new InnerClass(4); //line 4 | + | |
| - | | + | |
| } | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Αρχικά, | ||
| - | <code java> | ||
| - | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | ||
| - | </ | ||
| - | |||
| - | <WRAP todo 80% round center> | ||
| - | Είναι προφανές ότι μπορούμε να φτιάξουμε πολλαπλά αντικείμενα της εσωτερικής κλάσης, | ||
| - | <code java TestOuterClass.java> | ||
| - | public class TestOuterClass { | ||
| - | public static void mian(String args[]) { | ||
| - | OuterClass outer; | ||
| - | OuterClass.InnerOuterClass inner = outer.new InnerOuterClass(4); | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | Σε αυτή την περίπτωση λαμβάνετε από τον μεταγλωττιστή ένα λάθος της μορφής | ||
| - | < | ||
| - | OuterClass.java: | ||
| - | OuterClass.InnerClass inner = outer.new InnerClass(4); | ||
| - | ^ | ||
| - | 1 error | ||
| - | </ | ||
| - | Δοκιμάστε το. | ||
| - | </ | ||
| - | |||
| - | Οι εσωτερικές κλάσεις μπορούν να έχουν προσδιοριστές πρόσβασης (//public, protected, package-private, | ||
| - | |||
| - | ===== Πρόσβαση στα πεδία της εξωτερικής κλάσης (από την εσωτερική κλάση) ===== | ||
| - | |||
| - | Κάθε εσωτερική κλάση έχει πρόσβαση στα πεδία και τις μεθόδους της εξωτερικής κλάσης, | ||
| - | |||
| - | <WRAP tip 80% round center> | ||
| - | Εάν μία μέθοδος της εσωτερικής κλάσης καλεί μία άλλη μέθοδο η οποία δεν ανήκει στην εσωτερική κλάση, τότε ο compiler αναζητά την μέθοδο στην εξωτερική κλάση. Αν δεν την βρει και στην εξωτερική κλάση τότε εμφανίζει μήνυμα λάθους. | ||
| - | |||
| - | Αντίστοιχα, | ||
| - | </ | ||
| - | |||
| - | Δείτε το παρακάτω παράδειγμα προσβασιμότητας των πεδίων της εξωτερικής κλάσης από την εσωτερική κλάση: | ||
| - | |||
| - | <code java OuterClassAccess.java> | ||
| - | public class OuterClassAccess { | ||
| - | private int outerPriv; | ||
| - | int outerPckgPriv; | ||
| - | protected int outerProt; | ||
| - | public int outerPub; | ||
| - | InnerClass ic; | ||
| | | ||
| - | | + | |
| - | private int getOuterPriv() { return outerPriv; } | + | Iterator< |
| - | + | | |
| - | void setOuterPckgPriv(int v) { outerPckgPriv | + | E e = it.next(); |
| - | int getPckgOuterPriv() { return outerPckgPriv; } | + | if( e.equals(elem) ) |
| - | + | return | |
| - | protected void setOuterProt(int v) { outerProt = v; } | + | } |
| - | | + | return |
| - | + | ||
| - | public void setOuterPub(int v) { outerPub = v; } | + | |
| - | | + | |
| - | + | ||
| - | public OuterClassAccess() { | + | |
| - | ic = new InnerClass(1, | + | |
| - | | + | |
| } | } | ||
| | | ||
| - | public | + | public |
| - | | + | |
| - | ", outerProt: " | + | int index = -1; |
| - | } | + | |
| - | + | | |
| - | private class InnerClass { | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| } | } | ||
| - | | + | |
| - | public void setOuterClassFields(int p, int pp, int pr, int pu) { | + | |
| - | setOuterPriv(p); | + | |
| - | setOuterPckgPriv(pp); | + | |
| - | setOuterProt(pr); | + | |
| - | setOuterPub(pu); | + | |
| - | } | + | |
| - | } | + | |
| - | + | ||
| - | public static void main(String args[]) { | + | |
| - | OuterClassAccess oc = new OuterClassAccess(); | + | |
| - | System.out.println(oc); | + | |
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | <WRAP important 80% center round> | + | Το παρακάτω πρόγραμμα επιχειρεί να δημιουργήσει μία λίστα με 20 τυχαίους αριθμούς |
| - | Από το παραπάνω παράδειγμα, παρατηρούμε ότι η εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία | + | |
| - | </WRAP> | + | |
| - | ===== Πρόσβαση από την εξωτερική κλάση σε πεδία της εσωτερικής κλάσης ===== | + | <code java LinkedListUsage.java> |
| + | import java.util.*; | ||
| - | Το παρακάτω παράδειγμα εξηγεί την προσβασιμότητα της εξωτερικής κλάσης σε πεδία και μεθόδους της εσωτερικής κλάσης. | + | public class LinkedListUsage |
| - | + | public | |
| - | <code java OuterClass.java> | + | |
| - | public class OuterClass | + | |
| - | int outer; | + | |
| - | InnerOuterClass innerObj; | + | |
| - | + | ||
| - | public | + | |
| - | outer = o; | + | |
| - | innerObj = new InnerOuterClass(); | + | |
| - | innerObj.innerPriv = 10; | + | |
| - | innerObj.innerProt | + | |
| - | innerObj.innerPub = 30; | + | |
| - | System.out.println(innerObj); | + | |
| - | } | + | |
| - | + | ||
| - | class InnerOuterClass { | + | |
| - | private int innerPriv; | + | |
| - | protected int innerProt; | + | |
| - | public int innerPub; | + | |
| - | + | ||
| - | private void setInnerPriv(int priv) { innerPriv = priv; } | + | |
| - | protected void setInnerProt(int prot) { innerProt = prot; } | + | |
| - | public void setInnerPub(int pub) { innerPub = pub; } | + | |
| - | public String toString() { | + | |
| - | return " | + | |
| - | ", | + | |
| - | } | + | |
| - | } | + | |
| | | ||
| public static void main(String[] args) { | public static void main(String[] args) { | ||
| - | | + | |
| - | | + | |
| - | } | + | for(int i=0; i<SIZE; i++) { |
| - | </code> | + | |
| - | + | | |
| - | Όπως θα παρατηρήσετε αν μεταγλωττίσετε και εκτελέσετε το πρόγραμμα η εξωτερική κλάση έχει απόλυτη πρόσβαση στα πεδία και τις μεθόδους της εσωτερικής κλάσης ανεξάρτητα από τον προσδιοριστή πρόσβασης που έχουν αυτά. Η διαφορά ανάμεσα στην πρόσβαση της εξωτερικής κλάσης στα πεδία της εσωτερικής γίνεται μέσω ενός αντικειμένου της εξωτερικής κλάσης. | + | |
| - | + | | |
| - | <WRAP important 80% center round> | + | |
| - | * H εσωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εξωτερικής κλάσης. | + | |
| - | * Η εξωτερική κλάση έχει πρόσβαση σε όλα τα πεδία της εσωτερικής κλάσης. Η πρόσβαση στα πεδία αυτά γίνεται μέσω ενός αντικειμένου της εξωτερικής κλάσης. | + | System.out.println(); |
| - | Οι προσδιοριστές πρόσβασης **δεν εισάγουν κανένα περιορισμό** στον προσδιορισμό της προσβασιμότητας των πεδίων και των μεθόδων της εσωτερικής κλάσης από την εξωτερική κλάση και αντίστροφα. | + | |
| - | </ | + | |
| - | + | ||
| - | ===== Πρόσβαση από άλλες κλάσεις σε πεδία της εσωτερικής κλάσης ===== | + | |
| - | + | ||
| - | Ο παρακάτω κώδικας επιχειρεί να δημιουργήσει ένα αντικείμενο μίας κλάσης εσωτερικής κλάσης από μία άλλη κλάση. Σε αυτή την περίπτωση και __με την προϋπόθεση ότι η εσωτερική κλάση είναι συνολικά προσβάσιμη__ από την κλάση που επιχειρεί να δημιουργήσει το αντικείμενο, | + | |
| - | + | ||
| - | <code java OuterClass.java> | + | |
| - | public class OuterClass { | + | |
| - | | + | |
| - | InnerClass innerObj; | + | |
| - | + | ||
| - | public OuterClass(int o) { | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | System.out.println(innerObj); | + | |
| } | } | ||
| - | |||
| - | class InnerClass { | ||
| - | private int innerPriv; | ||
| - | protected int innerProt; | ||
| - | public int innerPub; | ||
| - | | ||
| - | private void setInnerPriv(int priv) { innerPriv = priv; } | ||
| - | protected void setInnerProt(int prot) { innerProt = prot; } | ||
| - | public void setInnerPub(int pub) { innerPub = pub; } | ||
| - | public String toString() { | ||
| - | return " | ||
| - | ", | ||
| - | } | ||
| - | } | ||
| - | | ||
| } | } | ||
| </ | </ | ||
| - | <code java TestOuterClass.java> | + | <WRAP todo center 80% round> **Εργασία για το σπίτι: |
| - | public class TestOuterClass { | + | |
| - | public static void main(String args[]) { | + | |
| - | OuterClass outer = new OuterClass(5); | + | |
| - | OuterClass.InnerClass inner = outer.new InnerClass(); | + | |
| - | inner.setInnerPriv(4); | + | |
| - | inner.setInnerProt(5); | + | |
| - | inner.setInnerPub(6); | + | |
| - | System.out.println(inner); | + | |
| - | } | + | |
| - | } | + | |
| - | </ | + | |
| - | + | ||
| - | Κατά συνέπεια, για την προσβασιμότητα των | + | |
| - | - Η εσωτερική κλάση θα πρέπει να είναι συνολικά προσβάσιμη. | + | |
| - | - Με την προϋπόθεση ότι ισχύει το **1.**, ισχύουν οι [[java: | + | |
| - | + | ||
| - | ==== Χρήση προσδιοριστών πρόσβασης στην | + | |
| - | + | ||
| - | Στο προηγούμενο παράδειγμα δοκιμάστε να αλλάξετε τον | + | |
| - | + | ||
| - | < | + | |
| - | 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); | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP tip 80% center round> | + | |
| - | Το παραπάνω εξηγεί ικανοποιητικά τον τρόπο με τον οποίο μπορείτε να αποκλείσετε την πρόσβαση στην εσωτερική κλάση από άλλες κλάσεις πέραν της εξωτερικής. Ορίζοντας την εσωτερική κλάση ως **private** αυτή είναι προσβάσιμη μόνο από την εξωτερική της κλάση. | + | |
| </ | </ | ||
| - | ==== Επαναορίζοντας (ή κρύβοντας..) τα πεδία της εξωτερικής κλάσης στην εσωτερική κλάση ==== | ||
| - | |||
| - | Στο προηγούμενο παράδειγμα είδαμε την προσβασιμότητα στα πεδία και τις μεθόδους της εξωτερικής κλάσης. Τι γίνεται όμως όταν υπάρχει μία μέθοδος που καλεί μία άλλη μέθοδο η οποία υπάρχει τόσο στη εσωτερική όσο και στην εξωτερική κλάση. Σε αναλογία τι γίνεται όταν μία μέθοδος καλεί ένα πεδίο το οποίο υπάρχει στην εσωτερική και την εξωτερική κλάση; Το παρακάτω παράδειγμα απαντά στις παραπάνω απορίες. | ||
| - | |||
| - | <code java ShadowTest.java> | ||
| - | public class ShadowTest { | ||
| - | |||
| - | public int x = 100; | ||
| - | |||
| - | class FirstLevel { | ||
| - | |||
| - | public int x = 200; | ||
| - | |||
| - | void methodInFirstLevel(int x) { | ||
| - | System.out.println(" | ||
| - | System.out.println(" | ||
| - | System.out.println(" | ||
| - | } | ||
| - | | ||
| - | String printX() { return "X in FirstLevel is " | ||
| - | } | ||
| - | | ||
| - | 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()); | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| + | |Προηγούμενο: | ||