Αρχικοποίηση Αντικειµένων & Κλάσεων στη Java Object Instantiation & Class Initialisation Κώστας Σαΐδης saiko@di.uoa.gr http://daemon.di.uoa.gr/daemon/issue4 Μάρτιος 2004
Η Αρχή είναι το ήµισυ του Παντός ηµιουργία Στιγµιοτύπων, µεταβλητές και µέθοδοι Στιγµιοτύπων Αρχικοποίηση Κλάσεων, Στατικές µεταβλητές και µέθοδοι static instance initializers Παρανοήσεις που οδηγούν σε λάθη = bugs. Το Πρότυπο Σχεδίασης Singleton Που ναι η main; a a Παρουσιάστηκε στη συνάντηση του Τεύχους 4 ως µπόνους! 2/34
Στιγµιοτύπιση (Constructors & Κληρονοµικότητα, Constructor Overloading και Instance Initializers) 3/34
Ισχύει Ολα τα πεδία αρχικοποιούνται σε default τιµές (0,, false, null), αν δεν τους ανατεθούν ϱητά Ολα τα αντικείµενα µε κενό extends κληρονοµούν από το java.lang.object Οι constructors δεν κληρονοµούνται, αλλά παρέχεται αναφορά σε αυτούς του γονέα µε την super() Αν δε δηλωθεί constructor, το αντικείµενο αποκτά τον default {super(); Ακόµα και όταν δηλωθεί, πάντα πρώτη καλείται η super(), εκτός αν καθοριστεί διαφορετικά (πχ super(new Foo()) ή this()) 4/34
public class A { protected int i ; A ( ) { System. out. println ("Constructor A()" ) ; A( int i ) { System. out. println ("Constructor A(int)" ) ; this. i = i ; class B extends A { public String tostring ( ) { return String. valueof ( i ) ; class C extends B { C ( ) { System. out. println ("Constructor C()" ) ; i += 1; class D extends A { D ( ) { super ( 1 0 ) ; System. out. println ("Constructor D()" ) ; public String tostring ( ) { return String. valueof ( i ) ; 5/34
CALL new A ( ) Constructor A ( ) A@f6a746 CALL new B ( ) Constructor A ( ) 0 CALL new C ( ) Constructor A ( ) Constructor C ( ) 1 CALL new D( ) Constructor A( int ) Constructor D( ) 10 6/34
Constructor Overloading this() Υπάρχει η δυνατότητα για constructor overloading (όπως και στις µεθόδους) Χρήση του this() ώστε να είναι δυνατή η κλήση ενός constructor από άλλον Αν υπάρχει this() δεν καλείται το super() Κεντρικό σηµείο αρχικοποίησης του αντικειµένου Επαναχρησιµοποίηση, καλύτερη διαχείριση και συντήρηση του κώδικα 7/34
public class E extends A { private int j ; private int k ; E ( ) { this ( DEFAULT_I, DEFAULT_J, DEFAULT_K ) ; E( int j ) { this ( DEFAULT_I, j, DEFAULT_K ) ; E( int j, int k ) { this ( DEFAULT_I, j, k ) ; E( int i, int j, int k ) { super ( i ) ; this. j = j ; this. k = k ; //blah blah public String tostring ( ) { return i + ", " + j + ", " + k ; private static f i n a l int DEFAULT_I = 1 ; private static f i n a l int DEFAULT_J = 2 ; private static f i n a l int DEFAULT_K = 3 ; 8/34
CALL new E(10, 20) Constructor A( int ) 1, 10, 20 CALL new E(1000) Constructor A( int ) 1, 1000, 3 9/34
Instance Initializer { Μπλοκ κώδικα που εκτελείται αµέσως µετά την κλήση στο super() και πριν συνεχίσει ο έλεγχος στο υπόλοιπο σώµα του constructor Κανονική πρόσβαση στα πεδία και τις µεθόδους του αντικειµένου 10/34
public class F extends A { private int j ; //instance i n i t i a l i z e r { System. out. println ("Instance initializer" ) ; i = 10; F ( int j ) { super ( 5 ) ; this. j = j ; public String tostring ( ) { return i + ", " + j ; 11/34
CALL new F(10) Constructor A( int ) Instance i n i t i a l i z e r 10, 10 CALL new F(100) Constructor A( int ) Instance i n i t i a l i z e r 10, 100 12/34
Αρχικοποίηση Κλάσεων static πεδία, µέθοδοι και static initializers 13/34
Ο κύκλος ωής µιας κλάσης ➀ Φόρτωση κλάσης από έναν Class Loader ➁ Linking (a) Verify (b) Prepare (c) Resolve ➂ Αρχικοποίηση ➃ Χρήση ηµιουργία Στιγµιοτύπων Garbage Collection & Finalization ➄ και προεραιτικά, Unload a a Προσοχή : Μια κλάση γίνεται unload αν και µόνο αν ο Class Loader που την όρισε γίνει garbage collected 14/34
Class Loader; Τι ναι τούτο; Εεεε. Αυτό που λέει το ονοµά του... Σε µία εφαρµογή είναι δυνατό να υπάρχουν πολλοί τέτοιοι (πχ Web Browser, Servlet Container). Παρέχεται ο default ή bootstrap class loader του Virtual Machine java.lang.classloader: Μπορείς να ϕτιάξεις κι εσύ έναν (για να ϕορτώνει τις κλάσεις από µία ϐάση δεδοµένων, πχ) Ο bootstrap είναι στιγµιότυπο του ClassLoader SecureClassLoader URLClassLoader 15/34
Ισχύει Μια κλάση προσδιορίζεται από το όνοµά της και τον Class Loader που την ϕόρτωσε Σε runtime, µια κλάση αναπαρίσταται ως στιγµιότυπο της κλάσης java.lang.class (Reflection) Περισσότερα σε άλλη παρουσίαση 16/34
Αρχικοποίηση Κλάσεων Ισχύει Αν µια κλάση ϕορτωθεί µε Class Loader εκτός του bootstrap, δεν υπάρχει εγγύηση ότι ϑα αρχικοποιηθεί µόνο µια ϕορά σε ένα Virtual Machine Αρχικοποίηση κλάσης αµέσως πριν τη χρήση κάποιου χαρακτηριστικού της (πεδίο ή µέθοδο) ή τη στιγµιοτύπισή της Αρχικοποίηση κλάσης Στατικά πεδία, µέθοδοι και initializers (static) Οτι είναι static ανήκει στην κλάση και όχι στο αντικείµενο / στιγµιότυπό της non-static variable x cannot be referenced from a static context 17/34
public class G extends A { static { System. out. println ("Class G Static Initializer" ) ; foo = Foo.DEFAULT; public G ( ) { super ( count ++); System. out. println ("Constructor G()" ) ; protected G( int i ) { super ( i ) ; System. out. println ("Constructor G(int)" ) ; public String tostring ( ) { return foo + " " + i ; private static int count = 0 ; protected static String foo ; interface Foo { public static f i n a l String DEFAULT = "foo"; public static f i n a l int DEFAULT_INT = 1 ; 18/34
CALL new G( ) Class G Static I n i t i a l i z e r Constructor A( int ) Constructor G( ) foo 0 CALL new G( ) Constructor A( int ) Constructor G( ) foo 1 CALL new G( ) Constructor A( int ) Constructor G( ) foo 2 19/34
Σύνοψη & Συµπεράσµατα 20/34
Αρχικοποίηση Κλάσεων Ι Lazy Αρχικοποίηση στην πρώτη ενεργό χρήση ενός στοιχείου της κλάσης ηλαδή, µια κλάση αρχικοποιείται ακριβώς πριν : 1. Τη δηµιουργία ενός στιγµιοτύπου της 2. Την κλήση µίας στατικής µεθόδου της 3. Την ανάθεση τιµής σε στατικό πεδίο της 4. Την αναφορά σε στατικό πεδίο της, αλλά όχι σε έκφραση που είναι compile-time constant (πχ 3 * Math.PI) Η αρχικοποίηση µιας κλάσης αρχικοποιεί την υπερ-κλάση της 21/34
Αρχικοποίηση Κλάσεων ΙΙ ιαδικασία ➀ Εκτέλεση της διαδικασίας για την υπερ-κλάση της εκτός αν είναι η java.lang.object ➁ Αρχικοποίηση των static πεδίων της ➂ Εκτέλεση των static initializers µε τη σειρά που εµφανίζονται στον πηγαίο κώδικα 22/34
Στιγµιοτύπιση Αντικειµένων I ηµιουργία ενός νέου στιγµιοτύπου µε τη ϱητή (ή όχι a ) κλήση ενός constructor έσµευση της απαιτούµενης µνήµης για όλα τα (instance) πεδία της κλάσης του αντικειµένου και των γονικών της κλάσεων Ακριβώς πριν επιστραφεί η αναφορά στο νέο στιγµιότυπο στον καλούντα : a πχ String concatenation: "ja" + "va" 23/34
Στιγµιοτύπιση Αντικειµένων II ➀ Πέρασµα των παραµέτρων στον constructor ➁ Αν ο constructor: (a) καλεί την this(), εκτέλεση της διαδικασίας γι αυτήν την κλήση από το ϐήµα ➀ αναδροµικά (b) δεν είναι του java.lang.object, εκτέλεση της διαδικασίας για την (ϱητή ή µη) κλήση του super() από το ϐήµα ➀ αναδροµικά ➂ Εκτέλεση των instance initializers και των αρχικοποιήσεων των instance πεδίων της κλάσης µε τη σειρά που εµφανίζονται στον πηγαίο κώδικα (από πάνω προς τα κάτω, από αριστερά προς τα δεξιά) ➃ Εκτέλεση του υπόλοιπου σώµατος του constructor 24/34
public class H extends G{ static { System. out. println ("Class H Static Initializer" ) ; j = Foo. DEFAULT_INT ; //instance { i n i t i a l i z e r System. out. println ("Class H Instance initializer" ) ; i += i ; public H ( ) { super ( j ) ; System. out. println ("Constructor H()" ) ; static void applydefaults (G g ) { g. i = Foo.DEFAULT_INT ; G. foo = Foo.DEFAULT; private static int j ; 25/34
CALL new H( ) Class G Static I n i t i a l i z e r Class H Static I n i t i a l i z e r Constructor A( int ) Constructor G( int ) Class H Instance i n i t i a l i z e r Constructor H( ) foo 2 CALL new H( ) Constructor A( int ) Constructor G( int ) Class H Instance i n i t i a l i z e r Constructor H( ) foo 2 CALL H. applydefaults (h) foo 1 26/34
Singleton ιασφάλιση της ύπαρξης µοναδικού στιγµιοτύπου για ένα αντικείµενο 27/34
Πρότυπο Σχεδίασης Singleton Παραδείγµατα περιπτώσεων που απαιτείται η ύπαρξη µοναδικού στιγµιοτύπου µιας κλάσης : database wrapper, print manager, configuration manager, interpreter Singleton Κλάση που διασφαλίζει την ύπαρξη µοναδικού στιγµιοτύπου και συνάµα παρέχει το κεντρικό σηµείο πρόσβασης σε αυτό Μοναδικό στιγµιότυπο κάτι ϑα πρέπει να είναι static Προβλήµατα µε την επέκταση µιας Singleton κλάσης Προσοχή στο thread safety της Singleton κλάσης Προσοχή στην απόκρυψη (hiding) µεθόδων 28/34
Προβλήµατα Singleton Κλάσεων I Κληρονοµικότητα Αν δηλωθεί private ο constructor όπως και πρέπει, κανονικά η κλάση δεν επεκτείνεται Εποµένως protected, αν υπάρχει η ανάγκη επέκτασης Thread Safety Πώς διασφαλίζεται η ύπαρξη µοναδικού στιγµιοτύπου (κλήση στον constructor µόνο µία ϕορά), σε περίπτωση που έχουµε πολλά threads; 29/34
import java. io. ; import java. u t i l. ; public class Configuration { private static f i n a l Configuration s e l f = new Configuration ( ) ; protected Properties props ; protected Configuration ( ) { System. out. println ("Configuration constructor..." ) ; props = new Properties ( ) ; //blah blah public static Configuration getinstance ( ) { return s e l f ; public void read ( InputStream i s ) throws IOException { props. load ( i s ) ; //blah blah public String getproperty ( String name ) { return props. getproperty (name, "" ) ; public String tostring ( ) { return "Configuration"; 30/34
Προβλήµατα Singleton Κλάσεων II Απόκρυψη & Κληρονοµικότητα εν ισχύει το override σε static µεθόδους. Nα παρέχεται πάντα η υλοποίηση της getinstance() για αποφυγή λαθών, εφόσον η Java ϑα χρησιµοποιήσει την πιο ειδική (most specific) µέθοδο. 31/34
public class SubConfiguration extends Configuration { private static f i n a l SubConfiguration s e l f = new SubConfiguration ( ) ; private SubConfiguration ( ) { System. out. println ("SubConfiguration constructor..." ) ; public String tostring ( ) { return "SubConfiguration"; class SubConfiguration2 extends Configuration { private static f i n a l SubConfiguration2 s e l f = new SubConfiguration2 ( ) ; private SubConfiguration2 ( ) { System. out. println ("SubConfiguration2 constructor..." ) ; public static Configuration getinstance ( ) { return s e l f ; public String tostring ( ) { return "SubConfiguration2"; 32/34
CALL Configuration. getinstance ( ) Configuration constructor... Configuration CALL SubConfiguration. getinstance ( ) Configuration CALL SubConfiguration2. getinstance ( ) Configuration constructor... SubConfiguration2 constructor... SubConfiguration2 33/34
Αναφορές Sheng Liang, Gilad Bracha Dynamic Class Loading in the Java Virtual Machine, OOPSLA 1998 James Gosling, Bill Joy, Guy Steele, Gilad Bracha The Java Language Specification, 2 nd Edition Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Design Patterns: Elements of re-usable object oriented software 34/34