Εισαγωγή στον Προγ/μό Η/Υ Ενότητα 7 2ο μέρος: Επιπλέον έννοιες σχετικά με αντικείμενα Διδάσκων: Μιχάλης Τίτσιας
Περιεχόμενα Τι μπορεί να περιέχει μια τάξη Μέθοδοι τάξης και σταθερές τάξης Πολυμορφισμός Κληρονομικότητα και προσπέλαση Κληρονομικότητα ως εξέλιξη ή ως εξειδίκευση Παύση της κληρονομικότητας H τάξη Object και η μέθοδος equals Πακέτα και οργάνωση τάξεων
Τι μπορεί να περιέχει μια τάξη Μεταβλητές στιγμιοτύπου: Καταγράφουν τα δεδομένα του αντικειμένου και αλλάζουν από αντικείμενο (δηλ. στιγμιότυπο της τάξης) σε αντικείμενο. Πχ num και den σε αντικείμενα της Rational είναι μεταβλητές στιγμιοτύπου. Κατασκευαστές. Μεθόδους στιγμιοτύπου: Μηνύματα που στέλνονται σε σε συγκεκριμένα αντικείμενα. Πχ r1.tostring() όπου r1 αντικείμενο της τάξης Rational. Μεθόδους τάξης (στατικές μέθοδοι τάξης): Μηνύματα που στέλνονται στην τάξη. Σταθερές τάξης: Σταθερές κοινές για όλα τα αντικείμενα της τάξης.
Τι μπορεί να περιέχει μια τάξη public class X { private int n; private int d; public X(int a, int b) { n = a; d = b; public String tostring() { return n+d; public void method1(arguments) { public static int method2(arguments) {.. Μεταβλητές στιγμιοτύπου Κατασκευαστής Μέθοδος στιγμιοτύπου Μέθοδος τάξης public final static double E = 2.7; Σταθερά τάξης
Μέθοδοι και σταθερές τάξης Η δεσμευμένη λέξη static είναι αυτή που καθορίζει της μεθόδους τάξης και σταθερές τάξης. Με τη σύνταξη ClassName.namemethod(arguments); ClassName.namevar; μπορούμε να καλέσουμε μια μέθοδο τάξης ή να αναφερθούμε σε μια σταθερά τάξης αντίστοιχα. Πχ σε ένα πρόγραμμα που χρησιμοποιεί την τάξη X που ορίσαμε στην προηγούμενη διαφάνεια θα μπορούσε να εμφανίζονται τις εντολές X.method2(arguments); double n1 = X.E;
Μέθοδοι τάξης: Παραδείγματα απο java.lang.* String.valueOf(43.33) // new String( 43.44 ) Integer.parseInt( 2011 ) // 2011 (τύπου int) Math.sqrt(2) // 2 (τύπου double) Math.log(10.32) // log(10.32) (τύπου double) Math.exp(-3.7) // e -3.7 (τύπου double) Math.pow(8.4, 9.2) // 8.4 9.2 (τύπου double) Math.sin(3.1415927/3) // ημ(π/3) (τύπου double) System.exit(1); // Τερματισμός προγράμματος // με κωδικό επιστροφής 1
Σταθερές τάξης: Παραδείγματα από java.* Math.PI // π (τύπου double) Math.E // e (τύπου double) Integer.MAX_VALUE // Η μεγαλύτερη τιμή int System.out // Αντικείμενο τάξης PrintStream π.χ., System.out.println( Hello world ); System.in // Αντικείμενο τάξης InputStream π.χ., Scanner sc = new Scanner(System.in); int i = sc.nextint(); // Ανάγνωση ακέραιας τιμής // από τον χρήστη
Σταθερές τάξης: Παραδείγματα από την γνωστή μας τάξη Color Χρώματα όπως Color.RED, Color.BLACK, κτλ.
Πολυμορφισμός Πολυμορφισμό έχουμε όταν η ίδια μέθοδος ή ο ίδιος τελεστής χρησιμοποιείται με διαφορετικούς τύπους δεδομένων. Για παράδειγμα ο τελεστής + είναι πολυμορφικός διότι μπορεί να χρησιμοποιηθεί με αριθμητικά δεδομένα αλλά και για την συνένωση αλφαριθμητικών. Πχ 3 + 4 Hello + World Στον αντικειμενοστρεφή προγραμματισμό ο πολυμορφισμός εμφανίζεται ως συνέπεια της κληρονομικότητας και του γεγονότος ότι η ίδια μέθοδος μπορεί να έχει διαφορετική λειτουργία σε διαφορετικά αντικείμενα.
Πολυμορφισμός Στο πρόγραμμα παρακάτω η μέθοδος tostring εμφανίζει πολυμορφισμό διότι στην πρώτη κλήση println(obj1.tostring()) οδηγεί στην κλήση της tostring που έχει οριστεί στην τάξη Object, ενώ στην δεύτερη περίπτωση println(obj2.tostring()) οδηγεί στην κλήση της tostring που έχει οριστεί στην τάξη Counter (ή οποία παρακάμπτει την αρχική tostring). public class Polymorphism extends Program { public void run() { Object obj1 = new Object(); println(obj1.tostring()); Counter obj2 = new Counter(); println(obj2.tostring());
Πολυμορφισμός Ο αποστολέας μηνυμάτων στα αντικείμενα δε χρειάζεται να ξέρει πως αυτά συμπεριφέρονται. Η χρήση αντικειμένων παλιών όσο και μελλοντικών τάξεων, από τον ίδιο κώδικα είναι δυνατή. Πχ αν είχαμε μια προγενέστερη έκδoση της Counter όπου η tostring δεν είχε οριστεί τότε η εντολή println(obj2.tostring()); στο ίδιο κυρίως πρόγραμμα της προηγούμενης διαφάνειας θα είχε διαφορετική λειτουργία αφού τώρα θα γινόταν κλήση στην tostring της τάξης Object.
Κληρονομικότητα και προσπέλαση Όταν δημιουργούμε μια υποκλάση που επεκτείνει μια υπάρχουσα υπερ-τάξη, τότε όλες οι μέθοδοι και τα δεδομένα της υπέρ-τάξης (μεταβλητές και σταθερές) κληρονομούνται στην υποκλάση. Ωστόσο το παραπάνω δεν σημαίνει ότι αντικείμενα της υπο-τάξης έχουν αυτομάτως πρόσβαση σε όλες τις μεθόδους και δεδομένα της υπέρ-τάξης. Αυτό εξαρτάται από το πώς έχει οριστεί η προσπέλαση (public, private κτλ). Για παράδειγμα αν στην υπέρ-τάξη υπάρχουν οι δηλώσεις μεταβλητών στιγμιοτύπου private int x; private int y; τότε αντικείμενα μιας υπό-τάξης δεν έχουν άμεση πρόσβαση στις τιμές αυτές. Πχ αν a είναι ένα αντικείμενο της υπό-τάξης τότε οι εντολές int n1= a.x*5; ή a.x++ θα οδηγούσαν σε σφάλμα κατά την μεταγλώττιση. Προκειμένου αντικείμενα της υπό-τάξης να αποκτήσουν πρόσβαση στις παραπάνω τιμές είτε θα αλλάξουμε τους ορισμούς στην υπέρ-τάξης ώστε protected int x; protected int y; το οποίο ενδεχομένως να μην είναι και τόσο καλή λύση (από την σκοπιά της αντικειμεστρεφούς σχεδίασης). Είτε θα ορίσουμε ειδικές μεθόδους στην υπέρ-τάξη της μορφής getvalue και setvalue με τις οποίες θα έχουμε (έμμεση) πρόσβαση στις τιμές x,y.
Κληρονομικότητα ως εξέλιξη RandomGenerator «Εξελίσσει την» RandomGeneratorImproved Η RandomGeneratorImproved είναι πιο εξελιγμένο «είδος» από τη RandomGenerator αφού κάνει ότι και η δεύτερη συν κάποιες επιπλέον λειτουργίες.
Κληρονομικότητα ως εξειδίκευση Shape area perimeter «Είναι» Circle area perimeter Η Circle είναι ένα Shape.
Κληρονομικότητα ως εξειδίκευση Shape area perimeter «Είναι» «Είναι» Circle Square area perimeter area perimeter Οι Circle και Square είναι Shape. Εδώ σε κάθε εξειδίκευση θα πρέπει να ξανά-οριστούν οι μέθοδοι area και perimeter.
Κληρονομικότητα ως εξειδίκευση class Shape { public double area() { return -1.0; public double perimeter() { return -1.0; Αντικείμενα Shape δεν έχουν νόημα. Μόνο αντικείμενα εξειδικευμένων ταξεών της (π.χ., Circle, Square) έχουν. Εντούτοις αναφορές σε Shape είναι χρήσιμες γιατί μπορούμε να γράφουμε «γενικό» κώδικα που θα δουλεύει στο μέλλον με όλα τα αντικείμενα κληρονόμων τάξεων (στα οποία αυτές οι αναφορές θα αναφέρονται.)
Κληρονομικότητα ως εξειδίκευση class Circle extends Shape { double r; // μήκος ακτίνας final double pi = 3.1415927; public double area() { return pi*r*r; public double perimeter() { return 2*pi*r; public Circle(double p) { r = p; class Square extends Shape { double s; // μήκος πλευράς public double area() { return s*s; public double perimeter() { return 4*s; public Square(double p) { s = p;
Κληρονομικότητα ως εξειδίκευση: Αφηρημένες τάξεις/μέθοδοι Ο προγραμματιστής μπορεί να δημιουργεί αφηρημένες (abstract) τάξεις. Η χρήση αναφορών αφηρημένων τάξεων επιτρέπεται Στις εξειδικευμένες τάξεις (π.χ., Square, Circle), πρέπει να οριστούν οι αφηρημένες μέθοδοι. abstract class Shape { public abstract double area(); // Αφηρημένη μέθοδος public abstract double perimeter(); // Αφηρημένη μέθοδος public String tostring() { // Μη αφηρημένη μέθοδος return Γειά σου, είμαι ένα σχήμα ;
Παύση της κληρονομικότητας Δεν επιτρέπεται η εξέλιξη της RationalV2 public final class RationalV2 extends Rational { public RationalV2(int a, int b) { super(a, b); public String tostring() {return 2*n+ / +2*d; Μπορούμε να κατασκευάζουμε αντικείμενα της RationalV2 αλλά δεν μπορούμε να την επεκτείνουμε, δηλ. τα ορίσουμε υποκλάσεις της. Στην Java ο τύπος δεδομένων String έχει οριστεί ως final class.
Η πρωταρχική τάξη Object Μπορούμε να γράφουμε «γενικό» κώδικα για αντικείμενα οποιασδήποτε τάξης; Ναι! Όλες οι τάξεις κληρονομούν την Object: class X { class X extends Object { ισοδύναμο με Μηνύματα της Object (υποστηρίζονται από όλα τα αντικείμενα κάθε τάξης): tostring(), equals(object b),
Μηνύματα τάξης Object tostring() obj1.tostring() String Object αναφ. Object Επιστρέφει String που περιγράφει το αντικείμενο: τάξη@μοναδικό_αναγνωριστικό
Μηνύματα τάξης Object tostring() obj1.tostring() String X Επιστρέφει String που περιγράφει το αντικείμενο, εάν οριστεί ξανά η tostring() στην τάξη X αναφ. Object
Μηνύματα τάξης Object tostring() 32 32 Integer αναφ. Integer Integer obj1 = new Integer(32); println(obj1.tostring());
Μηνύματα τάξης Object equals(obj2) boolean Object obj1.equals(obj2) αναφ. Object Η equals της Object επιστρέφει true εάν τα obj1, obj2 είναι ίσα Δηλαδή true, εάν αναφέρονται στο ίδιο αντικείμενο
Μηνύματα τάξης Object equals(obj2) obj1.equals(obj2) boolean Συνήθως αλλάζουμε την equals έτσι ώστε να είναι true εάν τα αντικείμενα που αναφέρονται οι αναφορές obj1, obj2 είναι ίσα. (Χωρίς να είναι κατ ανάγκη ίδια.) X αναφ. Object
Μηνύματα τάξης Object equals(obj2) 32 32 true Integer Integer αναφ. Integer αναφ. Integer Integer obj1 = new Integer(32); Integer obj2 = new Integer(32); println(obj1.equals(obj2)); // Όμως obj1!= obj2
Παράδειγμα: Μηνύματα τάξης Object public void run() { Rational r1 = new Rational(1,2); Rational r2 = new Rational(2,4); println(r1.equals(r2));
Μηνύματα τάξης Object Αντικατάσταση του equals στη RationalV3: class RationalV2 extends Rational { public boolean equals(object obj) { if ( obj instanceof Rational ) { // τελεστής instanceof Rational r = (Rational) obj; return n*r.d == d*r.n; else return false; Η boolean έκφραση obj instanceof X είναι true εάν και μόνο εάν το obj είναι αντικείμενο Χ ή υπο-τάξης της X.
Μηνύματα τάξης Object Δοκιμή με RationalV3: public void run() { RationalV3 r1 = new RationalV3(1,2); Rational r2 = new Rational(2,4); println(r1.equals(r2)); // Εμφανίζει true! println(r1.equals( 1/2 )); // Εμφανίζει false
Οργάνωση τάξεων στη Java πακέτο: σύνολο από σχετιζόμενες τάξεις String String String Program Scanner Rational RationalV3 RationalV2
Πρόσβαση μεταξύ πακέτων public class A { public int i; private int j; int k; protected int m; class C { C() { A a; a.i = 1; a.k = 2; class B extends A { B() { i = 1; m = 3; class D { D() { A a; a.i = 1;
Πρόσβαση μεταξύ πακέτων public class A { public int i; private int j; int k; protected int m; class C { C() { A a; a.i = 1; a.k = 2; class B extends A { B() { i = 1; m = 3; class D { D() { A a; a.i = 1;
Πρόσβαση μεταξύ πακέτων public class A { public int i; private int j; int k; protected int m; class C { C() { A a; a.i = 1; a.k = 2; class B extends A { B() { i = 1; m = 3; class D { D() { A a; a.i = 1;
Πρόσβαση μεταξύ πακέτων public class A { public int i; private int j; int k; protected int m; class C { C() { A a; a.i = 1; a.k = 2; class B extends A { B() { i = 1; m = 3; class D { D() { A a; a.i = 1;
Πρόσβαση μεταξύ πακέτων public class A { public int i; private int j; int k; protected int m; class C { C() { A a; a.i = 1; a.k = 2; a.m= 3; class B extends A { B() { i = 1; m = 3; class D { D() { A a; a.i = 1;
Οργάνωση τάξεων στη Java Ιεραρχική οργάνωση ονομάτων τάξεων Π.χ.: java.lang.string, java.util.scanner, acm.program.program, aueb.math.rationalv2 Ιεραρχική οργάνωση αρχείων.class (για μεταγλώττιση & εκτέλεση)
Ιεραρχική οργάνωση αρχείων πακέτο: σύνολο από σχετιζόμενες τάξεις CLASSPATH = C:\dir1 java F:\local acm aueb java lang util acm program aueb math lang util program math String.class Scanner.class Program.class ConsoleProgram.class Rational.class RationalV2.class RationalV3.class
Ιεραρχική οργάνωση αρχείων πακέτο: σύνολο από σχετιζόμενες τάξεις CLASSPATH = C:\dir1 java F:\local acm aueb java lang util acm program aueb math lang util program math String.class Scanner.class Program.class ConsoleProgram.class Rational.class RationalV2.class RationalV3.class
Ιεραρχική οργάνωση αρχείων πακέτο: σύνολο από σχετιζόμενες τάξεις CLASSPATH = C:\dir1 java acm.jar F:\local aueb java lang util aueb math lang util math String.class Scanner.class Rational.class RationalV2.class RationalV3.class
Ιεραρχική οργάνωση αρχείων πακέτο: σύνολο από σχετιζόμενες τάξεις CLASSPATH = C:\dir1 java acm.jar F:\local aueb java lang util aueb math lang util math String.class Scanner.class > cd F:\local > jar cf aueb.jar aueb Rational.class RationalV2.class RationalV3.class
Ιεραρχική οργάνωση αρχείων πακέτο: σύνολο από σχετιζόμενες τάξεις CLASSPATH = java lang util C:\dir1 java acm.jar F:\local aueb.jar aueb lang String.class util Scanner.class > cd F:\local > jar cf aueb.jar aueb
Ιεραρχική οργάνωση αρχείων πακέτο: σύνολο από σχετιζόμενες τάξεις CLASSPATH = java lang util C:\dir1 java acm.jar F:\local aueb aueb.jar lang util String.class Scanner.class
Οργάνωση τάξεων στη Java Αρχείο Rational.java: package aueb.math; // Οι ορισμοί που ακολουθούν είναι μέρος του πακέτου aueb.math public class Rational { // Πλήρες όνομα τάξης: aueb.math.rational int n; int d; public Rational(int a, int b) { n = a; d = b; public String tostring() { return n+ / +d; public void add(rational r) { n = n*r.d+d*r.n; d = d*r.d;
Οργάνωση τάξεων στη Java Αρχείο RationalV2.java: package aueb.math; // Οι ορισμοί που ακολουθούν είναι μέρος του πακέτου aueb.math public class RationalV2 extends Rational { // πλήρες όνομα: aueb.math.rationalv2 public RationalV2(int a, int b) { super(a, b); public String tostring() {reduce(); return n+ / +d; void reduce() {int m = gcd(n, d); n /= m; d /= m; int gcd(int a, int b) { if ( a == 0 ) return b; return b>a? gcd(b,a) : gcd(a%b, b);
Οργάνωση τάξεων στη Java Αρχείο Test.java: // δεν υπάρχει package.. = ανήκει στο «κενό» πακέτο import acm.program.*; public class Test extends Program { public void run() { aueb.math.rational r1 = new aueb.math.rational(1,2); println(r1.tostring());
Οργάνωση τάξεων στη Java Αρχείο Test.java: // δεν υπάρχει package.. = ανήκει στο «κενό» πακέτο import acm.program.*; import aueb.math; public class Test extends Program { public void run() { Rational r1 = new Rational(1,2); println(r1.tostring());
Οργάνωση τάξεων στη Java Αρχείο Test.java: // δεν υπάρχει package.. = ανήκει στο «κενό» πακέτο //import acm.program.*; import aueb.math; public class Test extends acm.program.program { public void run() { Rational r1 = new Rational(1,2); println(r1.tostring());
Οργάνωση τάξεων στη Java Αρχείο Test.java: // δεν υπάρχει package.. = ανήκει στο «κενό» πακέτο //import acm.program.*; //import aueb.math; public class Test extends acm.program.program { public void run() { aueb.math.rational r1 = new aueb.math.rational(1,2); println(r1.tostring());
Διάβασμα για το σπίτι Κεφάλαιο 6 από «Η Τέχνη και Επιστήμη της JAVA: Μια εισαγωγή στην Επιστήμη των Υεπολογιστών», E. Roberts Κεφάλαιο 5 και 6 του βιβλίου «Εισαγωγή στην JAVA», Γιώργος Λιακέας.