java:interfaces
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| java:interfaces [2017/01/31 14:32] – [Ορίζοντας ένα Interface] gthanos | java:interfaces [2017/02/03 09:51] (current) – removed gthanos | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Διεπαφές (Interfaces) ====== | ||
| - | |||
| - | ===== Εισαγωγικά ===== | ||
| - | |||
| - | Κατά την ανάπτυξη προγραμμάτων είναι σημαντικό να είναι τυποποιημένος ο τρόπος αλληλεπίδρασης ανάμεσα σε διαφορετικά συστήματα. Η ύπαρξη ενός " | ||
| - | |||
| - | Υπακούοντας στην παραπάνω αρχή, η Java εισάγει την έννοια της διεπαφής (**interface**). Τα // | ||
| - | - τους προγραμματιστές που το χρησιμοποιούν και | ||
| - | - τους προγραμματιστές που το υλοποιούν. | ||
| - | |||
| - | Οι πρώτοι γράφουν την εφαρμογή τους ώστε να χρησιμοποιεί τις μεθόδους του interface για να παρέχει συγκεκριμένη λειτουργικότητα. | ||
| - | |||
| - | Οι δεύτεροι, | ||
| - | |||
| - | Από τα παραπάνω εξάγεται ότι το // | ||
| - | |||
| - | Ως παράδειγμα, | ||
| - | * **setTimer: | ||
| - | * **startTimer: | ||
| - | * **endTimer: | ||
| - | |||
| - | Ας υποθέσουμε τώρα ότι ένας κατασκευαστής ηλεκτρικών συσκευών (κλιμαστιστικά, | ||
| - | |||
| - | Οποιοσδήποτε προγραμματιστής χρησιμοποιεί το παραπάνω // | ||
| - | |||
| - | Αντιπαραθέστε μια κατάσταση όπου οι συσκευές δεν τηρούν αυτό το συμβόλαιο. Σε αυτή την περίπτωση κάθε συσκευή θα έπρεπε να υλοποιεί τον δικό της timer. Η προτυποποίηση που παρέχει ο μηχανισμός του // | ||
| - | - την εύκολη και χωρίς σφάλματα επαναχρησιμοποίηση κώδικα σε διαφορετικά προγράμματα ή | ||
| - | - την αλλαγή της υφιστάμενης υλοποίησης μιας κλάσης, | ||
| - | |||
| - | ===== Ορίζοντας ένα Interface ===== | ||
| - | |||
| - | Ένα // | ||
| - | |||
| - | <code java> | ||
| - | double E = 2.718282; | ||
| - | double PI = 3.14159; | ||
| - | </ | ||
| - | |||
| - | Τα πεδία αυτά εξ ορισμού (by default) '' | ||
| - | |||
| - | Οι μέθοδοι σε ένα interface κατά κανόνα είναι **abstract**, | ||
| - | |||
| - | <code java> | ||
| - | public interface MyInterface extends Interface1, Interface2, Interface3 { | ||
| - | |||
| - | // constant declarations | ||
| - | // base of natural logarithms | ||
| - | double E = 2.718282; | ||
| - | double PI = 3.14159; | ||
| - | |||
| - | // method signatures | ||
| - | public void interfaceMethod1(int i, double x); | ||
| - | public int interfaceMethod2(String s); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== Υλοποιώντας ένα Interface ===== | ||
| - | |||
| - | Θα δείξουμε την υλοποίηση ενός interface μέσα από ένα παράδειγμα. | ||
| - | |||
| - | Μια πολύ συνηθισμένη χρήση interfaces είναι για το χαρακτηρισμό αντικειμένων τα οποία μπορούν να συγκριθούν μεταξύ τους: | ||
| - | |||
| - | Η μέθοδος '' | ||
| - | <code java> | ||
| - | public interface Comparable | ||
| - | { | ||
| - | int compareTo(Object other); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Μια κλάση που υλοποιεί το Comparable πρέπει να υλοποιήσει τη μέθοδο '' | ||
| - | |||
| - | Ας δούμε ένα παράδειγμα πάνω στην κλάση Rectangle που έχουμε ορίσει σε προηγούμενες ενότητες. Σύμφωνα με το documentation του interface Comparable η μέθοδος **compareTo** πρέπει να επιστρέφει ακέραιο αρνητικό, | ||
| - | |||
| - | <code java Rectangle.java> | ||
| - | import java.util.Arrays; | ||
| - | |||
| - | public class Rectangle implements Comparable { | ||
| - | private int width = 0; | ||
| - | private int height = 0; | ||
| - | private Point origin; | ||
| - | |||
| - | public Rectangle() { | ||
| - | origin = new Point(0, 0); | ||
| - | } | ||
| - | public Rectangle(Point p) { | ||
| - | origin = p; | ||
| - | } | ||
| - | public Rectangle(int w, int h) { | ||
| - | origin = new Point(0, 0); | ||
| - | width = w; | ||
| - | height = h; | ||
| - | } | ||
| - | public Rectangle(Point p, int w, int h) { | ||
| - | origin = p; | ||
| - | width = w; | ||
| - | height = h; | ||
| - | } | ||
| - | |||
| - | public void move(int x, int y) { | ||
| - | origin.setX(x); | ||
| - | origin.setY(y); | ||
| - | } | ||
| - | |||
| - | public int getArea() { | ||
| - | return width * height; | ||
| - | } | ||
| - | | ||
| - | @Override | ||
| - | public int compareTo(Object other) { | ||
| - | Rectangle otherRect = (Rectangle) other; // απαραίτητο για να μπορεί να κληθεί η getArea | ||
| - | return this.getArea() - otherRect.getArea(); | ||
| - | } | ||
| - | | ||
| - | @Override String toString() { | ||
| - | return origin + ", [" + width + " X " + height + " | ||
| - | } | ||
| - | | ||
| - | public static void main(String args[]) { | ||
| - | Rectangle [] shapes = new Rectangle[4]; | ||
| - | shapes[0] = new Rectangle(4, | ||
| - | shapes[1] = new Rectangle(1, | ||
| - | shapes[2] = new Rectangle(2, | ||
| - | shapes[3] = new Rectangle(9, | ||
| - | | ||
| - | System.out.println(" | ||
| - | for (Rectangle rectangle : shapes) { | ||
| - | System.out.println(rectangle + ", area: " + rectangle.getArea()); | ||
| - | } | ||
| - | | ||
| - | Arrays.sort(shapes); | ||
| - | | ||
| - | System.out.println(" | ||
| - | for (Rectangle rectangle : shapes) { | ||
| - | System.out.println(rectangle + ", area: " + rectangle.getArea()); | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | |||
| - | Για να εκτελέσετε το παράδειγμα κατεβάστε την κλάση '' | ||
| - | |||
| - | ===== Χρησιμοποιώντας ένα interface ως τύπο δεδομένων ===== | ||
| - | |||
| - | Μπορείτε να χρησιμοποιήσετε ένα Java Interface ως ένα reference τύπο δεδομένων. Μπορείτε να χρησιμοποιήσετε το όνομα ενός interface ως τον τύπο μιας παραμέτρου σε μία Java μέθοδο ή τύπο μιας τοπικής μεταβλητής στο σώμα μίας μεθόδου. Προϋπόθεση είναι οι τιμές των μεταβλητών να δείχνουν σε αντικείμενα των οποίων οι κλάσεις υλοποιούν το συγκεκριμένο interface. Δείτε το παρακάτω παράδειγμα. | ||
| - | |||
| - | Αρχικά ορίζουμε ένα interface με όνομα MyComparable το οποίο ορίζει τη μέθοδο isLarger που επιστρέφει true ή false ανάλογα με το αν το τρέχον αντικείμενο είναι μεγαλύτερο ή μικρότερο της παραμέτρου : | ||
| - | |||
| - | <code java MyComparable.java> | ||
| - | public interface MyComparable { | ||
| - | public boolean isLarger(MyComparable other); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Γράφουμε την Rectangle ώστε να υλοποιεί και το νέο μας interface: | ||
| - | <code java Rectangle.java> | ||
| - | public class Rectangle implements Comparable, MyComparable{ | ||
| - | | ||
| - | // the Rectangle class has 3 fields | ||
| - | 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, | ||
| - | } | ||
| - | | ||
| - | public Rectangle(int initWidth, int initHeight) { | ||
| - | this(initWidth, | ||
| - | } | ||
| - | |||
| - | 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 int compareTo(Object other) { | ||
| - | Rectangle otherRect = (Rectangle) other; | ||
| - | return (this.getArea() - otherRect.getArea()); | ||
| - | } | ||
| - | |||
| - | @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() { | ||
| - | | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Τώρα, μπορούμε να ορίσουμε την κλάση '' | ||
| - | |||
| - | <code java TwosComparator.java> | ||
| - | public class TwosComparator { | ||
| - | | ||
| - | public MyComparable findLargest(MyComparable object1, MyComparable object2) { | ||
| - | if (object1.isLarger(object2)) | ||
| - | return object1; | ||
| - | else | ||
| - | return object2; | ||
| - | } | ||
| - | | ||
| - | public MyComparable findSmallest(MyComparable object1, MyComparable object2) { | ||
| - | if (!(object1.isLarger(object2))) | ||
| - | return object1; | ||
| - | else | ||
| - | return object2; | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Χρησιμοποιούμε την TwosComparator ως εξής: | ||
| - | <code java Main.java> | ||
| - | public class Main { | ||
| - | |||
| - | public static void main(String args[]) { | ||
| - | Rectangle rec1 = new Rectangle(30, | ||
| - | Rectangle rec2 = new Rectangle(10, | ||
| - | TwosComparator comp = new TwosComparator(); | ||
| - | |||
| - | System.out.println(" | ||
| - | System.out.println(" | ||
| - | |||
| - | System.out.println( comp.findLargest(rec1, | ||
| - | System.out.println( comp.findSmallest(rec1, | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== Μεταβάλλοντας ένα υφιστάμενο Interface ===== | ||
| - | |||
| - | Κάποιες φορές στον προγραμματισμό εμφανίζεται η ανάγκη να μεταβάλλουμε ένα υφιστάμενο interface ή να το επεκτείνουμε. Το πρόβλημα σε αυτές τις περιπτώσεις είναι ότι οι κλάσεις που υλοποιούν το συγκεκριμένο interface με την προσθήκη ή αλλαγή των υφιστάμενων μεθόδων θα πάψουν να το υλοποιούν. Επομένως μία μονομερής αλλαγή του interface δεν είναι εφικτή. Παρόλα αυτά υπάρχουν δύο εναλλακτικές που μπορούν να μας καλύψουν. | ||
| - | |||
| - | |||
| - | **1η εναλλακτική: | ||
| - | <code java> | ||
| - | public interface DoIt { | ||
| - | |||
| - | void doSomething(int i, double x); | ||
| - | int doSomethingElse(String s); | ||
| - | } | ||
| - | |||
| - | public interface DoItPlus extends DoIt { | ||
| - | |||
| - | | ||
| - | |||
| - | } | ||
| - | </ | ||
| - | |||
| - | **2η εναλλακτική: | ||
| - | <code java> | ||
| - | public interface DoIt { | ||
| - | |||
| - | void doSomething(int i, double x); | ||
| - | int doSomethingElse(String s); | ||
| - | | ||
| - | // Method body | ||
| - | | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== Default μέθοδοι ===== | ||
| - | |||
| - | <WRAP 80% important center round> | ||
| - | **__Παρατήρηση: | ||
| - | </ | ||
| - | |||
| - | Ας θεωρήσουμε το παρακάτω υποθετικό interface | ||
| - | |||
| - | <code java StringInverter.java> | ||
| - | public interface StringInverter { | ||
| - | /** inverts a string | ||
| - | */ | ||
| - | String invert(String str); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Ας υποθέσουμε τώρα ότι η κλάση MyString υλοποιεί το παραπάνω interface. | ||
| - | |||
| - | <code java MyString.java> | ||
| - | import java.lang.*; | ||
| - | public class MyString implements StringInverter { | ||
| - | String invert(String str) { | ||
| - | StringBuffer strb = new StringBuffer(str); | ||
| - | return strb.reverse().toString(); | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Αν υποθέσουμε ότι το αρχικό interface αλλάζει στο παρακάτω | ||
| - | |||
| - | <code java StringInverter.java> | ||
| - | public interface StringInverter { | ||
| - | /** inverts a string | ||
| - | */ | ||
| - | String invert(String str); | ||
| - | /** splits a string in half and inverts | ||
| - | * the two parts. | ||
| - | */ | ||
| - | String invertHalf(String str); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Τώρα η κλάση MyString δεν υλοποιεί πλέον το αρχικό interface. Αυτό μπορεί να συνεχίσει να υλοποιείται εάν η νέα μέθοδος έχει μία default υλοποίηση μέσα στο interface όπως παρακάτω. | ||
| - | |||
| - | <code java StringInverter.java> | ||
| - | public interface StringInverter { | ||
| - | /* inverts a string | ||
| - | */ | ||
| - | String invert(String str); | ||
| - | /* splits a string in half and inverts | ||
| - | * the two parts | ||
| - | */ | ||
| - | default String invertHalf(String str) { | ||
| - | int len = str.length(); | ||
| - | | ||
| - | | ||
| - | | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | |||
| - | |||
| - | ===== Στατικές μέθοδοι ===== | ||
| - | |||
| - | Εκτός από //default// μεθόδους ένα interface μπορεί να περιέχει και στατικές (// | ||
| - | |||
| - | <code java StringInverter.java> | ||
| - | public interface StringInverter { | ||
| - | /** inverts a string | ||
| - | */ | ||
| - | String invert(String str); | ||
| - | /** splits a string in half and inverts | ||
| - | * the two parts | ||
| - | */ | ||
| - | default String invertHalf(String str) { | ||
| - | int len = str.length(); | ||
| - | | ||
| - | | ||
| - | | ||
| - | } | ||
| - | | ||
| - | /** removes character at index from String str | ||
| - | * and returns the new String. | ||
| - | */ | ||
| - | static String removeChar(String str, int index) { | ||
| - | if( str.length()-1 < index ) { | ||
| - | return str; | ||
| - | } | ||
| - | String str1 = str.substring(0, | ||
| - | String str2; | ||
| - | if( str.length() >= index-1 ) { | ||
| - | str2 = new String("" | ||
| - | } | ||
| - | else { | ||
| - | str2 = str.substring(index+1); | ||
| - | } | ||
| - | return str1+str2; | ||
| - | | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <WRAP 80% important center round> | ||
| - | **__Παρατήρηση: | ||
| - | </ | ||
| - | |||
| - | |||
| - | | Προηγούμενο : [[ :java:ant | Αυτόματη μεταγλώττιση με χρήση Apache Ant ]] | [[ :toc | Περιεχόμενα ]] | Επόμενο: | ||
| - | |||
| - | |||
java/interfaces.1485873167.txt.gz · Last modified: 2017/01/31 14:32 (external edit)
