====== Ανώνυμες εμφωλευμένες κλάσεις ====== Οι ανώνυμές εμφωλευμένες κλάσεις επιτρέπουν τον ταυτόχρονο ορισμό της κλάσης και την δημιουργία ενός αντικειμένου, σε μία εντολή. Οι κλάσεις αυτές **ΠΡΕΠΕΙ** **α)** __να υλοποιούν ένα υφιστάμενο interface__ ή **β)** __να επεκτείνουν μία υφιστάμενη κλάση__. Ανώνυμες εμφωλευμένες κλάσεις μπορούμε να υλοποιήσουμε όταν συντρέχουν ταυτόχρονα οι παρακάτω λόγοι: - θέλουμε να υλοποιήσουμε μία εσωτερική κλάση. - η κλάση αυτή υλοποιεί ένα //interface// ή επεκτείνει μία υφιστάμενη κλάση (η κλάση που επεκτείνεται μπορεί να είναι //abstract// ή όχι) και - από την κλάση αυτή επιθυμούμε να δημιουργηθεί μόνο ένα αντικείμενο. Σε αυτές τις περιπτώσεις η χρήση ανώνυμων κλάσεων μπορεί να είναι βολική, καθώς συμπιέζει το μέγεθος του κώδικα. Από την άλλη πλευρά η εκτεταμένη χρήση ανώνυμων κλάσεων μπορεί να δημιουργήσει κώδικα που είναι δυσανάγνωστος. ===== Παράδειγμα - Ανώνυμη εμφωλευμένη κλάση ως υλοποίηση ενός interface ===== Στο παρακάτω παράδειγμα ορίζουμε την κλάση **Student** η οποία έχει τα τρία (3) πεδία **firstName**, **lastName**, **AEM**. Θέλουμε να ταξινομήσουμε τα δεδομένα της λίστας κατά αύξουσα σειρά με δύο διαφορετικούς τρόπους α) με βάση τη σειρά επώνυμο/όνομα/ΑΕΜ και β) με βάση τη σειρά ΑΕΜ/επώνυμο/όνομα. Η ταξινόμηση των στοιχείων μίας λίστας μπορεί να γίνει με τη βοήθεια της στατικής μεθόδου [[https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator)|Collections.sort(java.util.List, java.util.Comparator)]], όπου παρέχεται ένας **συγκριτής** (//comparator//) για την σύγκριση των στοιχείων της λίστας. Η σύγκριση έχει υλοποιηθεί με δύο ανώνυμες κλάσεις που υλοποιούν και οι δύο το //interface// [[https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html|java.util.Comparator]]. import java.util.Comparator; import java.util.*; import java.io.*; class Student { String firstName; String lastName; int AEM; public Student(int AEM, String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; this.AEM = AEM; } public String toString() { return String.format("%5d. %s, %s", AEM, lastName, firstName); } // First anonymous comparator class static Comparator lexicographicCmp = new Comparator() { public int compare(Student st1, Student st2) { int cmp = st1.lastName.compareTo(st2.lastName); if(cmp==0) cmp = st1.firstName.compareTo(st2.firstName); if(cmp==0) cmp = st1.AEM - st2.AEM; return cmp; } }; public static void sortLexicographically(List students) { Collections.sort(students, Student.lexicographicCmp); } public static void sortByAEM(List students) { // Second anonymous comparator class Collections.sort(students, new Comparator() { public int compare(Student st1, Student st2) { int cmp = st1.AEM - st2.AEM; if(cmp==0) cmp = st1.lastName.compareTo(st2.lastName); if(cmp==0) cmp = st1.firstName.compareTo(st2.firstName); return cmp; } } ); } } Στη μέθοδο **//main//** διαβάζουμε από το αρχείο **students.txt** και καταχωρούμε το περιεχόμενο του σε μία λίστα (**ArrayList**). Στη συνέχεια εκτυπώνουμε τα στοιχεία της λίστας * με τη σειρά που τα διαβάσαμε * με λεξικογραφική σειρά. * με βάση το ΑΕΜ 4596 Super Man 5819 Peter Pan 1694 Susan Brown 7895 Lena Smith 3256 Oscar Gonzales 1243 Edgar Wallace 3265 Kate Gordon 4377 Leda Evans 1118 David Lerroy 8744 Amelia Dray import java.io.*; import java.util.*; public class SortListOfStudents { public static void readFromFile(List students, File f) { try(Scanner sc = new Scanner(f)) { while(sc.hasNextLine()) { students.add( new Student(sc.nextInt(), sc.next(), sc.next()) ); } } catch(FileNotFoundException ex) { System.out.println("File \""+f.getName()+"\" was not found!"); } catch(InputMismatchException ex) { System.out.println("Input mismatch while reading with scanner!!!"); ex.printStackTrace(); System.exit(-1); } } public static String toString(List students) { StringBuilder str = new StringBuilder(); for(Student st : students) str.append(st+"\n"); str.append("---------------------------------\n"); return str.toString(); } public static void main(String []args) { if(args.length == 0) { System.out.println("Insufficient number of arguments!\n"); return; } List students = new ArrayList(); readFromFile(students, new File(args[0])); System.out.println(" --- Init Ordering ---\n"); System.out.println(toString(students)); Student.sortLexicographically(students); System.out.println(" --- Lexicographic Ordering ---\n"); System.out.println(toString(students)); Student.sortByAEM(students); System.out.println(" --- AEM Ordering ---\n"); System.out.println(toString(students)); } } ===== Παράδειγμα - Ανώνυμη εμφωλευμένη κλάση ως επέκταση υφιστάμενης κλάσης ===== Δείτε το προηγούμενο παράδειγμα παραλλαγμένο ως εξής. Αρχικά φτιάχνουμε την εσωτερική //abstract// κλάση **BasicComparator** που περιέχει μόνο την μέθοδο //equals// του //interface// [[https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html|java.util.Comparator]]. Στη συνέχεια ορίζουμε δύο ανώνυμες εμφωλευμένες κλάσεις (όπως στο προηγούμενο παράδειγμα), οι οποίες δεν υλοποιούν το //interface// java.util.Comparator, αλλά την εσωτερική //abstract// κλάση **BasicComparator**. import java.util.Comparator; import java.util.*; import java.io.*; class Student { String firstName; String lastName; int AEM; public Student(int AEM, String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; this.AEM = AEM; } public String toString() { return String.format("%5d. %s, %s", AEM, lastName, firstName); } static abstract class BasicComparator implements Comparator { } static Comparator lexicographicCmp = new BasicComparator() { public int compare(Student st1, Student st2) { int cmp = st1.lastName.compareTo(st2.lastName); if(cmp==0) cmp = st1.firstName.compareTo(st2.firstName); if(cmp==0) cmp = st1.AEM - st2.AEM; return cmp; } }; public static void sortLexicographically(List students) { Collections.sort(students, lexicographicCmp); } public static void sortByAEM(List students) { Collections.sort(students, new BasicComparator() { public int compare(Student st1, Student st2) { int cmp = cmp = st1.AEM - st2.AEM; if(cmp==0) cmp = st1.lastName.compareTo(st2.lastName); if(cmp==0) cmp = st1.firstName.compareTo(st2.firstName); return cmp; } } ); } } ===== Πρόσβαση στις τοπικές μεταβλητές και στις μεταβλητές της εξωτερικής κλάσης ===== Σε αναλογία με τις [[java:local_inner_classes|τοπικές εμφωλευμένες κλάσεις]] οι ανώνυμες κλάσεις έχουν τις ίδιες δυνατότητες πρόσβασης στις τοπικές μεταβλητές της μεθόδου στην οποία ορίζονται: * Η ανώνυμη κλάση έχει πρόσβαση στις μεταβλητές της εξωτερικής κλάσης. * Η ανώνυμη κλάση δεν μπορεί να έχει πρόσβαση σε τοπικές μεταβλητές της μεθόδου στην οποία ορίζεται αν αυτές δεν έχουν δηλωθεί ως //final//. * Όπως σε όλες τις μη στατικές εμφωλευμένες κλάσεις ο ορισμός του ίδιου τύπου δεδομένων στην εσωτερική και την εξωτερική κλάση "//κρύβει//" τον συγκεκριμένο τύπο δεδομένων από την εξωτερική κλάση. * __Δεν μπορείτε__ να ορίσετε στατικές μεταβλητές ή μεθόδους μέσα σε μία ανώνυμη κλάση. Σε μία ανώνυμη κλάση μπορείτε να ορίσετε τα εξής: * Πεδία * Επιπλέον μεθόδους που δεν ορίζονται στο interface ή στην κλάση που επεκτείνεται. * Τοπικές κλάσεις που ανήκουν στη ανώνυμη κλάση. * **ΔΕΝ** μπορείτε και __δεν έχει νόημα__ να ορίσετε κατασκευαστές μέσα σε μία ανώνυμη κλάση. | Προηγούμενο : [[ :java:local_inner_classes | Τοπικές εμφωλευμένες κλάσεις ]] | [[ :toc | Περιεχόμενα ]] | Επόμενο: [[ :java:static_nested_classes | Στατικές εμφωλευμένες κλάσεις ]] |