This shows you the differences between two versions of the page.
|
java:generic_interface_example [2016/04/14 15:22] gthanos [Εισάγοντας μία νέα κλάση που υλοποιεί το Interface] |
java:generic_interface_example [2020/02/25 09:34] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Παράδειγμα δημιουργίας και χρήσης ενός interface ====== | ||
| - | |||
| - | Ας επανέλθουμε στο παράδειγμα [[java: | ||
| - | |||
| - | <code java MyComparable.java> | ||
| - | public interface MyComparable { | ||
| - | public boolean isLarger(MyComparable other) throws InvalidComparableTypeException; | ||
| - | public boolean isEqual(MyComparable other) throws InvalidComparableTypeException; | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Η κλάση **InvalidComparableTypeException** ορίζεται ως εξής: | ||
| - | <code java InvalidComparableTypeException.java> | ||
| - | class InvalidComparableTypeException extends Exception { | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | και είναι απαραίτητη ώστε να σηματοδοτήσουμε την πιθανή σύγκριση ασύμβατων μεταξύ τους τύπων δεδομένων. | ||
| - | |||
| - | Στη συνέχεια κατασκευάζουμε την κλάση Rectangle που υλοποιεί το συγκεκριμένο interface ως εξής: | ||
| - | |||
| - | <code java Rectangle.java> | ||
| - | public class Rectangle implements 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 boolean isLarger(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof Rectangle ) { | ||
| - | Rectangle otherRect = (Rectangle) other; | ||
| - | return (this.getArea() > otherRect.getArea()); | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | @Override | ||
| - | public boolean isEqual(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof Rectangle ) { | ||
| - | Rectangle otherRect = (Rectangle) other; | ||
| - | return (this.getArea() == otherRect.getArea()); | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | |||
| - | @Override | ||
| - | public String toString() { | ||
| - | return origin.toString() + ", " + width + " X " + height ; | ||
| - | } | ||
| - | |||
| - | public double getArea() { | ||
| - | | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Παρατηρήστε ότι υλοποιούμε το interface MyComparable συγκρίνοντας τα αντικείμενου τύπου Rectangle με βάση το εμβαδόν τους. Επιπλέον έχετε την κλάση MyComparableUtil που συγκρίνει αντικείμενα τύπου MyComparable ως εξής: | ||
| - | |||
| - | <code java MyComparableUtil.java> | ||
| - | public class MyComparableUtil { | ||
| - | /** | ||
| - | * Returns the larger among the two objects. If objects are equal returns null. | ||
| - | */ | ||
| - | public static MyComparable findLarger(MyComparable object1, MyComparable object2) throws InvalidComparableTypeException { | ||
| - | if(object1.isLarger(object2)) | ||
| - | return object1; | ||
| - | else if( object1.isEqual(object2) ) | ||
| - | return null; | ||
| - | return object2; | ||
| - | } | ||
| - | | ||
| - | /** | ||
| - | * Returns the smaller among the two objects. If objects are equal returns null. | ||
| - | */ | ||
| - | public static MyComparable findSmaller(MyComparable object1, MyComparable object2) throws InvalidComparableTypeException { | ||
| - | if(!object1.isLarger(object2)) | ||
| - | return object1; | ||
| - | else if( object1.isEqual(object2) ) | ||
| - | return null; | ||
| - | return object2; | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <code java CompareObjects.java> | ||
| - | public class CompareObjects { | ||
| - | public static void main (String []args) { | ||
| - | try { | ||
| - | Point p = new Point(1,1); | ||
| - | Rectangle rec1 = new Rectangle(10, | ||
| - | Rectangle rec2 = new Rectangle(10, | ||
| - | | ||
| - | System.out.println(" | ||
| - | } catch(InvalidComparableTypeException ex) { | ||
| - | System.err.println(" | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | |||
| - | Ας υποθέσουμε τώρα ότι θέλετε να φτιάξετε την κλάση Circle (άλλο διδιάστατο σχήμα) που υλοποιεί και αυτή το interface MyComparable. Δείτε την κλάση Circle παρακάτω. | ||
| - | |||
| - | <code java Circle.java> | ||
| - | public class Circle implements MyComparable{ | ||
| - | private Point origin; | ||
| - | private int radius; | ||
| - | |||
| - | public Circle(Point origin, int radius) { | ||
| - | this.origin = origin; | ||
| - | this.radius = radius; | ||
| - | } | ||
| - | | ||
| - | public void setOrigin(Point newOrigin) { | ||
| - | origin = newOrigin; | ||
| - | } | ||
| - | | ||
| - | public Point getOrigin() { return origin; } | ||
| - | | ||
| - | public void setRadius(int newRadius ) { | ||
| - | radius = newRadius; | ||
| - | } | ||
| - | | ||
| - | public int getRadius() { return radius; } | ||
| - | | ||
| - | public double getArea() { | ||
| - | return 3.14159 * radius * radius; | ||
| - | } | ||
| - | | ||
| - | @Override | ||
| - | public boolean isLarger(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof Circle ) { | ||
| - | Circle otherRect = (Circle) other; | ||
| - | return (this.getArea() > otherRect.getArea()); | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | @Override | ||
| - | public boolean isEqual(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof Circle ) { | ||
| - | Circle otherRect = (Circle) other; | ||
| - | return (this.getArea() == otherRect.getArea()); | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | public String toString() { | ||
| - | return origin.toString()+" | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Αν αναδιαμορφώσουμε την // | ||
| - | |||
| - | <code java CompareObjects.java> | ||
| - | public class CompareObjects { | ||
| - | public static void main (String []args) { | ||
| - | try { | ||
| - | Point p = new Point(1,1); | ||
| - | Rectangle rect = new Rectangle(10, | ||
| - | Circle circle = new Circle(p, 12); | ||
| - | | ||
| - | System.out.println(" | ||
| - | } catch(InvalidComparableTypeException ex) { | ||
| - | System.err.println(" | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | παρατηρούμε ότι η παραπάνω κλάση μεταγλωττίζεται, | ||
| - | |||
| - | <code java TwoDShape.java> | ||
| - | |||
| - | public abstract class TwoDShape implements MyComparable { | ||
| - | |||
| - | public final boolean isLarger(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof TwoDShape ) { | ||
| - | TwoDShape obj = (TwoDShape)other; | ||
| - | if( this.getArea() > obj.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | public final boolean isEqual(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof TwoDShape ) { | ||
| - | TwoDShape obj = (TwoDShape)other; | ||
| - | if( this.getArea() == obj.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | public abstract double getArea(); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <WRAP important 80% center round> | ||
| - | Παρατηρήστε τα εξής: | ||
| - | - Η μέθοδος isLarger για τα διδιάστατα σχήματα βασίζεται στη μέθοδο getArea(). Η μέθοδος getArea() ορίζεται στην κλάση TwoDShape, αλλά η υλοποίηση της εξαρτάται από το εκάστοτε διδιάστατο σχήμα. Κατά συνέπεια, | ||
| - | - H μέθοδος isLarger συγκρίνει τα διδιάστατα σχήματα με βάση το εμβαδό τους. Προκειμένου κάποια υποκλάση να μην επαναορίσει την μέθοδο isLarger με τρόπου που δεν είναι επιθυμητός, | ||
| - | </ | ||
| - | |||
| - | Με βάση τα παραπάνω οι κλάσεις Rectangle και Circle γίνονται ως εξής: | ||
| - | |||
| - | <code java Rectangle.java> | ||
| - | public class Rectangle extends TwoDShape { | ||
| - | | ||
| - | // 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 String toString() { | ||
| - | return origin.toString() + ", " + width + " X " + height ; | ||
| - | } | ||
| - | |||
| - | public double getArea() { | ||
| - | | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <code java Circle.java> | ||
| - | |||
| - | public class Circle extends TwoDShape { | ||
| - | private Point origin; | ||
| - | private int radius; | ||
| - | |||
| - | public Circle(Point origin, int radius) { | ||
| - | this.origin = origin; | ||
| - | this.radius = radius; | ||
| - | } | ||
| - | | ||
| - | public void setOrigin(Point newOrigin) { | ||
| - | origin = newOrigin; | ||
| - | } | ||
| - | | ||
| - | public Point getOrigin() { return origin; } | ||
| - | | ||
| - | public void setRadius(int newRadius ) { | ||
| - | radius = newRadius; | ||
| - | } | ||
| - | | ||
| - | public int getRadius() { return radius; } | ||
| - | | ||
| - | public double getArea() { | ||
| - | return 3.14159 * radius * radius; | ||
| - | } | ||
| - | | ||
| - | public String toString() { | ||
| - | return origin.toString()+" | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Επιχειρώντας τώρα να τρέξετε τη κλάση CompareObjects παρατηρήστε ότι τρέχει χωρίς πρόβλημα. | ||
| - | |||
| - | ===== Εισάγοντας μία νέα κλάση που υλοποιεί το Interface ===== | ||
| - | |||
| - | Σε αναλογία με τα παραπάνω ας υποθέσουμε ότι φτιάχνουμε την κλάση ThreeDShape που υλοποιεί και αυτή το interface | ||
| - | |||
| - | <code java ThreeDShape.java> | ||
| - | |||
| - | public abstract class ThreeDShape implements MyComparable { | ||
| - | |||
| - | public final boolean isLarger(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof ThreeDShape ) { | ||
| - | ThreeDShape obj = (ThreeDShape)other; | ||
| - | if( this.getArea() > obj.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | public final boolean isEqual(MyComparable other) throws InvalidComparableTypeException { | ||
| - | if( other instanceof ThreeDShape ) { | ||
| - | ThreeDShape obj = (ThreeDShape)other; | ||
| - | if( this.getArea() == obj.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | throw new InvalidComparableTypeException(); | ||
| - | } | ||
| - | | ||
| - | public abstract double getVolume(); | ||
| - | | ||
| - | public abstract double getArea(); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <code java Cuboid.java> | ||
| - | public class Cuboid extends ThreeDShape { | ||
| - | Rectangle rec; | ||
| - | int depth; | ||
| - | | ||
| - | public Cuboid( Rectangle rec, int depth) { | ||
| - | this.rec = rec; | ||
| - | this.depth = depth; | ||
| - | } | ||
| - | | ||
| - | public double getVolume() { | ||
| - | return rec.getArea() * depth; | ||
| - | } | ||
| - | | ||
| - | public double getArea() { | ||
| - | return 2 * ( depth * rec.getWidth() + depth * rec.getHeight() + rec.getArea() ); | ||
| - | } | ||
| - | | ||
| - | public String toString() { | ||
| - | return rec.toString() + " ,depth: " | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Ας υποθέσουμε τώρα ότι επιχειρούμε να μεταγλωττίσουμε και να τρέξουμε την παρακάτω έκδοση της κλάσης CompareObjects | ||
| - | |||
| - | <code java CompareObjects.java> | ||
| - | public class CompareObjects { | ||
| - | public static void main (String []args) { | ||
| - | try { | ||
| - | Point p = new Point(1,1); | ||
| - | Rectangle rect = new Rectangle(10, | ||
| - | Cuboid cuboid = new Cuboid(rect, | ||
| - | | ||
| - | System.out.println(" | ||
| - | } catch(InvalidComparableTypeException ex) { | ||
| - | System.err.println(" | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | Ο παρακάτω κώδικας ΔΕΝ θα έπρεπε να δουλεύει καθώς επιχειρεί να συγκρίνει ένα διδιάστατο με ένα τρισδιάστατο σχήμα που είναι μη συγκρίσιμα. Πράγματι δεν δουλεύει καθώς παράγει ένα exception InvalidComparableTypeException. __Ιδανικά θα θέλαμε ένα σφάλμα αυτού του τύπου να το αντιληφθούμε κατά την μεταγλώττιση του προγράμματος και όχι κατά την εκτέλεση του__. | ||
| - | |||
| - | Η λύση στο πρόβλημα είναι η χρήση παραμετρικών τύπων δεδομένων (generics). __Οι παραμετρικοί τύποι δεδομένων έχουν την δυνατότητα να αντιλαμβάνονται ασυμβατότητες τύπων δεδομένων κατά την εκτέλεση και όχι κατά την μεταγλώττιση.__ Δείτε πως διαμορφώνονται όλες οι παραπάνω κλάσεις με χρήση generics. | ||
| - | |||
| - | <code java MyComparable.java> | ||
| - | |||
| - | public interface MyComparable< | ||
| - | public boolean isLarger(T other); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <code java TwoDShape.java> | ||
| - | public abstract class TwoDShape implements MyComparable< | ||
| - | |||
| - | public final boolean isLarger(TwoDShape other) { | ||
| - | if( this.getArea() > other.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | | ||
| - | public final boolean isEqual(TwoDShape other) { | ||
| - | if( this.getArea() > other.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | | ||
| - | public abstract double getArea(); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <code java ThreeDShape.java> | ||
| - | public abstract class ThreeDShape implements MyComparable< | ||
| - | |||
| - | public final boolean isLarger(ThreeDShape other) { | ||
| - | if( this.getArea() > other.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | | ||
| - | public final boolean isEqual(ThreeDShape other) { | ||
| - | if( this.getArea() > other.getArea() ) | ||
| - | return true; | ||
| - | else | ||
| - | return false; | ||
| - | } | ||
| - | | ||
| - | public abstract double getArea(); | ||
| - | public abstract double getVolume(); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <code java MyComparableUtil.java> | ||
| - | public class MyComparableUtil <T extends MyComparable< | ||
| - | | ||
| - | public T findLarger(T object1, T object2) { | ||
| - | if (object1.isLarger(object2)) | ||
| - | return object1; | ||
| - | else | ||
| - | return object2; | ||
| - | } | ||
| - | | ||
| - | public T findSmaller(T object1, T object2) { | ||
| - | if (!(object1.isLarger(object2))) | ||
| - | return object1; | ||
| - | else | ||
| - | return object2; | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | <WRAP important 80% center round> | ||
| - | Παρατηρήστε ότι δεν έχει νόημα η παραγωγή του InvalidComparableTypeException, | ||
| - | </ | ||
| - | |||
| - | Αν προσπαθήσετε να μεταγλωττίσετε την CompareObjects θα δείτε ότι είναι αδύνατον να το κάνετε. | ||
| - | |||
| - | <code java CompareObjects.java> | ||
| - | public class CompareObjects { | ||
| - | public static void main (String []args) { | ||
| - | try { | ||
| - | Point p = new Point(1,1); | ||
| - | Rectangle rect = new Rectangle(10, | ||
| - | Cuboid cuboid = new Cuboid(rect, | ||
| - | | ||
| - | MyComparableUtil util = new MyComparableUtil(); | ||
| - | | ||
| - | System.out.println(" | ||
| - | } catch(InvalidComparableTypeException ex) { | ||
| - | System.err.println(" | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||