User Tools

Site Tools


java:anon_inner_classes

This is an old revision of the document!


Ανώνυμες εμφωλευμένες κλάσεις

Οι ανώνυμές εμφωλευμένες κλάσεις επιτρέπουν τον ταυτόχρονο ορισμό της κλάσης και την δημιουργία ενός αντικειμένου, σε μία εντολή. Οι κλάσεις αυτές ΠΡΕΠΕΙ α) να υλοποιούν ένα υφιστάμενο interface ή β) να επεκτείνουν μία υφιστάμενη κλάση. Δείτε το παράδειγμα που παρουσιάστηκε στις μη στατικές εμφωλευμένες κλάσεις αλλαγμένο, ώστε να χρησιμοποιεί ανώνυμες κλάσεις.

Ανώνυμες εμφωλευμένες κλάσεις μπορούμε να υλοποιήσουμε όταν συντρέχουν ταυτόχρονα οι παρακάτω λόγοι:

  1. επιθυμούμε την υλοποίηση εσωτερικής κλάσης.
  2. η κλάση αυτή υλοποιεί ένα interface ή επεκτείνει μία άλλη κλάση (η κλάση που επεκτείνεται μπορεί να είναι abstract ή όχι) και
  3. από την κλάση αυτή πρόκειται να δημιουργηθεί μόνο ένα αντικείμενο.

Σε αυτές τις περιπτώσεις η χρήση ανώνυμων κλάσεων μπορεί να είναι βολική, καθώς συμπιέζει τον όγκο του κώδικα. Από την πλευρά η εκτεταμένη χρήση ανώνυμων κλάσεων μπορεί να δημιουργήσει κώδικα που είναι δυσανάγνωστος.

Παράδειγμα - Ανώνυμη εμφωλευμένη κλάση ως υλοποίηση ενός interface

DataStructure.java
public class DataStructure {
 
  // Create an array
  private final static int SIZE = 15;
  private int[] arrayOfInts = new int[SIZE];
 
  public DataStructure() {
    // fill the array with ascending integer values
    for (int i = 0; i < SIZE; i++) {
      arrayOfInts[i] = i;
    }
  }
 
  interface DataStructureIterator extends java.util.Iterator<Integer> { } 
 
  public void printEven() {
 
    // Print out values of even indices of the array
    DataStructureIterator iterator = new 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 = Integer.valueOf(arrayOfInts[nextIndex]);
 
      // Get the next even element
      nextIndex += 2;
      return retValue;
      }
 
      public void remove() { }
 
    };
    while (iterator.hasNext()) {
      System.out.print(iterator.next() + " ");
    }
    System.out.println();
  }
 
  public static void main(String s[]) {
    DataStructure ds = new DataStructure();
    ds.printEven();
  }
}

Παρατηρήστε ότι η ορίζουμε μία νέα κλάση που υλοποιεί το interface DataStructureIterator χωρίς να δώσουμε όνομα στην νέα κλάση (η κλάση προσδιορίζεται από τον τύπο δεδομένων που ορίζει το interface). Παράλληλα με τον ορισμό της κλάσης, δημιουργείται ένα νέο αντικείμενο, στο οποίο δείχνει η μεταβλητή iterator. Η συγκεκριμένη κλάση δημιουργήθηκε με βάση το inteface DataStructureIterator.

Παράδειγμα - Ανώνυμη εμφωλευμένη κλάση ως επέκταση υφιστάμενης κλάσης

Παρακάτω δίνεται ένα άλλο παράδειγμα, όπου η ανώνυμη κλάση επεκτείνει μία υφιστάμενη κλάση αντί για ένα inteface.

HelloWorldAnonymousClasses.java
public class HelloWorldAnonymousClasses {
 
  interface HelloWorld {
    public void greet();
    public void greetSomeone(String someone);
  }
 
  public static void sayHello() {
 
    class EnglishGreeting implements HelloWorld {
      String name = "world";
      public void greet() {
        greetSomeone("world");
      }
      public void greetSomeone(String someone) {
        name = someone;
        System.out.println("Hello " + name);
      }
    }
 
    HelloWorld englishGreeting = new EnglishGreeting();
 
    HelloWorld frenchGreeting = new HelloWorld() {
      String name = "tout le monde";
      public void greet() {
        greetSomeone("tout le monde");
      }
      public void greetSomeone(String someone) {
        name = someone;
        System.out.println("Salut " + name);
      }
    };
 
    HelloWorld spanishGreeting = new EnglishGreeting() {
      String name = "mundo";
      public void greet() {
        greetSomeone("mundo");
      }
      public void greetSomeone(String someone) {
        name = someone;
        System.out.println("Hola, " + name);
      }
    };
    englishGreeting.greet();
    frenchGreeting.greetSomeone("Fred");
    spanishGreeting.greet();
  }
 
  public static void main(String... args) {    
    HelloWorldAnonymousClasses.sayHello();
  }      
}

Παρατηρήστε ότι η μεταβλητή frenchGreeting προκύπτει από μία κλάση που υλοποιεί το inteface HelloWorld η μεταβλητή spanishGreeting προκύπτει ως επέκταση της κλάση EnglishGreeting.

Πρόσβαση στις τοπικές μεταβλητές και στις μεταβλητές της εξωτερικής κλάσης

Σε αναλογία με τις τοπικές εμφωλευμένες κλάσεις οι ανώνυμες κλάσεις έχουν τις ίδιες δυνατότητες πρόσβασης στις τοπικές μεταβλήτές της μεθόδου στην οποία ορίζονται:

  • Η ανώνυμη κλάση έχει πρόσβαση στις μεταβλητές της εξωτερικής κλάσης.
  • Η ανώνυμη κλάση δεν μπορεί να έχει πρόσβαση σε τοπικές μεταβλητές της μεθόδου στην οποία ορίζονται αν αυτές δεν έχουν δηλωθεί ως final.
  • Όπως σε όλες τις μη στατικές εμφωλευμένες κλάσεις ο ορισμός του ίδιου τύπου δεδομένων στην εσωτερική και την εξωτερική κλάση “κρύβει” τον συγκεκριμένο τύπο δεδομένων από την εξωτερική κλάση.
  • Δεν μπορείτε να ορίσετε στατικές μεταβλητές ή μεθόδους μέσα σε μία ανώνυμη κλάση.

Σε μία ανώνυμη κλάση μπορείτε να ορίσετε τα εξής:

  • Πεδία
  • Επιπλέον μεθόδους που δεν ορίζονται στη interface ή στην κλάση που επεκτείνει.
  • Μεθόδους ή block αρχικοποίησης πεδίων της κλάσης.
  • Τοπικές κλάσεις που ανήκουν στη ανώνυμη κλάση.
  • ΔΕΝ μπορείτε και δεν έχει νόημα να ορίσετε κατασκευαστές μέσα σε μία ανώνυμη κλάση.
java/anon_inner_classes.1486389055.txt.gz · Last modified: 2017/02/06 13:50 (external edit)