Seminar Softwareentwicklung Dynamisches Laden und Binden in Java
Seminar Softwareentwicklung Dynamisches Laden und Binden in Java Reinhard Stumptner
Dynamisches Laden und Binden in Java l l 2 Der Lebenszyklus eines Typs Der Lebenszyklus eines Objekts Dynamisches Binden Eigene Lader Reinhard Stumptner
Der Lebenszyklus eines Typs 3 Der Lebenszyklus eines Typs Reinhard Stumptner
Class-File laden l Drei Hauptaktivitäten: – – – l l l 4 Erzeugen eines binären Datenstroms umwandeln dieser Daten in interne Strukturen (Method Area) Erzeugen einer Instanz von java. lang. Class Die Class - Instanz dient als Interface zwischen Programm und internen Datenstrukturen (Method Area) Geladen wird entweder mit dem Bootstrap Class Loader (Teil der JVM) oder mit benutzerdefinierten Ladern Benutzerdefinierte Lader könnten z. B. Dateien von einem Netzwerk laden oder verschlüsselte Dateien laden Der Lebenszyklus eines Typs Reinhard Stumptner
Class-File verifizieren l l Entspricht es der Semantik von Java? Prüfungen in der Verifikationsphase: – – – 5 Von final Klassen wurde nicht geerbt Final Methoden wurden nicht überschrieben Keine inkompatiblen Methodendeklarationen Einträge im Constant Pool sind untereinander konsistent Integritätsprüfung des Bytecodes Der Lebenszyklus eines Typs Reinhard Stumptner
Vorbereiten des Typs l l 6 Für die Klassenvariablen wird Speicher reserviert und mit „ 0“ initialisiert Anlegen zusätzlicher Datenstrukturen (Methodentabelle) Der Lebenszyklus eines Typs Reinhard Stumptner
Constant Pool auflösen 7 Der Lebenszyklus eines Typs Reinhard Stumptner
Initialisieren des Typs l l l Class Variable Initializer: class Class. Init { static int i=3*5*Math. random(); } Static Initializer: class Static. Init { static int i; static { i=13*Math. random(); } } 2 Schritte der Initialisierung: – – l 8 Initialisieren der direkten Superklasse (wenn nicht bereits initialisiert) Ausführen von <clinit>() (mit enthaltenen Initializern) Initialisierung vor erster aktiver Verwendung Der Lebenszyklus eines Typs Reinhard Stumptner
Initialisieren des Typs l Aktive vs. Passive Verwendung class A { static int x=10*Math. random(); static {System. out. println(“init A”); } } class B extends A { static int y=20*Math. random(); static {System. out. println(“init B”); } } class C { static { System. out. println(“init C”); } public static void main(String[] args) { int z=B. x; // aktive Verwendung von A, // passive Verwendung von B System. out. println(“finished”); } } Ausgabe: 9 init C init A finished Der Lebenszyklus eines Typs Reinhard Stumptner
Der Lebenszyklus eines Objekts l Das Erzeugen einer Instanz stellt den Beginn des Lebenszyklus eines Objekts dar, Garbage Collection (bzw. finalize()) dessen Ende Method Area Heap Class-Instanz für A Typinformation von A new A() 10 Der Lebenszyklus eines Objekts Reinhard Stumptner
Instanzieren einer Klasse l vier Arten: – new() A – obj = new A(); new. Instance()(java. lang. Class) Class my. Class=Class. for. Name(Name); Name obj = (Name) my. Class. new. Instance(); – clone() A – 11 obj 2 = obj. clone(); Deserialisieren eines Objekts mit get. Object(), enthalten in java. io. Object. Input. Stream Der Lebenszyklus eines Objekts Reinhard Stumptner
Instanzieren einer Klasse l Reservieren von Speicher am Heap – – l l 12 für Instanzvariablen der Klasse und die der Superklassen default Initialwert (0) Instanzvariablen mit den richtigen Startwerten versehen zumindest eine <init>() Methode wird erzeugt (Konstruktor) Der Lebenszyklus eines Objekts Reinhard Stumptner
Instanzieren einer Klasse public class Konstruktoren { public String name; public int min=0, max=10; (Initializer) public Konstruktoren(String name) { // Aufruf des default Konsruktors von Object, // Ausführen von „min=0“, „max=10“ this. name=name; } public Konstruktoren(String name, int min) { this(name); // kein Aufruf des Konsruktors von Object this. min=min; } } 13 Der Lebenszyklus eines Objekts Reinhard Stumptner
Freigeben eines Objekts l l 14 Programme können Speicher für Objekte am Heap reservieren, aber nicht explizit freigeben Garbage Collector Besitzt eine Klasse eine finalize() Methode, wird diese, vor Freigeben des Speichers des Objekts, ausgeführt Der Lebenszyklus eines Objekts Reinhard Stumptner
Freigeben eines Typs l 15 Typen werden, wenn sie nicht mehr benötigt werden, freigegeben, d. h. wenn sie nicht erreichbar sind Der Lebenszyklus eines Objekts Reinhard Stumptner
Dynamisches Binden – The Linking Model l l 16 Auflösen symbolischer Referenzen Dynamische Erweiterung Parent-Delegation Model Constant Pool Resolution Reinhard Stumptner
Auflösen symbolischer Referenzen l l l 17 . class Dateien werden beim Kompilieren durch symbolische Referenzen im Constant Pool verbunden Diese müssen vor Programmstart aufgelöst und durch direkte Referenzen ersetzt werden (constant pool resolution) frühe – späte Resolution The Linking Model Reinhard Stumptner
Dynamische Erweiterung l l Java Applikationen können zur Laufzeit entscheiden, welche Typen geladen und gebunden werden sollen Zwei Mechanismen: – java. lang. Class: (hier wird immer gebunden) l – java. lang. Class. Loader: (Binden offen) l 18 public static Class for. Name (String class. Name, boolean initialize, Class. Loader loader) throws Class. Not. Found. Exception; protected Class load. Class (String name, boolean resolve) throws Class. Not. Found. Exception; The Linking Model Reinhard Stumptner
Parent-Delegation Model l 19 Versucht ein Lader einen Typ zu laden, gibt er diesen Auftrag immer zuerst an seine Superklasse weiter. Am Ende dieser Aufrufkette steht der Bootstrap Class Loader Lader, der eine Klasse lädt: definierender Class Loader Lader, der einen anderen Lader mit dem Ladeprozess beauftragt: initialisierender Class Loader The Linking Model Reinhard Stumptner
Constant Pool Resolution l l Der Constant Pool ist mit Symboltabellen vergleichbar Struktur eines Eintrags: CONSTANT_Class_Eintrag { byte Tag(=7); short Namensindex; } 20 Constant Pool Resolution Typen der Einträge im Konstantenpool Reinhard Stumptner
Resolution von Klassen und Interfaces Auflösen einer symbolischen Referenz auf eine Klasse: 1. C und Superklassen laden – – – Wurde C noch nicht geladen, sucht die JVM nach C. class C binden, verifizieren und vorbereiten binäre Datenstruktur von C prüfen C wird initialisiert 3. Zugriffsrechte werden überprüft Verwendeter Lader: der, mit dem referenzierende Klasse geladen wurde 2. 21 Constant Pool Resolution Reinhard Stumptner
Resolution von Array Klassen l l l Anzahl der Dimensionen und Basistyp aus dem field descriptior auslesen. Anzahl von „[“ gibt Dimensionen an Basistyp: – primitiver Datentyp (erstes Zeichen ist kein „L“) l – l 22 Z…. boolean, B…. byte, I…. int, … Referenztyp diesen laden, binden Von Bootstrap geladen Constant Pool Resolution Reinhard Stumptner
Resolution von Feldern und Methoden l l l 23 CONSTANT_Fieldref: Klassen- oder Instanzvariable CONSTANT_Methodref: Methode einer Klassenvariablen, statische Methoden werden durch Referenz auf Typinformationen aufgelöst Constant Pool Resolution Reinhard Stumptner
Resolution von Feldern und Methoden l Direkte Referenzen von Instanzvariablen und –methoden entsprechen einem Offset class A { int x; String s=“Hello“; public void get. X(){return x; } } 24 Constant Pool Resolution A- Instanz 0 Zeiger in Method Area 1 x 2 s Reinhard Stumptner
Resolution von Feldern und Methodentabelle von A: 25 0 Zeiger auf wait() 1 Zeiger auf clone() 2 Zeiger auf equals() 3 Zeiger auf finalize() 4 Zeiger auf get. Class() 5 Zeiger auf hash. Code() 6 Zeiger auf notify() 7 Zeiger auf notify. All() 8 Zeiger auf to. String() 9 Zeiger auf get. X() Constant Pool Resolution Typinformation von Object Typinformation von A Reinhard Stumptner
Resolution von Strings l CONSTANT_String (java. lang. String), verweist auf CONSTANT_Utf 8 l Gleiche Strings verweisen auf selbe Instanz der Klasse String Resolution: String- Objekt wird erzeugt und als direkte Referenz eingetragen l 26 Constant Pool Resolution Reinhard Stumptner
Resolution von anderen Elementen im Constant Pool l l 27 CONSTANT_Integer, CONSTANT_Long, CONSTANT_Float und CONSTANT_Double werden direkt dargestellt: CONSTANT_Integer { byte tag=3; int wert; } CONSTANT_Name. And. Type und CONSTANT_Utf 8 werden nicht aufgelöst, sie können von anderen Einträgen referenziert werden Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation class Salutation { private static final String hello=“Hello, world!“; private static final String greeting=“Greetings, planet!“; private static final String salutation=“Salutations, orb!“; private static int choice=(int)(Math. random()*2. 99); public static void main(String[] args) { String s =hello; if (choice==1) s=greeting; else if (choice==2) s=salutation; System. out. println(s); } } Beim Initialisieren wird sichergestellt, dass alle Superklassen von Salutation initialisiert wurden. 28 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation l l 29 Verifikation: – Bytecode ist syntaktisch korrekt – Salutation entspricht der Java Semantik – Salutation wird die JVM nicht zum Absturz bringen (Jumps) Vom Compiler wurde. class Datei mit Constant Pool erzeugt Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation Symbolische Referenz zu “Hello, world!“ 30 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation Symbolische Referenzen von Salutation zu Math. random() 31 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation Symbolische Referenz zu System. out 32 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation Symbolische Referenz zu Print. Stream. println() 33 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation private static int choice=(int)(Math. random()*2. 99); <clinit>(): 0 invokestatic #13 <Method double random()> java. lang. Math laden und binden direkte Referenz eintragen 3 ldc 2_w #14 <Double 2. 99> Wert 2. 99 6 dmul // Multiplikation 7 d 2 i// Konvertierung: double int 8 putstatic #10 <Field int choice> choice direkt referenzieren 11 return 34 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation main(): 0 ldc #2 <String “Hello, world!“> 2 astore_1 // speichert Referenz in 1. lokalen Variable // s = hello; 3 getstatic #10 <Field int choice> 6 iconst_1 // push 1 7 if_icompne 16 // if (choice == 1) (choice sei hier =2) 10 ldc #1 <String “Greetings, planet!“> 12 astore_1 // s = greeting; 13 goto 26 16 getstatic #10 <Field int choice> 19 iconst_2 // push 2 20 if_icompne 26 // if (choice == 2) 35 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation main(): 23 ldc #3 <String “Salutations, orb!“> 25 astore_1 // s = salutation; 26 getstatic #11 <Field java. io. Printstream out> 29 aload_1 // push s für System. out. println(s); 30 invokevirtual #12 <Method void println(java. lang. String) 33 return 36 Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation Auflösen der symbolischen Referenzen: l l 37 ldc #2 <String “Hello, world!“> – CONSTANT_String_info – String Objekt “Hello, world!“ wird erzeugt, Referenz vermerken – ldc_quick getstatic #10 <Field int choice> – Eintrag #10 wurde bei <clinit>() aufgelöst, getstatic_quick getstatic #10 <Field int choice> – bereits aufgelöst, getstatic_quick ldc #3 <String “Salutations, orb!“> – CONSTANT_String_info – String Objekt erzeugen, Referenz bei Eintrag #3 vermerken – ldc_quick Constant Pool Resolution Reinhard Stumptner
Beispiel: Salutation- Applikation Auflösen der symbolischen Referenzen: l l 38 getstatic #11 <Field java. io. Printstream out> – CONSTANT_Fieldref_info – java. lang. System laden und binden – Prüfung auf Vorhandensein eines statischen Feldes out – direkte Referenz zum Feld wird installiert, getstatic_quick invokevirtual #12 <Method void println(java. lang. String)> – CONSTANT_Methodref_info – java. io. Print. Stream laden und binden – Prüfung: Methode public, Rückgabe: void Parameter: String – invokevirtual_quick Constant Pool Resolution Reinhard Stumptner
Eigene Lader public class Base { public Base b; public Base() { b = null; System. out. println("t. Base Konstruktor"); } public void print() {System. out. println("t. Print Base"); } } public class Derived extends Base { public Derived() { System. out. println("t. Derived Konstruktor"); } } 39 Reinhard Stumptner
Eigene Lader 40 class My. Loader extends Class. Loader { public Class find. Class(String name) throws Class. Not. Found. Exception { Class new. Class=search. Loaded. Type(name); if (new. Class==null){ byte[] class. Data = load. Class. Data(name); new. Class=define. Class(name, class. Data, 0, class. Data. length); } return new. Class; } private byte[] load. Class. Data(String name) throws Class. Not. Found. Exception { File source=new File(name+". class"); Buffered. Input. Stream in=… byte[] b=new byte[in. available()]; in. read(b, 0, in. available()); return b; } Reinhard Stumptner
Eigene Lader Verwendung eines benutzerdefinierten Laders: My. Loader l=new My. Loader(); Class c 1=l. load. Class("Derived"); c 1. get. Class. Loader(); // Lader eines Typs kann // abgerufen werden java. lang. reflect. Method m; m=c 1. get. Method("print", null); Object o=c 1. new. Instance(); m. invoke(o, null); // Ausführen der Methode // print() des erzeugten // Objekts 41 Reinhard Stumptner
Eigene Lader class My. Decrypt. Loader extends Class. Loader { public Class find. Class(String name) throws Class. Not. Found. Exception{ class. Data = load. Class. Data(name, key); … } public byte[] load. Class. Data(String name, byte key){ byte[] b=null; in. read(b, 0, in. available()); for (int i=0; i<b. length; i++) b[i]=(byte)(b[i] ^ key); return b; } } 42 Reinhard Stumptner
Eigene Lader public class Compiling. Class. Loader extends Class. Loader { private boolean compile(String java. File) throws IOException { Process p = runtime. get. Runtime(). exec ("javac "+java. File); p. wait. For(); return p. exit. Value() == 0; } public Class load. Class(String name, boolean resolve) throws Class. Not. Found. Exception { Class c = null; if (!compile(name+". java") throw new Class. Not. Found. Exception(); … c = define. Class(name, raw, 0, raw. length); resolve. Class(c); } 43 Reinhard Stumptner
- Slides: 43