ΠΛΗΡΟΦΟΡΙΚΗ Ι JAVA Τμήμα θεωρίας με Α.Μ. σε 3, 7, 8 & 9 17/1/08 Constructors (Κατασκευαστές) Ειδικός τύπος μεθόδων που δημιουργούν αντικείμενα μιας κλάσης και: Εκτελούνται κατά την αρχικοποίηση των αντικειμένων Έχουν ίδιο όνομα με την κλάση Δεν επιστρέφουν κάποια τιμή Χρησιμοποιούνται για απόδοση τιμών στις μεταβλητές των αντικειμένων Π.χ., σε μια κλάση ClassName μπορεί να έχουμε τους εξής κατασκευαστές: public class ClassName public ClassName() public ClassName(int x, String b)... Οπότε, κατά τη δημιουργία αντικειμένου της ClassName από μια άλλη κλάση: ClassName obj = new ClassName(...); η κλήση ClassName(...) στο τέλος της εντολής αφορά κάποιον κατασκευαστή της κλάσης ClassName. Το ποιος κατασκευαστής τελικά θα κληθεί καθορίζεται από το πλήθος και τον τύπο των ορισμάτων (τιμές παραμέτρων) που θα υπάρχουν μέσα στην παρένθεση. Ο πρώτος κατασκευαστής (ClassName()) ονομάζεται default constructor. Υπάρχει σε κάθε κλάση, αυτόματα από τη Java, και ας μην εμφανίζεται στον κώδικα. Όταν όμως κάποιος φτιάξει έστω και έναν δικό του κατασκευαστή, τότε ο default constructor παύει να υπάρχει (δηλ. να παρέχεται αυτόματα από τη Java), οπότε εάν η ύπαρξή του είναι απαραίτητη (για να μπορούν να δημιουργούνται αντικείμενα με την απλή κλήση δημιουργού ClassName(), χωρίς παραμέτρους εισόδου), τότε πρέπει να γραφεί και ο default constructor, όπως στο παράδειγμα παραπάνω. 1
Παράδειγμα: public class Circle private double x, y; // συντεταγμένες του κέντρου του κύκλου private double r; // ακτίνα του κύκλου (*) public double area() return Math.PI*Math.pow(r,2); public double circumf() return 2*Math.PI*r; Η κλάση αυτή θα μπορούσε να έχει μία μέθοδο που να δέχεται τιμές για τα x, y και r. Επειδή όμως κάθε αντικείμενο της Circle θα πρέπει να έχει κάποια τιμή τουλάχιστον για το r, μπορούμε να την αυτοματοποιήσουμε αυτή τη διαδικασία, με τους constructors. Οπότε, στο σημείο του αστερίσκου παραπάνω, προσθέτουμε τους ακόλουθους κατασκευαστές: (*) public Circle(double a, double b, double c) x = a; y = b; r = c; public Circle(double r) x = 0; y = 0; this.r = r; public Circle() x = 0; y = 0; r = 1; Σημείωση 1: Όταν το όνομα μιας τοπικής μεταβλητής συμπίπτει με το όνομα μιας μεταβλητής κλάσης (όπως στην περίπτωση του r στους δεύτερο κατασκευαστή παραπάνω), στα σημεία που «υπάρχουν» και οι δύο μεταβλητές (δηλ. στη μέθοδο της τοπικής μεταβλητής) η αναφορά στη μεταβλητή κλάσης γίνεται με τον τελεστή this ως 2
εξής: this.<μεταβλητή>, ενώ η τοπική μεταβλητή αναφέρεται κανονικά με το όνομά της. Άρα στον δεύτερο κατασκευαστή της Circle, με την εντολή «this.r = r;» η μεταβλητή r της κλάσης παίρνει την τιμή της τοπικής μεταβλητής r του κατασκευαστή. Υπο-σημείωση 1: Ο όρος «μεταβλητή κλάσης» ταυτίζεται με τον όρο «μεταβλητή αντικειμένου». Οι μεταβλητές κλάσης ανήκουν στα αντικείμενα των κλάσεων. Σημείωση 2: Όπως αναφέρθηκε και προηγουμένως, όταν φτιάξουμε έστω και έναν δικό μας κατασκευαστή, ο default constructor παύει να δίνεται αυτόματα από τη Java και αν θέλουμε να υπάρχει τότε πρέπει να τον φτιάξουμε και αυτόν. Επίσης, όπως φαίνεται και παραπάνω, ο default constructor που φτιάχνουμε εμείς δεν είναι απαραίτητο να είναι κενός. Οπότε, σε μια άλλη κλάση, η δημιουργία αντικειμένων της Circle μπορεί να γίνει ως εξής: Circle circle1 = new Circle(2.3, 4.2, 5); Circle circle2 = new Circle(4); Circle circle3 = new Circle(); Τι είναι το API (Applications Programming Interface) Σε κάθε κλάση υπάρχουν πεδία (μεταβλητές και μέθοδοι) public και private. Τα private στοιχεία προορίζονται για εσωτερική χρήση της κλάσης και οι λεπτομέρειες των λειτουργιών τους δεν είναι απαραίτητο να είναι γνωστές σε κάποιον που θα χρησιμοποιήσει την κλάση (η διαδικασία αυτής της απόκρυψης των λεπτομερειών της κλάσης λέγεται ενθυκάκωση (encapsulation)). Τα public στοιχεία της κλάσης, τα οποία μπορούν να χρησιμοποιηθούν από άλλες κλάσεις αποτελούν το API της κλάσης, ή αλλιώς τη διασύνδεση χρήστη (μαζί με τα σχόλια που υπάρχουν στην κλάση και περιγράφουν τις λειτουργίες της). 3
Η Κλάση String Κάθε αλφαριθμητικό (string) είναι αντικείμενο της κλάσης String. Τρόποι δημιουργίας: i) Με τη χρήση εισαγωγικών: String str = Hello ; ii) Με τους τελεστές = και += πάνω σε υπάρχοντα strings: Hello + there --νέο string--> Hello there iii) Με κανονική δημιουργία αντικειμένου μέσω της new: String str1 = new String(); String str2 = new String( Hello ); Η κλάση String έχει δύο constructors: a) public String() b) public String(String value) Βασικές μέθοδοι της String public int length() επιστρέφει το πλήθος των χαρακτήρων π.χ., String a = Hello there! ; int x = a.length(); // x=12 public char charat(int index) επιστρ. τον χαρ/ρα στο σημείο index π.χ., char y = a.charat(4); // y= o (η αρίθμηση ξεκινάει από το 0) public boolean equals(string str) true αν βρει ίδιο μήκος και ακριβώς ίδιους χαρακτήρες, false διαφορετικά. π.χ., String b = Hello ; boolean z = a.equals(b); // z=false 4
public int compareto(string str) σύγκριση μήκους π.χ., Hello.compareTo( Hello again ); // <0 Hello again.compareto( Hello ); // >0 Hello.compareTo( Hello ); // ==0 public String touppercase() public String tolowercase() π.χ., String c = a.touppercase; // c = HELLO THERE! Σημείωση: Η equals ελέγχει για ισότητα της τιμής δύο αντικειμένων. Ο τελεστής == ελέγχει για ταύτιση δύο αντικειμένων π.χ., String d = Hello there! ; boolean f = a.equals(d); boolean g = (a==d); // f=true // g=false Παράδειγμα με strings Μέθοδος που ελέγχει αν ένα string είναι παλίνδρομο (διαβάζεται και ανάποδα): public boolean ispalindrome(string s) int n = s.length(); for (int i=0; i<n/2; i++) if (s.charat(i)!= s.charat(n-1-i)) return false; return true; Π.χ., boolean b = ispalindrome( anna ); // b = true 5
Πίνακες (Arrays) 1-D 0 1 2 2-D 3-D 0 0 1 1 2 2 3 3 array[3][2] array[0][1] Γενική δήλωση πίνακα (στη Java οι πίνακες είναι αντικείμενα): elementtype [ ] arrayname = new elementtype [size]; // 1-D π.χ. int n = 10; double [ ] myarray = new double [n]; 2-D: elementtype [ ][ ] arrayname = new elementtype [size1][size2]; Αρχικές τιμές: 0 Αρχικοποίηση σε συγκεκριμένες τιμές: elementtype [ ] arrayname = value1, value2,...; π.χ., int [ ] daysinmonth = 31, 28, 31, 30, 31,...; ή int [ ] daysinmonth = new int [12]; daysinmonth[0] = 31; daysinmonth[1] = 28; daysinmonth[2] = 31; daysinmonth[3] = 30;... ΠΡΟΣΟΧΗ: Το daysinmonth[12] δεν υπάρχει! 12 είναι το μέγεθος του πίνακα. Το index πάει από 0 έως 11. 6
Η length επιστρέφει το μέγεθος ενός πίνακα: double [ ] a = new double [10]; int x = a.length; // x=10 Οπότε, μια καλή μέθοδος αυτοματοποιημένης αρχικοποίησης ενός πίνακα: (παράδειγμα): int [ ] arr = new int [100]; for (int i=0; i<arr.length; i++) arr[i] = 1; Στην περίπτωση 2-D πινάκων: double [ ][ ] a = new double [20][10]; for (int i=0; i<a.length; i++) for (int j=0; j<a[0].length; j++) a[i][j] = 1.0; Το 0 στο a[0].length θα μπορούσε να είναι οποιοσδήποτε ακέραιος μεταξύ 0 και 9 εφόσον ο a είναι ορθογώνιος πίνακας (όλες η γραμμές έχουν τον ίδιο αριθμό στοιχείων), και δίνει το πλήθος των στοιχείων των στηλών του πίνακα. Παραδείγματα: 1-D: Εσωτερικό γινόμενο διανυσμάτων: double [ ] x = new double [N]; // το Ν έχει ήδη αρχικοποιηθεί double [ ] y = new double [N]; double sum = 0.0; for (int i=0; i<n; i++) sum += x[i]*y[i]; 7
Αντιστροφή στοιχείων: double [ ] b = new double [N]; // το Ν έχει ήδη αρχικοποιηθεί for (int i=0; i<n/2; i++) double temp = b[i]; b[i] = b[n-1-i]; b[n-1-i] = temp; Αντιγραφή: double [ ] c = new double [N]; for (int i=0; i<n; i++) c[i] = b[i]; Σημείωση: με c=b τα b και c αναφέρονται στο ίδιο array (αντικείμενο). Δηλαδή αν άλλαζε κάποιο στοιχείο στον ένα πίνακα, αυτόματα θα άλλαζε και στον άλλο. 8