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:interfaces [2016/02/12 10:17] gthanos [Στατικές μέθοδοι] |
java:interfaces [2016/04/09 06:48] gthanos [Χρησιμοποιώντας ένα interface ως τύπο δεδομένων] |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| ===== Εισαγωγικά ===== | ===== Εισαγωγικά ===== | ||
| - | Κατά την ανάπτυξη προγραμμάτων, υπάρχουν περιπτώσεις που είναι σημαντικό να διαχωρίσουμε την δουλειά μεταξύ προγραμματιστών, ώστε κάθε ομάδα προγραμματιστών να μπορεί να αναπτύξει κώδικα ανεξάρτητα από τις υπόλοιπες ομάδες. | + | Κατά την ανάπτυξη προγραμμάτων είναι σημαντικό να είναι τυποποιημένος ο τρόπος αλληλεπίδρασης ανάμεσα σε διαφορετικά συστήματα. Η ύπαρξη ενός "συμβολαίου" το οποίο καθορίζει ακριβώς το πώς μπορεί μια εφαρμογή να αλληλεπιδράσει με μια άλλη διευκολύνει την ανεξάρτητη ανάπτυξη κώδικα από διαφορετικές ομάδες. |
| - | Φανταστείτε το πληροφοριακό σύστημα μιας Τράπεζας. Υπάρχει μία ομάδα προγραμματιστών που ασχολείται με τη διαχείριση των δεδομένων της Τράπεζας (χρήστες, πελάτες, λογαριασμοί πελατών κλπ), μία ομάδα που ασχολείται με το εσωτερικό πληροφοριακό σύστημα της τράπεζας (υπηρεσίες προς τους υπάλληλους της) και μία άλλη ομάδα που ασχολείται με το e-banking και m-banking (υπηρεσίες προς τους πελάτες της). | + | Υπακούοντας στην παραπάνω αρχή, η Java εισάγει την έννοια της διεπαφής (**interface**). Τα //interfaces// στη Java λειτουργούν ως προ-συμφωνημένες διεπαφές μεταξύ προγραμματιστών. Κάθε interface τυπικά σχετίζεται με: |
| - | Οι ομάδες προγραμματιστών που ασχολούνται με υπηρεσίες θέλουν με κάποιον τρόπο να έχουν ασφαλή πρόσβαση στα δεδομένα της τράπεζας. Για τον λόγο αυτό, η ομάδα που ασχολείται με την διαχείριση των δεδομένων της Τράπεζας δίνει μια σειρά από μεθόδους μέσω των οποίων, οι άλλες ομάδες μπορούν να έχουν ασφαλή και πιστοποιημένη πρόσβαση στα δεδομένα αυτά. | + | - τους προγραμματιστές που το χρησιμοποιούν και |
| + | - τους προγραμματιστές που το υλοποιούν. | ||
| - | Στην γλώσσα του προγραμματισμού, λέμε ότι η ομάδα που είναι υπεύθυνη για την διαχείριση των δεδομένων παρέχει ένα //Application Programming Interface (**API**)// προς τις άλλες ομάδες. Οι άλλες ομάδες δεν ενδιαφέρονται για το πως έχει υλοποιηθεί το παραπάνω //API//, αλλά θέλουν να το χρησιμοποιήσουν με ασφάλεια. Η ομάδα που διαχειρίζεται τα δεδομένα, μπορεί να αλλάξει την εσωτερική υλοποίηση των παραπάνω μεθόδων που αποτελούν το συγκεκριμένο //API//, αρκεί να μην το μεταβάλει. Από τα παραπάνω συμπεραίνουμε ότι κάθε //API// λειτουργεί σαν **"συμβόλαιο"** μεταξύ δύο ομάδων προγραμματιστών, αυτούς που το υλοποιούν και τους χρήστες του. | + | Οι πρώτοι γράφουν την εφαρμογή τους ώστε να χρησιμοποιεί τις μεθόδους του interface για να παρέχει συγκεκριμένη λειτουργικότητα. |
| - | ===== Τα Java Interfaces ===== | + | Οι δεύτεροι, αν θέλουν να επωφεληθούν από την λειτουργικότητα που υποδεικνύει ένα //interface// θα πρέπει να υλοποιήσουν τις μεθόδους του στα προγράμματά τους και να επιλέγουν προς χρήση κλάσεις που υλοποιούν το συγκεκριμένο interface. |
| - | Υπακούοντας στην παραπάνω αρχή, η Java εισάγει την έννοια της διεπαφής (**interface**). Τα //interfaces// στη Java λειτουργούν ως προ-συμφωνημένες διεπαφές μεταξύ προγραμματιστών. Κάθε Interface έχει κατά κανόνα δύο μέρη | + | Από τα παραπάνω εξάγεται ότι το interface είναι μία προσυμφωνημένη διεπαφή η οποία δεσμεύει και τις δύο πλευρές, δηλαδή οι χρήστες του δεσμεύονται να χρησιμοποιούν τις μεθόδους του //interface// και οι προγραμματιστές που το υλοποιούν να το υλοποιούν στις κλάσεις τους. Παρακάτω θα δούμε την υποστήριξη των interfaces από τον compiler της Java και τους κανόνες που τα διέπουν. |
| - | - τους προγραμματιστές που το υλοποιούν και | + | Ως παράδειγμα, θεωρήστε ένα interface το οποίο ορίζει πως όποιοι κατασκευαστές συσκευών θέλουν να χρησιμοποιήσουν χρονόμετρο σε συσκευή τους πρέπει να υλοποιήσουν τις μεθόδους setTimer, startTimer και endTimer. |
| - | - τους προγραμματιστές που το χρησιμοποιούν. | + | Ένας κατασκευαστής κλιματιστικών (που θέλει να μπορεί να σταματήσει η λειτουργία της συσκευής μετά από ένα χρονικό διάστημα), και ένας κατασκευαστής κουζινών (που θέλει η κουζίνα του να παράγει έναν ήχο μετά από ένα χρονικό διάστημα) επιλέγουν να υλοποιήσουν αυτές τις μεθόδους. Με αυτόν το τρόπο τηρούν ένα συμβόλαιο αλληλεπίδρασης με το χρονόμετρο. |
| - | Οι δεύτεροι εάν θέλουν όμως να επωφεληθούν από την λειτουργικότητα που υποδεικνύει ένα //interface// θα πρέπει να χρησιμοποιούν τις μεθόδους του στα προγράμματα τους και να επιλέγουν προς χρήση κλάσεις που υλοποιούν το συγκεκριμένο interface. Με αυτόν τον τρόπο προσπαθούμε να γράψουμε κώδικα που είναι αρκετά γενικός, δηλαδή δεν στηρίζεται απαραίτητα σε συγκεκριμένες κλάσεις, αλλά σε ομάδες κλάσεων που έχουν ως κοινό χαρακτηριστικό την υλοποίηση του συγκεκριμένου //interface//. | + | Οι υλοποιήσεις για τις κουζίνες και τα κλιματιστικά είναι εντελώς διαφορετικές και γίνονται ανεξάρτητα η μία από την άλλη. Η εγγύηση είναι μόνο ότι οι μέθοδοι έχουν υλοποιηθεί και παρέχουν ασφαλή και ομοιόμορφο τρόπο αλληλεπίδρασης με τα χρονόμετρα των συσκευών. |
| - | Αντίστοιχα, οι προγραμματιστές που υλοποιούν μία λειτουργία είναι πολύ πιθανό να θέλουν να υλοποιήσουν ένα ή περισσότερα //interfaces//, έτσι ώστε προγράμματα που χρησιμοποιούν τα //interfaces// αυτά να είναι συμβατά με τον κώδικα που φτιάχνουν. | + | Ένας χρήστης αυτών των συσκευών δε χρειάζεται να γνωρίζει πώς ακριβώς λειτουργούν εσωτερικά τα χρονόμετρα, αλλά του αρκεί να γνωρίζει ότι μπορεί να αλληλεπιδράσει με το χρονόμετρο οποιασδήποτε τέτοιας συσκευής μέσω ίδιων πάντα μεθόδων οι οποίες παίρνουν πάντα συγκεκριμένες παραμέτρους κι επιστρέφουν συγκεκριμένη τιμή. |
| + | |||
| + | Αντιπαραθέστε μια κατάσταση όπου οι συσκευές δεν τηρούν αυτό το συμβόλαιο (δηλαδή δεν υλοποιούν το συγκεκριμένο interface) και ως αποτέλεσμα ο χρήστης αναγκάζεται να χρησιμοποιήσει μια μέθοδο setACTimer για το χρονόμετρο του κλιματιστικού, μια μέθοδο setStoveTimer για το χρονόμετρο της κουζίνας κτλ. | ||
| - | Από τα παραπάνω εξάγεται ότι το interface είναι μία προσυμφωνημένη διεπαφή η οποία δεσμεύει και τις δύο πλευρές, δηλαδή οι χρήστες του δεσμεύονται να χρησιμοποιούν τις μεθόδους του //interface// και οι προγραμματιστές που το υλοποιούν να το υλοποιούν στις κλάσεις τους. Παρακάτω θα δούμε την υποστήριξη των interfaces από τον compiler της Java και τους κανόνες που τα διέπουν. | ||
| ===== Ορίζοντας ένα Interface ===== | ===== Ορίζοντας ένα Interface ===== | ||
| - | Παρακάτω δίνεται το παράδειγμα ορισμού ενός Interface ως εξής: | + | Ένα interface ορίζεται με τρόπο παρόμοιο με κλάση, αλλά με το χαρακτηρισμό interface, για παράδειγμα, |
| <code java> | <code java> | ||
| - | public interface MyInterface extends Interface1, Interface2, Interface3 { | + | public interface ApplianceTimer{ |
| // constant declarations | // constant declarations | ||
| - | // base of natural logarithms | + | int TIMEOUT = 20000; |
| - | double E = 2.718282; | + | |
| - | double PI = 3.14159; | + | |
| // method signatures | // method signatures | ||
| - | public void interfaceMethod(int i, double x); | + | public int setTimer(int t); |
| - | public int interfaceMethod2(String s); | + | public int startTimer(int t); |
| + | public int stopTimer(); | ||
| } | } | ||
| </code> | </code> | ||
| - | * **public ή κανένας προσδιοριστής πρόσβασης:** Αν οριστεί //public// τότε το interface είναι ορατό από όλες τις κλάσεις και όλα τα πακέτα στην Java. Αν δεν οριστεί κάτι (package private) τότε το interface είναι ορατό μόνο μέσα στο πακέτο στο οποίο δηλώνεται. | + | Ο προσδιοριστής ενός interface είναι public ή μπορούμε να τον παραλείψουμε (package-private). |
| - | * **interface:** δεσμευμένη λέξη | + | |
| - | * **το όνομα του interface:** στο παράδειγμα μας ''MyInterface''. | + | Ένα interface μπορεί να περιέχει **μόνο** σταθερές (πχ. το TIMΕOUT στο παράδειγμα), abstract μεθόδους, default μεθόδους, static μεθόδους. Θα εξηγήσουμε κάθε μία από τις κατηγορίες μεθόδων παρακάτω. Όλες οι μέθοδοι σε ένα interface είναι εξ ορισμού //public//, κατά συνέπεια ο προσδιοριστής public σε αυτές μπορεί να παραληφθεί. |
| - | * **extends:** ένα ή περισσότερα interfaces τα οποία επεκτείνει το συγκεκριμένο interface (comma seperated). | + | |
| Τόσο στις κλάσεις όσο και στα interfaces ορίζεται η ιδιότητα της κληρονομικότητας. Η διαφορά είναι ότι ενώ στην κλάση μπορούμε να έχουμε μόνο μία γονική κλάση, στα interfaces μπορούμε να έχουμε περισσότερα του ενός γονικά interfaces. | Τόσο στις κλάσεις όσο και στα interfaces ορίζεται η ιδιότητα της κληρονομικότητας. Η διαφορά είναι ότι ενώ στην κλάση μπορούμε να έχουμε μόνο μία γονική κλάση, στα interfaces μπορούμε να έχουμε περισσότερα του ενός γονικά interfaces. | ||
| - | ==== Το σώμα του interface ==== | ||
| - | Ένα interface μπορεί να περιέχει πεδία όπως στο παραπάνω παράδειγμα. | + | ===== Υλοποιώντας ένα Interface ===== |
| - | <code java> | + | Θα δείξουμε την υλοποίηση ενός interface μέσα από ένα παράδειγμα. |
| - | double E = 2.718282; | + | |
| - | double PI = 3.14159; | + | |
| - | </code> | + | |
| - | Τα πεδία αυτά εξ ορισμού (by default) ''public, static, final'', δηλ είναι **__σταθερές__** που ανήκουν στις κλάσεις που θα υλοποιήσουν το interface στο οποίο δηλώνονται. | + | Μια πολύ συνηθισμένη χρήση interfaces είναι για το χαρακτηρισμό αντικειμένων τα οποία μπορούν να συγκριθούν μεταξύ τους: |
| - | + | ||
| - | Οι μέθοδοι σε ένα interface μπορούν να ανήκουν στις παρακάτω 3 κατηγορίες a) abstract methods, b) default methods, static methods. Θα εξηγήσουμε κάθε μία από τις 3 κατηγορίες παρακάτω. Όλες οι μέθοδοι σε ένα interface είναι εξ ορισμού //public//, κατά συνέπεια ο προσδιορισστής public μπορεί να παραληφθεί δηλ | + | |
| + | Η μέθοδος ''Arrays.Sort'' μπορεί να ταξινομήσει τα περιεχόμενα ενός πίνακα που αποτελείται από οποιοδήποτε είδος αντικειμένων αλλά μόνο υπό την προϋπόθεση ότι η κλάση που αναπαριστά αυτά τα αντικείμενα υλοποιεί το interface Comparable: | ||
| <code java> | <code java> | ||
| - | public interface MyInterface extends Interface1, Interface2, Interface3 { | + | public interface Comparable |
| - | + | { | |
| - | // constant declarations | + | int compareTo(Object other); |
| - | // base of natural logarithms | + | |
| - | double E = 2.718282; | + | |
| - | double PI = 3.14159; | + | |
| - | + | ||
| - | // method signatures | + | |
| - | public void interfaceMethod(int i, double x); | + | |
| - | public int interfaceMethod2(String s); | + | |
| } | } | ||
| </code> | </code> | ||
| - | ===== Υλοποιώντας ένα Interface ===== | + | Μια κλάση που υλοποιεί το Comparable πρέπει να υλοποιήσει τη μέθοδο ''compareTo''. Εφόσον συμβεί αυτό, η μέθοδος Arrays.Sort μπορεί πια να αλληλεπιδράσει με τα αντικείμενα που θέλουμε να ταξινομήσουμε ώστε να μας παρέχει την υπηρεσία ταξινόμησης. |
| - | Ας υποθέσουμε ότι για τις ανάγκες αυτής της παραγράφου ορίζουμε ένα interface το οποίο ορίζει ένα τρόπο για να συγκρίνουμε το μέγεθος επιμέρους αντικειμένων. | + | Ας δούμε ένα παράδειγμα πάνω στην κλάση Rectangle που έχουμε ορίσει σε προηγούμενες ενότητες. Σύμφωνα με το documentation του interface Comparable η compareTo πρέπει να επιστρέφει ακέραιο αρνητικό, μηδέν ή θετικό αν το τρέχον αντικείμενο (this) θεωρείται αντίστοιχα "μικρότερο", "ίσο" ή "μεγαλύτερο" από αυτό με το οποίο το συγκρίνουμε. Το πώς ορίζεται το "μικρότερο", κτλ. για αντικείμενα Rectangle είναι απόφαση του προγραμματιστή που υλοποιεί την κλάση Rectangle. Στο συγκεκριμένο παράδειγμα αποφασίζουμε να συγκρίνουμε τα αντικείμενα με βάση το εμβαδό τους. |
| - | <code java StrictlyComparable.java> | + | <code java Rectangle.java> |
| - | public interface StrictlyComparable { | + | import java.util.Arrays; |
| - | + | ||
| - | // this (object calling isLargerThan) | + | |
| - | // and other must be instances of | + | |
| - | // the same class returns 1, 0, -1 | + | |
| - | // if this is greater than, | + | |
| - | // equal to, or less than other | + | |
| - | public int isLarger(StrictlyComparable other); | + | |
| - | } | + | |
| - | </code> | + | |
| - | Ας υποθέσουμε ότι θέλουμε να συγκρίνουμε το μέγεθος αντικειμένων του ιδίου τύπου (ανεξάρτητα με το τι αντικείμενα είναι αυτά), οι κλάσεις που υλοποιούν τα αντικείμενα αυτά μπορούν να υλοποιούν το interface ''StrictlyComparable''. Για παράδειγμα, εάν πρόκειται για Strings μπορούμε να συγκρίνουμε το μέγεθος του String, αν πρόκειται για δι-διάστατα σχήματα θα μπορούσαμε να συγκρίνουμε το εμβαδό τους, ενώ αν πρόκειται για τρισδιάστατα σχήματα θα μπορούσαμε να συγκρίνουμε τον όγκο τους. | + | public class Rectangle implements Comparable { |
| - | + | private int width = 0; | |
| - | Ας υποθέσουμε ότι υλοποιούμε την κλάση Rectangle όπως αυτή δίνεται παρακάτω: | + | private int height = 0; |
| - | + | private Point origin; | |
| - | <code java Rectangle.java> | + | |
| - | public class Rectangle | + | |
| - | implements StrictlyComparable { | + | |
| - | public int width = 0; | + | |
| - | public int height = 0; | + | |
| - | public Point origin; | + | |
| - | // four constructors | ||
| public Rectangle() { | public Rectangle() { | ||
| origin = new Point(0, 0); | origin = new Point(0, 0); | ||
| Line 120: | Line 92: | ||
| } | } | ||
| - | // a method for moving the rectangle | ||
| public void move(int x, int y) { | public void move(int x, int y) { | ||
| origin.setX(x); | origin.setX(x); | ||
| Line 126: | Line 97: | ||
| } | } | ||
| - | // a method for computing | ||
| - | // the area of the rectangle | ||
| public int getArea() { | public int getArea() { | ||
| return width * height; | return width * height; | ||
| } | } | ||
| | | ||
| - | // a method required to implement | + | @Override |
| - | // the Relatable interface | + | public int compareTo(Object other) { |
| - | public int isLarger(StrictlyComparable other) { | + | Rectangle otherRect = (Rectangle) other; // απαραίτητο για να μπορεί να κληθεί η getArea |
| - | Rectangle otherRect = (Rectangle)other; | + | return this.getArea() - otherRect.getArea(); |
| - | if (this.getArea() < otherRect.getArea()) | + | } |
| - | return -1; | + | |
| - | else if (this.getArea() > otherRect.getArea()) | + | @Override String toString() { |
| - | return 1; | + | return origin + ", [" + width + " X " + height + "]"; |
| - | else | + | |
| - | return 0; | + | |
| } | } | ||
| | | ||
| public static void main(String args[]) { | public static void main(String args[]) { | ||
| - | Point p = new Point(10,20); | + | Rectangle [] shapes = new Rectangle[4]; |
| - | Rectangle rec1 = new Rectangle(p, 30, 40); | + | shapes[0] = new Rectangle(4, 5); |
| - | Rectangle rec2 = new Rectangle(p, 30, 20); | + | shapes[1] = new Rectangle(1, 8); |
| - | if( rec1.isLarger(rec2) > 0 ) { | + | shapes[2] = new Rectangle(2, 15); |
| - | System.out.println("rec1 is larger!"); | + | shapes[3] = new Rectangle(9, 2); |
| - | } | + | |
| - | else if( rec1.isLarger(rec2) < 0 ) { | + | System.out.println("Initial array:"); |
| - | System.out.println("rec2 is larger!"); | + | for (Rectangle rectangle : shapes) { |
| - | } | + | System.out.println(rectangle + ", area: " + rectangle.getArea()); |
| - | else { | + | } |
| - | System.out.println("req1 is equal to req2"); | + | |
| - | } | + | Arrays.sort(shapes); |
| - | + | | |
| + | System.out.println("Sorted array:"); | ||
| + | for (Rectangle rectangle : shapes) { | ||
| + | System.out.println(rectangle + ", area: " + rectangle.getArea()); | ||
| + | } | ||
| } | } | ||
| } | } | ||
| </code> | </code> | ||
| - | **Σημείωση:** Αν παραλείψετε την γραμμή | ||
| - | |||
| - | <code java> | ||
| - | Rectangle otherRect = (Rectangle)other; | ||
| - | </code> | ||
| - | |||
| - | ο compiler δεν γνωρίζει ότι η μεταβλητή ''other'' ανήκει στην κλάση ''Rectangle'' και η προσπάθεια μεταγλώτισσης θα εμφανίσει λάθος (δοκιμάστε το!). | ||
| Για να εκτελέσετε το παράδειγμα κατεβάστε την κλάση ''Point'', από [[:java:objects |εδώ]]. | Για να εκτελέσετε το παράδειγμα κατεβάστε την κλάση ''Point'', από [[:java:objects |εδώ]]. | ||
| Line 176: | Line 140: | ||
| Μπορείτε να χρησιμοποιήσετε ένα Java Interface ως ένα reference τύπο δεδομένων. Μπορείτε να χρησιμοποιήσετε το όνομα ενός interface ως τον τύπο μιας παραμέτρου σε μία Java μέθοδο ή τύπο μιας τοπικής μεταβλητής στο σώμα μίας μεθόδου. Προϋπόθεση είναι οι τιμές των μεταβλητών να δείχνουν σε αντικείμενα των οποίων οι κλάσεις υλοποιούν το συγκεκριμένο interface. Δείτε το παρακάτω παράδειγμα. | Μπορείτε να χρησιμοποιήσετε ένα Java Interface ως ένα reference τύπο δεδομένων. Μπορείτε να χρησιμοποιήσετε το όνομα ενός interface ως τον τύπο μιας παραμέτρου σε μία Java μέθοδο ή τύπο μιας τοπικής μεταβλητής στο σώμα μίας μεθόδου. Προϋπόθεση είναι οι τιμές των μεταβλητών να δείχνουν σε αντικείμενα των οποίων οι κλάσεις υλοποιούν το συγκεκριμένο interface. Δείτε το παρακάτω παράδειγμα. | ||
| - | <code java FinestComparator.java> | + | Αρχικά ορίζουμε ένα interface με όνομα MyComparable το οποίο ορίζει τη μέθοδο isLarger που επιστρέφει true ή false ανάλογα με το αν το τρέχον αντικείμενο είναι μεγαλύτερο ή μικρότερο της παραμέτρου : |
| - | public class FinestComparator { | + | <code java MyComparable.java> |
| + | public interface MyComparable { | ||
| + | public boolean isLarger(MyComparable other); | ||
| + | } | ||
| + | </code> | ||
| - | /* Παράδειγμα χρήσης interface ως τύπο τοπικής μεταβλητής στο σώμα μιας μεθόδου. | + | Γράφουμε την Rectangle ώστε να υλοποιεί και το νέο μας interface: |
| - | */ | + | <code java Rectangle.java> |
| - | public Object findLargest(Object object1, Object object2) { | + | public class Rectangle implements MyComparable{ |
| - | StrictlyComparable obj1 = (StrictlyComparable)object1; | + | |
| - | StrictlyComparable obj2 = (StrictlyComparable)object2; | + | // the Rectangle class has 3 fields |
| - | if ((obj1).isLarger(obj2) > 0) | + | private int width; |
| + | private int height; | ||
| + | private Point origin; | ||
| + | |||
| + | // the Rectangle class has one constructor | ||
| + | public Rectangle(int initWidth, int initHeight, Point initOrigin) { | ||
| + | width = initWidth; | ||
| + | height = initHeight; | ||
| + | origin = initOrigin; | ||
| + | } | ||
| + | |||
| + | public Rectangle(int initWidth, int initHeight, int xPos, int yPos) { | ||
| + | this(initWidth, initHeight, new Point(xPos,yPos)); | ||
| + | } | ||
| + | |||
| + | public Rectangle(int initWidth, int initHeight) { | ||
| + | this(initWidth, initHeight, 0, 0); | ||
| + | } | ||
| + | |||
| + | public void setWidth(int newWidth ) { | ||
| + | width = newWidth; | ||
| + | } | ||
| + | |||
| + | public int getWidth() { return width; } | ||
| + | |||
| + | public void setHeight(int newHeight ) { | ||
| + | height = newHeight; | ||
| + | } | ||
| + | |||
| + | public int getHeight() { return height; } | ||
| + | |||
| + | public void setOrigin(Point newOrigin) { | ||
| + | origin = newOrigin; | ||
| + | } | ||
| + | |||
| + | public Point getOrigin() { return origin; } | ||
| + | |||
| + | @Override | ||
| + | public boolean isLarger(MyComparable other) { | ||
| + | Rectangle otherRect = (Rectangle) other; | ||
| + | return (this.getArea() > otherRect.getArea()); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public String toString() { | ||
| + | return origin + ", Dimensions [" + width + " X " + height + "]"; | ||
| + | } | ||
| + | |||
| + | public int getArea() { | ||
| + | return width * height; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Τώρα, μπορούμε να ορίσουμε την κλάση ''TwosComparator'' η οποία παρέχει μεθόδους που μπορούν να χρησιμοποιηθούν για σύγκριση ανάμεσα σε οποιαδήποτε δύο αντικείμενα //εφόσον// αυτά υλοποιούν το MyComparable. | ||
| + | |||
| + | <code java TwosComparator.java> | ||
| + | public class TwosComparator { | ||
| + | | ||
| + | public MyComparable findLarger(MyComparable object1, MyComparable object2) { | ||
| + | if (object1.isLarger(object2)) | ||
| return object1; | return object1; | ||
| else | else | ||
| return object2; | return object2; | ||
| } | } | ||
| - | + | ||
| - | /* Παράδειγμα χρήσης interface ως τύπο τοπικής μεταβλητής στο σώμα μιας μεθόδου. | + | public MyComparable findSmaller(MyComparable object1, MyComparable object2) { |
| - | */ | + | if (!(object1.isLarger(object2))) |
| - | public Object findSmallest(Object object1, Object object2) { | + | |
| - | StrictlyComparable obj1 = (StrictlyComparable)object1; | + | |
| - | StrictlyComparable obj2 = (StrictlyComparable)object2; | + | |
| - | if ((obj1).isLarger(obj2) < 0) | + | |
| return object1; | return object1; | ||
| else | else | ||
| return object2; | return object2; | ||
| } | } | ||
| + | } | ||
| + | </code> | ||
| - | /* η μέθοδος isEqual δίνεται εδώ με δύο διαφορετικές εκδοχές | + | Χρησιμοποιούμε την TwosComparator ως εξής: |
| - | * οι οποίες είναι ισοδύναμες. | + | <code java Main.java> |
| - | */ | + | public class Main { |
| - | public boolean isEqual(Object object1, Object object2) { | + | |
| - | StrictlyComparable obj1 = (StrictlyComparable)object1; | + | |
| - | StrictlyComparable obj2 = (StrictlyComparable)object2; | + | |
| - | if ( (obj1).isLarger(obj2) == 0) | + | |
| - | return true; | + | |
| - | else | + | |
| - | return false; | + | |
| - | } | + | |
| - | + | ||
| - | /* Παράδειγμα χρήσης interface ως τύπο τυπικής παραμέτρου σε μία μέθοδο. | + | |
| - | */ | + | |
| - | public boolean isEqual(StrictlyComparable object1, StrictlyComparable object2) { | + | |
| - | if ( (object1).isLarger(object2) == 0) | + | |
| - | return true; | + | |
| - | else | + | |
| - | return false; | + | |
| - | } | + | |
| - | | + | |
| public static void main(String args[]) { | public static void main(String args[]) { | ||
| - | Point p = new Point(10,20); | + | Rectangle rec1 = new Rectangle(30, 40); |
| - | Rectangle rec1 = new Rectangle(p, 30, 40); | + | Rectangle rec2 = new Rectangle(10, 50); |
| - | Rectangle rec2 = new Rectangle(p, 30, 40); | + | TwosComparator comp = new TwosComparator(); |
| - | FinestComparator comp = new FinestComparator(); | + | |
| - | + | System.out.println("rec1 is " + rec1); | |
| - | System.out.println("rec1 is "+rec1.toString()); | + | System.out.println("rec2 is " + rec2); |
| - | System.out.println("rec2 is "+rec2.toString()); | + | |
| - | + | System.out.println( comp.findLarger(rec1, rec2) + " is larger!"); | |
| - | if( !comp.isEqual(rec1,rec2) ) { | + | System.out.println( comp.findSmaller(rec1, rec2) + " is smaller!"); |
| - | System.out.println( comp.findLargest(rec1, rec2).toString()+" is larger!"); | + | |
| - | System.out.println( comp.findSmallest(rec1, rec2).toString()+" is smaller!"); | + | |
| - | } else { | + | |
| - | System.out.println("Objects are equal!"); | + | |
| - | } | + | |
| } | } | ||
| } | } | ||
| </code> | </code> | ||
| - | |||
| - | Οι παραπάνω μέθοδοι δουλεύουν για οποιοδήποτε αντικείμενο η κλάση του υλοποιεί το παραπάνω interface, ώστε να μπορεί να κληθεί εσωτερικά η μέθοδος ''isLarger()''. Παρατηρήστε τις δύο διαφορετικές αλλά ισοδύναμες εκδοχές της μεθόδου ''isEqual''. | ||
| ===== Μεταβάλλοντας ένα υφιστάμενο Interface ===== | ===== Μεταβάλλοντας ένα υφιστάμενο Interface ===== | ||
| Line 251: | Line 253: | ||
| **1η εναλλακτική:** Να υλοποιήσουμε ένα νέο interface με παραπλήσιο όνομα, το οποίο να αποτελέσει τη νέα έκδοση του υφιστάμενου interface. | **1η εναλλακτική:** Να υλοποιήσουμε ένα νέο interface με παραπλήσιο όνομα, το οποίο να αποτελέσει τη νέα έκδοση του υφιστάμενου interface. | ||
| <code java> | <code java> | ||
| + | public interface DoIt { | ||
| + | |||
| + | void doSomething(int i, double x); | ||
| + | int doSomethingElse(String s); | ||
| + | } | ||
| + | |||
| public interface DoItPlus extends DoIt { | public interface DoItPlus extends DoIt { | ||
| Line 335: | Line 343: | ||
| ===== Στατικές μέθοδοι ===== | ===== Στατικές μέθοδοι ===== | ||
| - | Εκτός από //default// μεθόδους ένα interface μπορεί να περιέχει και στατικές (//static//) μεθόδους. Οι στατικές μέθοδοι ορίζονται σε αναλογία με τις στατικές μεθόδους των κλάσεων και ουσιαστικά ανήκουν στις κλάσεις που θα υλοποιήσουν το interface και όχι στα αντικείμενα. Μπορούν να χρησιμοποιηθούν ως βοηθητικές μέθοδοι. Ένα παράδειγμα μπορείτε να δείτε παρακάτω. | + | Εκτός από //default// μεθόδους ένα interface μπορεί να περιέχει και στατικές (//static//) μεθόδους. Οι στατικές μέθοδοι ορίζονται σε αναλογία με τις στατικές μεθόδους των κλάσεων και ουσιαστικά ανήκουν στις κλάσεις που θα υλοποιήσουν το interface και όχι στα αντικείμενα. Ένα παράδειγμα μπορείτε να δείτε παρακάτω. |
| <code java StringInverter.java> | <code java StringInverter.java> | ||
| public interface StringInverter { | public interface StringInverter { | ||
| - | /* inverts a string | + | /** inverts a string |
| */ | */ | ||
| String invert(String str); | String invert(String str); | ||
| - | /* splits a string in half and inverts | + | /** splits a string in half and inverts |
| * the two parts | * the two parts | ||
| */ | */ | ||
| Line 352: | Line 360: | ||
| } | } | ||
| | | ||
| - | /* Removes character at index from String str | + | /** removes character at index from String str |
| * and returns the new String. | * and returns the new String. | ||
| */ | */ | ||
| Line 373: | Line 381: | ||
| </code> | </code> | ||
| + | <WRAP 80% important center round> | ||
| + | **__Παρατήρηση:__** Οι **static** μέθοδοι στην Java υλοποιούνται στην έκδοση 8 της γλώσσας. Μεταγλωττιστές που ανήκουν σε προηγούμενες εκδόσεις αδυνατούν να μεταγλωττίσουν τον παραπάνω κώδικά. | ||
| + | </WRAP> | ||
| + | | Προηγούμενο : [[ :java:abstract_classes | Abstract Κλάσεις ]] | [[ :toc | Περιεχόμενα ]] | Επόμενο: [[ :java:access_modifiers | Περιοριστές πρόσβασης ]] | | ||