Faktenextraktion aus Java-Bytecode für Refaktorisierungswerkzeuge

Größe: px
Ab Seite anzeigen:

Download "Faktenextraktion aus Java-Bytecode für Refaktorisierungswerkzeuge"

Transkript

1 Fern-Universität Hagen Fachbereich Mathematik und Informatik Lehrstuhl Programmiersysteme Abschlussarbeit im Studiengang Master of Computer Science Wintersemester 2010/2011 Faktenextraktion aus Java-Bytecode für Refaktorisierungswerkzeuge Autor: Dipl.-Ing. (FH) Gabriel Wetzler Matrikel-Nr.: Adresse: Auf den Brechen Kreuzau Betreuer: Dipl.-Inf. Andreas Thies Stand: 10. April

2 Danksagung Herrn Prof. Dr. Steimann danke ich für die Ermöglichung, meine Masterarbeit im Bereich Programmiersysteme der FernUni Hagen anfertigen zu können. Insbesondere möchte ich mich bei meinem Betreuer Dipl.-Inf. Andreas Thies für die interessante Aufgabenstellung, seine Unterstützung, seine hilfreichen Ratschläge sowie die fachlichen Diskussionen und die Durchsicht der Arbeit bedanken. Ebenso möchte ich mich an dieser Stelle ganz herzlich bei meiner Frau Petra für ihr entgegengebrachtes Verständnis, ihre stetige Unterstützung sowie das Korrekturlesen der Arbeit bedanken. Außerdem geht ein großes Dankeschön an meine Eltern für deren Unterstützung in jeglicher Hinsicht, ganz besonders während der Anfertigung der Masterarbeit. 2

3 Inhaltsverzeichnis 1 Einleitung Motivation Aufgabenstellung Aufbau der Arbeit Erläuterungen zur Aufgabenstellung Der JVM Bytecode Das Class-File Format Class-File Strukturen Die Hauptstruktur (Class-File Struktur) Die Constant-Pool Tabelle Deskriptoren Feld-Deskriptoren Methoden-Deskriptoren Tabellen mit Bezug zum Constant-Pool Felder Methoden Attribute / Annotations Code Attribut Die Java-Virtual-Machine (JVM) Einführung Strukturen der JVM Die Method Area JVM Stack und Frames Die Execution Engine Typen der JVM Die Primitiven Typen Die Referenz-Typen Befehlssatz der JVM Bytecode Framework Bibliotheken BCEL Der FaktenExtraktor Der Programmablauf Deklarations-ID Interface zu Referenzen und Deklarationen Das FaktenExtraktor Interface Eine Anwendung Beispiel 1: Offene Rekursion Beispiel 2: Down-Cast Bemerkung Evaluierung Installation Was nicht analysiert werden kann Zusammenfassung Erklärung Anhänge...61 A. Interface Hierarchie

4 B. AST Parser...63 C. Inhalt der CD...65 D. Verzeichnisse

5 Einleitung 1 Einleitung 1.1 Motivation Das Wort Refactoring ist eine Neuschöpfung aus dem englischen Sprachbereich. Sie leitet sich aus dem Verständnis her, dass ein Programm aus einer Menge von Faktoren besteht, es also faktorisiert ist. Die Faktorisierung offenbart dabei einer innere Struktur des Programms. Ändert man die Faktorisierung, nennt man das folgerichtig Refaktorisierung [Steimann 1853][ 5]. Ein Refactoring beschreibt den Vorgang, bei dem der Code eines Programms verändert wird, ohne jedoch seine Funktionalität, also seine Bedeutung, zu ändern. Ziel dabei ist es, den Code verständlicher, einfacher änderbar bzw. wartbarer zu machen. Das Besondere dabei ist, dass diese Designverbesserung erfolgt, nachdem ein Softwareprojekt komplett oder teilweise implementiert worden ist. Es ist damit ein wirksames Werkzeug, um der sog. Softwarefäulnis entgegenzutreten. Hierunter versteht man den Umstand, dass bei notwendigen Änderungen am Programm lediglich die Änderungen am Code vorgenommen werden, die für die Funktionalität unbedingt notwendig sind. Dabei geht jedoch schnell die Struktur des Programms verloren. Um die Struktur eines Programms zu erhalten, muss jedoch oft ein wesentlich höherer Aufwand betrieben werden, als nur seine Funktionalität zu ändern. Die Methode des Extreme Programmings verzichtet sogar komplett auf die Designphase bei der Entwicklung und setzt statt dessen auf Refactoring als strukturbildende Maßnahme in Softwareprojekten [Steimann 1853][ 5.1]. Dennoch gelten Refactorings als eher lästige Aufgabe, die zu Fuß ausgeführt zudem noch sehr fehleranfällig und zeitaufwändig ist. In der Softwareindustrie wäre daher ein solches Vorgehen nicht akzeptabel. Die Kosten und das Risiko würden nämlich aus Sicht des Unternehmens die oben genannten Vorteile sehr schnell in den Schatten stellen. Es besteht also die Notwendigkeit, für diesen Prozess ein Werkzeug zur Verfügung zu stellen, welches die meisten Aufgaben schnell und zuverlässig erledigen kann. Versteht man unter einem bestimmten Refactoring eine bestimmte Codeänderung, beispielsweise die Umbenennung einer Methode, so kann man die hierfür notwendigen Tätigkeiten als einen Algorithmus formulieren. Dieser erhält als Eingabe den verbesserungswürdigen Code (und weitere Parameter, wie z.b. den neuen Namen der Methode...) und liefert als Ausgabe den verbesserten refaktorierten Code. Ein solcher Algorithmus, als Programm implementiert, ist ein Refactoring Tool. Refactoring Tools gehören daher zu den sog. Metaprogrammen. Um Refactorings durchzuführen, muss ein solches Werkzeug zunächst bestimmte Informationen bzgl. des zu refaktorisierenden Codes ermitteln. So muss ein Refactoring Tool, welches eine Methode umbenennt, beispielsweise feststellen, an welchen Stellen im Programmcode diese Methode referenziert wird. Diese Referenzen müssen dann ebenfalls entsprechend geändert werden. Fragestellungen dieser Art sollen durch das hier entwickelte Programm beantwortet werden. Als Informationsquelle dient dabei nicht, wie man wohl vermuten würde, der AST des Eingabecodes, sondern der aus einem Kompiliervorgang resultierende Bytecode. Dies hat zum einen den Vorteil, dass gewisse Informationen, die der Compiler dem Programm hinzufügt, mit betrachtet werden. Zum anderem eignet sich dieses Programm zur Analyse von allen Codes von Programmiersprachen, aus welchem JVM basierter Bytecode generiert werden kann. Für diese Arbeit steht jedoch die Programmiersprache Java im Vordergrund. 5

6 Einleitung 1.2 Aufgabenstellung Refaktorisierungswerkzeuge müssen, bevor sie ihre Aufgabe korrekt durchführen können, eine möglichst genaue Analyse des Sourcecodes durchführen. Dies erfolgt normalerweise durch Betrachtung des AST der zu refaktorisierenden Klassen. Dabei müssen beispielsweise Deklarationen und Referenzen aus dem Code extrahiert werden. Problematisch ist hier, dass sich die benötigten Informationen teils nicht aus dem Sourcecode ermitteln lassen. Beispielsweise sind vorhandene Defaultkonstruktoren von Java-Klassen nicht im Code sichtbar. Durch diese Arbeit soll untersucht werden, welche Fakten bzgl. des Sourcecodes aus einer Bytecodedatei ermittelt werden können. Hierfür soll eine Anwendung entwickelt werden, die möglichst vollständig die im Sourcecode enthaltenen Referenzen und Deklarationen ermittelt. Die Elemente beider Mengen sollen dabei möglichst mit all ihren Eigenschaften aufgeführt werden. Die Mengen sind derart miteinander zu verknüpfen, dass eine Baumstruktur entsteht, die die Struktur des Programmcodes widerspiegelt. Diese soll mittels eines geeigneten Interfaces zugänglich gemacht werden. 1.3 Aufbau der Arbeit Kapitel 1 gibt einen Überblick zur Aufgabenstellung. Kapitel 2 erläutert die Aufgabenstellung und definiert einige Ziele, die zu erreichen sind. Im Kapitel 3 werden einige Grundlagen vermittelt, deren Kenntnis zur Lösung der Aufgabenstellung notwendig ist. Der Fokus liegt dabei auf dem Aufbau von Bytecodedateien für die JVM und einem Überblick in die Funktionsweise der JVM. Zum einen soll dabei klar werden, welche Informationen aus Bytecodedateien ermittelt werden können. Zum anderen soll ein Verständnis vermittelt werden, wie und wo Referenzen entstehen. Dadurch wird erklärt, an welchen Stellen innerhalb von Bytecodedateien nach Referenzen gesucht werden kann. Im Kapitel 4 wird das zur Implementierung des Programms verwendete Framework BCEL vorgestellt. Im Kapitel 5 wird die Funktion des entwickelten Programms zur Ermittlung von Fakten aus Bytecodedateien vorgestellt. Kapitel 6 gibt ein Beispiel der Anwendung des FaktenExtraktors. Dabei wird dieser zur Prüfung von Vorbedingungen des RWID Refactorings, welches am Lehrgebiet für Programmiersysteme der FernUni Hagen entwickelt wurde, eingesetzt. Kapitel 7 vergleicht die Performance des FaktenExtraktors mit einem rudimentären AST Parser bezüglich der Laufzeit anhand von drei OpenSource Projekten. Kapitel 8 gibt einige Hinweise, die bei der Installation zu beachten sind. Kapitel 9 erläutert Elemente, die vom FaktenExtraktor nicht analysiert werden können. Kapitel 10 fasst diese Arbeit zusammen. 6

7 Erläuterungen zur Aufgabenstellung 2 Erläuterungen zur Aufgabenstellung Zunächst stellt sich die Frage, was genau Deklarationen und was Referenzen im Programmcode sind. Deklarationen sind jeweils die Definitionen von: Interfaces Klassen Feldern Methoden lokalen Variablen Methodenparametern Es gibt allerdings auch implizite Deklarationen, die nicht aus dem Programmcode ersichtlich sind. Dies sind Defaultkonstruktoren oder implizite Initialisierungsmethoden in Klassen, z.b. zur Initialisierung von statischen Variablen. Referenzen ergeben sich aus Bezügen auf Deklarationen. Hierzu zählen : Zugriffe auf Variablen, Felder und Methodenparameter, Aufrufe von Methoden oder Konstruktoren, Referenzen auf Typen, z.b. in Type Casts, in Methodensignaturen und Deklarationen von lokalen Variablen Die Menge der Referenzen kann demnach an die Menge der Deklarationen gekoppelt werden. Dabei kann sich eine Referenz immer nur auf eine bestimmte Deklaration beziehen. Dagegen können auf eine Deklaration beliebig viele Referenzen Bezug nehmen. Es besteht eine 1:n Beziehung zwischen Deklarationen und Referenzen. Deklarationen selbst können dabei auch Referenzen bilden. Dies ist bei der Deklaration eines Feldes, einer lokalen Variablen, einer Methode oder dem Überschreiben einer Methode der Fall. Derartige Deklarationen beziehen sich dabei auf eine Typdeklaration oder, falls eine Methode überschrieben wird, auf die Deklaration einer Methode. Diese Beziehungen können mittels entsprechender Eigenschaften von Deklarationen aufgelöst werden. Für die zu erzeugenden Objekte müssen einige Eigenschaften der Deklarationen bzw. Referenzen definiert werden, damit sie die für ein Refaktorisierungswerkzeug notwendigen Informationen bereitstellen können. Im Falle von Deklarationen sind dies z.b.: der Access Modifier der Bezeichner der deklarierte Typ (eine Referenz auf eine Deklaration) 7

8 Erläuterungen zur Aufgabenstellung der Ort, an dem sich die Deklaration befindet die Methodenparameter (im Falle einer deklarierten Methode oder eines deklarierten Konstruktors) eine Liste der Typparameter einer Klasse oder Methode die Supertypen einer Klasse eine Liste der implementierten Interfaces einer Klasse die Art der Deklaration (Package / Compilation-Unit / Klasse / abstrakte Klasse / Feld / Methode / abstrakte Methode) Im Falle von Referenzen sind dies beispielsweise: der Name, mit dem eine Deklaration referenziert wird der Ort, an dem die Referenz steht die Deklaration, an die die Referenz vom Compiler gebunden wird der Empfänger eines Methodenaufrufs bzw. Feldzugriffs Der Zugriff auf diese Mengen erfolgt dann über ein geeignetes Interface. 8

9 Der JVM Bytecode 3 Der JVM Bytecode Ein syntaktisch korrektes Java-Programm, welches in einem beliebigem Editor erstellt wurde, muss, bevor es zur Ausführung kommt, zunächst von einem Compiler in Java-Bytecode umgesetzt werden. Bei den klassischen Programmiersprachen, wie beispielsweise C / C++, übersetzt der zugehörige Compiler den Quelltext direkt in Befehlszyklen, die von einem bestimmten Prozessor verarbeitet werden können. Java geht hier einen anderen Weg. Programme werden als Quelltext in Dateien gespeichert und jede für sich von einem Compiler in Bytecode übersetzt. Abbildung 1: Implementierungsmöglichkeiten der JVM Dieser Bytecode ist unabhängig von einer bestimmten CPU oder einem bestimmten Betriebssystem. Der aus dem Compiler-Vorgang resultierende Bytecode ist jedoch nicht unmittelbar durch einen Prozessor verarbeitbar, sondern muss zunächst einer Java Virtual Machine (JVM) zugeführt werden. Eine Komponente der JVM, der ClassLoader, übernimmt das Laden und Linken mehrerer Bytecodedateien und legt diese dann in einer zur Verarbeitung optimierten Form im Speicher ab. Die JVM bildet eine CPU nach, die den Bytecode ausführen kann. Sie erzeugt dabei einen Maschinencode, der spezifisch für eine bestimmte CPU ist. JVM Implementierungen sind daher abhängig von einer bestimmten Betriebssystem/CPU-Kombination. Ziel dieses Vorgehens ist es, eine größere Flexibilität bei der Entwicklung und Verteilung von Anwendungen zu erhalten. Denn der vom Compiler generierte Bytecode ist im Prinzip auf jeder Maschine und jedem Betriebssystem ausführbar, für das es eine JVM gibt [Steimann 1814][ 4.1]. Ein weiterer Vorteil dieses Konzeptes ist es, dass durch die Verwendung unterschiedlicher Compiler auch aus anderen Programmiersprachen als Java Bytecode für JVM's generiert werden kann. Heute existieren außer Java weitere Programmiersprachen, z.b. ADA, C, PHP, Ruby oder Phyton, die eine JVM als Ausführungseinheit nutzen. 3.1 Das Class-File Format Ein Class-File entsteht durch das Kompilieren des Codes durch den Compiler. Der Dateiaufbau ist so gestaltet, dass möglichst kleine Dateien produziert werden. Bytecodedateien weisen dabei eine bestimmte Struktur auf, die wiederum aus mehreren ineinander verschachtelten Strukturen aufgebaut ist. Einige davon sind von variabler Größe, wodurch es nicht möglich ist, ein bestimmtes Feld durch einen Offset vom Dateianfang aus zu finden. Aus diesem Grund sind Bytecodedateien 9

10 Der JVM Bytecode nicht sehr performant auswertbar. Sie werden daher beim Laden durch den ClassLoader der JVM geparst. Die JVM wandelt sie dann intern in Strukturen um, die dann in bestimmte Speicherbereiche abgelegt werden (siehe auch Kapitel 3.3.3). Diese Strukturen weisen dann eine für die maschinelle Verarbeitung optimierte Form auf. Im Folgenden werden die Strukturen eines Class-Files näher betrachtet. 3.2 Class-File Strukturen Ein Class-File bezieht sich immer auf exakt eine Klasse oder ein Interface [JVMS][ 3.1]. Dabei kann eine Klasse auch Anonyme Klassen oder Innere Klassen enthalten. Ein Class-File besteht aus einer Folge von 8 Bit Bytes. Ein Wort kann dabei auch 16, 32 oder 64 Bit lang sein. In diesem Falle ist es dann aus mehreren 8 Bit Worten zusammengesetzt. Jedes dieser Wörter stellt ein Feld einer Struktur im Class-File dar. Alle Felder werden in einer durch die JVM- Spezifikation vorgeschriebenen Reihenfolge im Class-File notiert. Die Länge der Felder ist ebenfalls durch die JVM-Spezifikation vorgeschrieben. Einige Felder, meist handelt es sich um tabellenartige Auflistungen, haben eine variable Länge. In diesem Falle ist die Anzahl der Elemente, die in dieser Struktur gespeichert wird, durch ein weiteres Feld vor der entsprechenden Struktur angegeben. Es gibt ansonsten keine Start- oder Ende-Zeichen für Felder oder Strukturen Die Hauptstruktur (Class-File Struktur) Die Hauptstruktur eines Class-Files ist dabei immer eine Struktur vom Typ Class-File. Diese ist folgendermaßen aufgebaut [JVMS][4.1]: ClassFile { magic; (2 Byte) minor_version; (2 Byte) major_version; (2 Byte) constant_pool_count; (2 Byte) cp_info constant_pool[constant_pool_count-1]; access_flags; (2 Byte) this_class; (2 Byte) super_class; (2 Byte) interfaces_count; (2 Byte) interfaces[interfaces_count]; (2 Byte pro Interface) fields_count; (2 Byte) field_info fields[fields_count]; methods_count; (2 Byte) method_info methods[methods_count]; attributes_count (2 Byte); attribute_info attributes[attributes_count]; 10

11 Der JVM Bytecode Die Bedeutung der Felder ist dabei wie folgt: Feld magic minor_verison, major_version constant_pool_count constant_pool[] access_flags this_class super_class interfaces_count Interfaces[] fields_count field_info fields[] methods_count method_info methods[] attributes_count attribute_info attributes[] Bedeutung Version des Class-File Formates Version dieses Class-Files Anzahl der Einträge in der Constant-Pool Tabelle die Constant-Pool Tabelle kodiert den Zugriffsmodifier der korrespondierenden Klasse oder des Interfaces Index in Constant-Pool Tabelle (zeigt auf eine CONSTANT_Class_info Struktur) Index in Constant-Pool Tabelle (zeigt auf eine CONSTANT_Class_info Struktur, bezeichnet die Superklasse dieser Klasse) Anzahl der Interfaces der Superinterfaces dieser Klasse Indices der Constant-Pool Tabelle (zeigen auf eine CONSTANT_Class_info Struktur, bezeichnet die Superinterfaces dieser Klasse) Anzahl der Felder dieser Klasse Indices der Constant-Pool Tabelle (zeigt auf eine field_info Struktur, beschreibt Felder dieser Klasse) Anzahl der Methoden dieser Klasse Indices der Constant-Pool Tabelle (zeigt auf eine method_info Struktur, beschreibt Methoden dieser Klasse) Anzahl der Attribute Indices der Constant-Pool Tabelle (zeigt auf eine attribute_info Struktur, beschreiben Eigenschaften von Elementen dieser Klasse) Tabelle 1: Elemente der ClassFile Struktur 11

12 Der JVM Bytecode Alle hier als Array dargestellten Strukturen sind dabei ebenfalls Tabellen bzw. Listen, die im Folgenden weiter beschrieben werden Die Constant-Pool Tabelle Die Einträge in dieser Tabelle haben wiederum eine Struktur, welche in nachstehender Tabelle beschrieben ist. Die in der Constant-Pool Tabelle enthaltenen Elemente beziehen sich auf folgende Informationen: Namen von Methoden und Feldern der korrespondierenden Klasse die Klassen, die von der korrespondierenden Klasse referenziert werden Deskriptoren (für Felder und Methoden) numerische Konstanten String Konstanten Jeder Eintrag wird dabei mit einem sog. Tag eingeleitet. Ein Tag ist eine ganze Zahl, welche den Typ des Eintrags kodiert. Es folgt eine Instanz des Typs. Insgesamt gibt es 11 verschiedene Typen, die in der Constant-Pool Tabelle vorkommen können. Einer davon, CONSTANT_Utf8, hat eine variable Länge, die anderen haben feste Längen. Folgende Typen von Constant-Pool Einträgen werden in der JVM-Spezifikation definiert [JVMS] [ 4.4]: Name Aufbau Bedeutung CONSTANT_Utf8 Tag (= 1) Länge bytes[] Name, Bezeichner CONSTANT_Integer Tag (= 3) bytes Wert einer Integer Konstanten CONSTANT_Float Tag (= 4) bytes Wert einer Float Konstanten CONSTANT_Long CONSTANT_Double Tag (= 5) high_bytes low bytes Tag (= 6) high_bytes low bytes Wert einer Long Konstanten Wert einer Double Konstanten CONSTANT_Class Tag (= 7) Name-Index Index auf einen CONSTANT_Utf8 Eintrag, der den Namen einer Klasse enthält CONSTANT_String Tag (= 8) String-Index Index auf einen CONSTANT_Utf8 Eintrag, der den Wert des Strings enthält 12

13 Der JVM Bytecode Name Aufbau Bedeutung CONSTANT_Fieldref Tag (= 9) Class-Index NameType-Index CONSTANT_Methodref Tag (= 10) Class-Index NameType-Index CONSTANT_InterfaceMeth odref Tag (= 11) Class-Index NameType-Index CONSTANT_NameAndType Tag (= 12) Name-Index Deskriptor-Index Tabelle 2: Typen von Constant-Pool Einträgen Index eines CONSTANT_Class Eintrags (Name der Klasse, zu der dieses Feld gehört) und Index auf einen CONSTANT_NameAndType Eintrag (Name und Deskriptor des Feldes) Index eines CONSTANT_Class Eintrags (Name der Klasse, zu der diese Methode gehört) und Index auf einen CONSTANT_NameAndType Eintrag (Name und Deskriptor der Methode) Index eines CONSTANT_Class Eintrags (Name des Interfaces, zu dem diese Methode gehört) und Index auf einen CONSTANT_NameAndType Eintrag (Name und Deskriptor der Methode) Index auf einen CONSTANT_Utf8 (Name) Eintrag und Index auf einen CONSTANT_Utf8 (Descriptor) Eintrag Die Constant-Pool Tabelle hat also einige Referenzen auf sich selbst. Aus ihr können einige der Eigenschaften von Deklarationen und Referenzen der korrespondierenden Klasse abgeleitet werden. Vier Arten von Informationen können hier gefunden werden: numerische Werte von Konstanten Strings von Namen Verweise auf andere Einträge derselben Tabelle Deskriptoren (siehe Kapitel 3.2.3) Typ von Feldern Parameter und Typ von Methoden 13

14 Der JVM Bytecode Beispiel: Möchte man beispielsweise alle Methoden, die von der korrespondierenden Klasse referenziert werden, ermitteln, muss man alle Einträge mit Tag 10 (CONSTANT_Methodref), deren Class- Index nicht auf den Eintrag mit dem eigenen Klassennamen zeigt, auswählen. Die zugehörigen Namen erhält man, indem aus CONSTANT_Methodref der NameAndType-Index ermittelt wird. Der so ermittelte Name-Index verweist auf einen CONSTANT_Utf8 Eintrag, der den Namen der entsprechenden Methode darstellt Deskriptoren Es gibt zwei Arten von Deskriptoren: Feld-Deskriptoren und Methoden-Deskriptoren. Sie beschreiben den Typ von Feldern bzw. die Signatur von Methoden. Methoden-Signaturen der Java Sprache setzen sich aus dem Namen einer Methode und den Methodenparametern zusammen. Sie sind entscheidend beim dynamischen Binden von Methoden. Dynamisches Binden erfolgt jedoch zur Laufzeit einer Anwendung. Daher müssen diese Informationen der JVM zugänglich gemacht werden. Deskriptoren zu einem Feld oder einer Methode werden im Constant-Pool durch Einträge vom Typ CONSTANT_NameAndType an diese gebunden. Der Deskriptor selbst ist dann in einer Konstanten vom Typ CONSTANT_Utf8 als String abgelegt (siehe auch 2.1.2). Deskriptoren gehören zu einer Struktur vom Typ Attribut, welcher noch gesondert betrachtet wird Feld-Deskriptoren Diese beschreiben den Typ einer Klasse, einer Instanz oder einer lokalen Variablen. Der Typ wird dabei mittels eines konstanten Literals kodiert. Folgende Literale werden von der JVM Spezifikation benannt [JVMS][ 4.3.2]: Literal Type Bedeutung B Byte Byte Wert C Char Unicode Zeichen D Double Double Wert F Float FloatingPoint Wert I Int Integer Wert J Long Long Integer Wert L<Klassenname>; Referenz Eine Instanz der Klasse Klassenname S Short Short Integer Wert Z Boolean true oder false [<Komponententyp> Referenz Referenz auf ein Array Tabelle 3: Feld-Deskriptoren 14

15 Der JVM Bytecode Alle Literale außer 'L' und '[' gehören zu den Base Typen. Diese stellen die Integralen Typen der JVM dar (siehe auch Kapitel und [JVMS][ 3.3.1]). Der Komponententyp eines Arrays ist wiederum ein Literal aus obiger Tabelle. Beispiel: Der Deskriptor einer Variablen vom Typ Integer ist das Literal I. Der Deskriptor einer Variablen vom Typ String sieht folgendermaßen aus: Ljava/lang/String;. Der Deskriptor einer Referenz auf ein Array mit Elementen vom Typ Integer sieht wie folgt aus: [I;. Ein zweidimensionales Array mit Elementen vom Typ String sieht wie folgt aus: [[Ljava/lang/String; Methoden-Deskriptoren Ein Methoden-Deskriptor beschreibt die Parameter und den Rückgabewert einer Methode. Der Name ist hier nicht enthalten. Ein Methoden-Deskriptor ist dabei aus folgenden Elementen aufgebaut [JVMS][ 4.3.3]: ( Feld_Deskriptor_1,, Feld_Deskriptor_n ) Return_Deskriptor Der Return-Deskriptor ist dabei entweder ebenfalls ein Feld-Deskriptor oder ein Void-Deskriptor. Void-Deskriptoren werden durch das Literal 'V' dargestellt. Beispiel: Der Deskriptor der Methode Object method (String Name, long[][] werte) sieht wie folgt aus: (Ljava/lang/String;[[J)Ljava/lang/Object; Tabellen mit Bezug zum Constant-Pool Im Class-File gibt es noch drei weitere Tabellen mit Elementen, die sich auf den Constant-Pool beziehen. Hierbei handelt es sich um die field_info fields[], method_info methods[]und attribute_info Felder des ClassFile Typs. Dies sind Listen mit den Feldern, Methoden oder Attributen der mit dem ClassFile korrespondierenden Klasse Felder In dieser Tabelle können alle Informationen zu den in der korrespondierenden Klasse deklarierten Feldern gefunden werden. Die field_info fields[] Tabelle enthält Elemente vom Typ field_info, die wie folgt aufgebaut sind [JVMS][ 4.5]: field_info{ access_flags; (2 Bytes) name-index; (2 bytes) descriptor_index; (2 Bytes) attribute_count; (2 Byte) attribute_info[] attributes; 15

16 Der JVM Bytecode Die Bedeutung der Felder ist dabei wie folgt: Feld access_flags Name-Index descriptor_index attribute_count attribute_info[] attributes Bedeutung Ein Byte, das den Zugriffsmodifier eines Feldes kodiert. Dabei hat jedes Flag des Bytes die Bedeutung eines Zugriffsmodifiers (siehe ). Index auf einen CONSTANT_Utf8 Eintrag im Constant-Pool (Name des Feldes) Index auf einen CONSTANT_Utf8 Eintrag im Constant-Pool (Deskriptor des Feldes) Anzahl der Elemente vom Typ attribute_info in der folgenden Tabelle Tabelle mit Einträgen vom Typ attribute_info (Attribute des Feldes) Tabelle 4: Elemente der field_info Struktur Methoden Das method_info methods[] Feld der Class-File Struktur enthält Einträge vom Typ method_info. Diese repräsentieren je eine Methode, die in der korrespondierenden Klasse deklariert ist. Sie ist wie folgt aufgebaut: method_info{ access_flags; (2 Bytes) name-index; (2 bytes) descriptor_index; (2 Bytes) attribute_count; (2 Byte) attribute_info[] attributes; Die Bedeutung der Felder entspricht der Bedeutung der Felder der field_info Struktur. Die Accessflags der Felder als auch der Methoden sind wie folgt, durch eine zwei Byte große Maske, kodiert [JVMS][ 4.5, 4.6]: Zugriffsmodifier public private protected Wert 0x0001 0x0002 0x

17 Der JVM Bytecode Zugriffsmodifier static final synchronized volatile transient native abstract strictfp Wert 0x0008 0x0010 0x0020 0x0040 0x0080 0x0100 0x0200 0x0400 Tabelle 5: Zugriffsmodifier Attribute / Annotations Als letztes Feld der ClassFile Struktur bleibt noch die Liste der Attribute. Wie oben bereits erwähnt, sind Tabellen dieses Typs auch Bestandteil der Fields und der Method Tabelle. Tabellen dieses Typs enthalten Einträge des Typs attribute_info, welche wie folgt aufgebaut sind [JVMS][ 4.7]: attribute_info{ attribute_name_index; (2 Byte) attribute_length; (4 Byte) info[]; Die Bedeutung der Felder ist wie folgt: Feld attribute_name_index attribute_length Info[] Bedeutung Index auf einen CONSTANT_Utf8 Eintrag im Constant-Pool (Name des Attributes) Anzahl der Bytes des folgenden Info Strings Liste mit Attributen Tabelle 6: Elemente der attribute_info Struktur Attribute sind dabei Namen - Werte Paare. Sie können für Klassen, Felder und Methoden definiert werden. Sie befinden sich dann immer innerhalb der Attribut-Tabelle der entsprechenden Struktur. Die JVM Spezifikation definiert folgende Attribute für Felder Methoden oder ClassFiles [JVMS][ 4.7ff]: 17

18 Der JVM Bytecode Name Vorkommen in Strukturen Bedeutung Synthetic Depricated Signature RuntimeVisibleAnnotat ions RuntimeInvisibleAnnot ations SourceFile InnerClasses EnclosingMethod SourceDebugExtension Code LineNumberTable LocalVariableTable Exceptions RuntimeVisibleParamet erannotations AnnotationDefault Methoden, Felder, Class-Files (max. 1x) Methoden, Felder, Class-Files (max. 1x) Methoden, Felder, Class-Files (exakt 1x) Methoden, Felder, Class-Files (max. 1x) Methoden, Felder, Class-Files (max. 1x) Class-Files (exakt 1x) Class-Files (max. 1x) Class-Files (max. 1x) Class-Files (max. 1x) Methoden (max. 1x) Code (max. 1x) Code (max 1x) Methoden (max. 1x) Methoden (max. 1x) Methoden (max. 1x) ein vom Compiler generiertes Element Elemente, die nicht mehr verwendet werden sollen Verweis auf einen Eintrag im Constant-Pool Annotations, die zur Laufzeit über Reflections abgefragt werden können Annotations, die nicht zur Laufzeit abgefragt werden können Verweis auf einen Eintrag im Constant-Pool, der den Namen der Quellcode-Datei enthält Zugriffsrechte und Eigenschaften von inneren Klassen Zusatzinformationen zu lokalen und anonymen Klassen zusätzliche Texte für den Debugger enthält die Bytecode -Implementierung einer Methode Zeilennummern innerhalb von Methoden, die vom Debugger genutzt werden können Name und Typinformationen der lokalen Variablen einer Methode Ausnahmen, die eine Methode auslösen kann Annotations von Methoden, die zur Laufzeit mittels Reflexion abgefragt werden können Default Wert von Annotation Methoden, die per Reflection abgefragt werden können ConstenValue Felder Verweis auf eine Konstante im 18

19 Der JVM Bytecode Name Vorkommen in Strukturen Bedeutung (max. 1x) Tabelle 7: Attribute von der JVM Spezifikation definiert Constant-Pool, mit der ein Feld initialisiert wird Grundsätzlich haben alle Attribute die oben beschriebene Struktur. Dabei enthalten einige der Attribute weitere Informationen und daher auch größere Strukturen als oben beschrieben. Für eine genauere Beschreibung siehe [JVMS][ 4.7]. Für alle Attribute gilt, dass sie nur maximal einmal in ihrer Elternstruktur vorkommen dürfen. Es gibt aber auch Attribute, die zwingend vorhanden sein müssen. Aus dem Vorhandensein von Attributen können wichtige Informationen ermittelt werden. Beispielsweise lässt sich am Vorhandensein des Attributes InnerClass ablesen, dass die korrespondierende Klasse mindestens eine Innere Klasse besitzt. Ob weitere Innere Klassen vorhanden sind, können dem Inhalt des Attributs entnommen werden. Eines der oben aufgelisteten Attribute hat jedoch für diese Arbeit eine besonders wichtige Bedeutung. Es ist das Code Attribut, welches deshalb nun genauer betrachtet wird Code Attribut Alle Methoden, die nicht abstract oder native deklariert sind, müssen exakt ein Code Attribut besitzen. Code Attribute tragen u.a. Informationen über: die Größe des Stacks, der benötigt wird, um diese Methode ausführen zu können die Anzahl der lokalen Variablen die JVM Befehlsfolge, die ausgeführt werden muss, um diese Methode auszuführen die Exceptions, die ausgelöst werden können Ihre Struktur sieht wie folgt aus [JVMS][ 4.7.3]: Code_attribute { attribute_name_index; (2 Bytes) attribute_length; (4 Bytes) max_stack; (2 Bytes) max_locals; (2 Bytes) code_length; (4 Bytes) code[code_length]; exception_table_length; (2 Bytes) { start_pc; (2 Bytes) end_pc; (2 Bytes) handler_pc; (2 Bytes) catch_type; (2 Bytes) exception_table[exception_table_length]; attributes_count; (2 Bytes) attribute_info attributes[attributes_count]; 19

20 Der JVM Bytecode Die Bedeutung ist wie folgt: Feld attribute_name_index attribute_length max_stack max_locals code_length Code[] exception_table_length start_pc, end_pc handler_pc catch_type attributes_count attribute_info attributes[] Bedeutung Name des Attributes Länge des Attributes in Bytes maximale Größe des Stacks, der zur Ausführung dieser Methode benötigt wird Anzahl der lokalen Variablen Größe der Liste mit JVM Befehlen in Bytes Liste von JVM Befehlen; diese stellen den implementierten Code dar Anzahl der Exceptions, die für diese Methode definiert worden sind beschreiben Abschnitte, in denen ein Exceptionhandler aktiv ist der erste Befehl, der vom Exceptionhandler ausgeführt werden muss; Index auf das Code Array Index im Constant-Pool auf einen CONSTANT_Class Eintrag, der die zu fangende Klasse beschreibt Anzahl der Attribute des Code Attributes die Attribute des Code Attributes; dies können die LineNumberTable und LocalVariableTable Attribute sein Tabelle 8: Elemente der Code_attribute Struktur Vor allem die JVM Befehlsfolge, also das Code Array des Code Attributs, ist von besonderem Interesse. Hierbei handelt es sich um das, was vom Prozessor ausgeführt wird. Dies ist die Stelle, an der Referenzen entstehen können. Die JVM Befehlsfolge von Methoden muss daher zum Auffinden von Referenzen analysiert werden. Daher ist es notwendig, den Befehlssatz der JVM interpretieren zu können. Dieser wird im Kapitel genauer betrachtet. 3.3 Die Java-Virtual-Machine (JVM) Bytecodedateien sind streng genommen lediglich eine Form der Persistenz von Typen. Instanzen dieser Typen entstehen erst in der JVM. Dabei wandelt die JVM Bytecodedateien in Objekte um, die für die Verarbeitung optimiert sind, und legt diese in bestimmte Speicherbereiche ab. Bei diesem Vorgang werden zusätzliche Objekte erzeugt, die so nicht in Bytecodedateien zu finden sind. Um der Aufgabenstellung dieser Arbeit zu genügen, ist es jedoch notwendig, alle Deklarationen und Referenzen eines Programms zu betrachten. Eigentlich müsste der Speicherbereich, in dem Instanzen abgelegt werden, Gegenstand der Untersuchung sein, denn hier sind alle Klassen, von denen Instanzen gebildet werden können, zu finden. Dies ist jedoch nur mit sehr hohem Aufwand 20

21 Der JVM Bytecode und zudem auch nur in Abhängigkeit des Betriebssystems, auf dem die JVM installiert ist, möglich. Statt dessen werden Bytecodedateien betrachtet. Diese entstehen durch den Kompilierungsprozess, also bevor Klassen (im Sinne von Templates zur Erzeugung von Instanzen) von der JVM erzeugt und im Speicher abgelegt werden. Folglich müssen weitere Operationen, die bei der von der JVM vorgenommen Umwandlung von Bytecodedateien in Klassen durchgeführt werden, berücksichtigt werden (siehe Kapitel ). Ein rudimentäres Verständnis des Aufbaus und der Funktionsweise der JVM ist daher unumgänglich. Dieses Kapitel beschreibt daher die Strukturen und einige für diese Arbeit wichtige Prozesse der JVM im Überblick. Hierdurch wird ermöglicht, die Bytecodedateien derart zu interpretieren, dass alle Deklarationen und Referenzen aus ihnen abgeleitet werden können Einführung Die JVM bildet einen realen Prozessor nach. Genau wie ein Prozessor hat sie einen Befehlssatz und arbeitet nach dem Stackprinzip [JVMS][ 7.2]. Sie manipuliert verschiedene Speicherbereiche und erzeugt Befehlssätze, die von einer realen CPU verarbeitet werden können [JVMS][ 1.2]. Eine JVM muss sowohl spezifisch zu einem Betriebssystem als auch zu einer CPU implementiert werden. Als Eingabe akzeptiert eine JVM ausschließlich Bytecode und hat damit keine Berührungspunkte mit der Programmiersprache Java. Tatsächlich werden JVM s auch von ganz anderen Sprachen genutzt. Beispielsweise gibt es Compiler, die Bytecode für JVM s erzeugen und als Eingabe Textdateien der Sprachen ADA, C, PHP, Ruby, Phyton... (um nur einige zu nennen) akzeptieren. Entscheidend ist jedoch immer ein von der verwendeten CPU und dem Betriebssystem unabhängiger Bytecode, der auf virtuellen Maschinen ablaufen kann (siehe auch Abb. 1) Strukturen der JVM Die JVM reserviert zur Laufzeit verschiedene Datenbereiche, in denen die zur Ausführung eines Programms benötigten Daten abgelegt werden. Einige dieser Bereiche werden reserviert, wenn die JVM gestartet wird und werden beim Beenden wieder freigegeben. Andere Bereiche werden für jeden Thread, den die JVM erzeugt, neu angelegt und beim Beenden des Threads wieder freigegeben [JVMS][ 3.5]. Die JVM ist als Stackmachine implementiert. Sie erwartet daher die Operanden eines Befehls auf einem Verarbeitungsstack, auf den die Execution Engine Zugriff hat. Das Ergebnis der Operation wird dann wieder auf den Stack gelegt. Der Operand Stack (auch JVM - Stack) ist als 32 Bit LIFO Stack ausgeführt. JVM Stacks sind zur Ausführung von Code, der in Bytecodedateien hinterlegt ist, vorgesehen. Dabei handelt es sich immer um einen für die JVM spezifischen Befehlssatz, welcher dem Befehlssatz eines Prozessors ähnelt. Die JVM kann aber optional auch sog. Native Code ausführen. Dieser Code wird in der Native Method Area abgelegt. Mittels des Native Stack, welcher ebenfalls für jeden Thread angelegt wird, kann dann dieser Code ausgeführt werden. Der Native Stack und auch die Native Area sind laut Spezifikation optional [JVMS][ 3.5.6]. 21

22 Der JVM Bytecode Abbildung 2: Strukturen der JVM Native Code müsste eigentlich mit berücksichtigt werden. Dies würde jedoch den Rahmen dieser Arbeit sprengen. Daher werden Strukturen, die in diesen Themenbereich fallen, nicht weiter betrachtet. Das gleiche gilt für den Heap. Zwar ist es durchaus möglich, die Method Area als Teil des Heaps zu implementieren, dies ist jedoch nicht von der JVM Spezifikation vorgeschrieben [JVMS][ 3.5.4]. Aus diesem Grunde wird die Method Area als eigenständige Struktur betrachtet, obwohl sie logisch wohl zum Heap gehört Die Method Area Die Method Area ist eine Struktur der JVM, auf die alle Threads Zugriff haben. Sie enthält alle Informationen der Class-File Struktur einer Bytecodedatei. Dies sind der Constant-Pool, die Felder und Methoden und die Attribute einer Bytecodedatei: Der Constant-Pool Numerische Konstanten String Konstanten Referenzen auf Felder 22

23 Der JVM Bytecode Methoden (dieser Klasse und referenzierten Klassen) Klassen (die von dieser Klasse referenziert werden) die Felder der Klasse Methoden (den Code der Methoden, also JVM Befehle) Attribute (z.b. Type Parameter, Exceptiontables ) (siehe hierzu auch Abb. 2) Dabei lädt der ClassLoader die Bytecodedatei und übergibt den Inhalt der JVM. Diese erzeugt dann eine implementationsabhängige interne Darstellung der Klasse und legt diese in der Method Area ab. Innerhalb der Method Area wird eine Substruktur erzeugt, der Runtime Constant-Pool (RCP), welcher die Informationen des Constant-Pools einer Bytecodedatei enthält. Die JVM versucht dabei, alle Referenzen des Constant-Pools aufzulösen und veranlasst den ClassLoader Bytecodedateien nachzuladen, falls einige dieser Referenzen nicht aufgelöst werden können. Dieser Vorgang wird als Resolution bezeichnet [JVMS][ ]. Wichtig dabei ist, dass Methoden generiert werden, die nicht explizit im Programmcode bzw. in der Bytecodedatei zu finden sind. Dabei handelt es sich um zwei Methoden, die Teil von Konstruktoren sind. Genau eine Methode mit dem Namen <init>. Diese wird immer dann aufgerufen, wenn eine neue Instanz erstellt wird. Sie gehört zum Konstruktor einer Klasse und initialisiert diese, falls sie nicht initialisiert ist [JVMS][ 3.5.4, 3.9]. Sie stellt also den Default Konstruktor dar. Des weiteren genau eine Methode <client>. Diese initialisiert statische Member einer Klasse oder eines Interfaces, falls welche vorhanden sind [JVMS][ 3.5.4, 3.9]. Sie wird immer dann ausgeführt, wenn eine Klasse statische Felder besitzt und diese instantiiert wird JVM Stack und Frames Jeder Thread, der innerhalb einer JVM erzeugt wird, besitzt einen JVM Stack und ein PC Register (siehe hierzu auch Abb. 2). Das PC Register verweist dabei immer auf den nächsten in diesem Thread auszuführenden Befehl. Der Stack eines Threads enthält eine Liste mit Frames, die abzuarbeiten sind. Dabei erzeugt der JVM Stack eines Threads für jede Methode, die aufgerufen wird, einen Frame und zerstört diesen wieder, wenn die Methode abgearbeitet wurde. Ein Frame ist eine Struktur, die die folgenden Komponenten enthält: die lokalen Variablen einer Methode einen Operandstack eine Referenz auf den Runtime Constant-Pool der Klasse, zu der die Methode dieses Frames gehört 23

24 Der JVM Bytecode Abbildung 3: JVM Stack Komponenten Dabei wird ein Frame n erzeugt, wenn die Methode, die mit Frame n-1 korrespondiert, eine weitere Methode aufruft. Folglich wird Frame 1 gelöscht, wenn alle folgenden Frames abgearbeitet wurden. Das Ergebnis einer Methode, falls eines existiert, wird auf den Operandstack des aufrufenden Frames abgelegt [JVMS][ 3.6]. Die Befehle der JVM werden auf dem Operandstack eines Frames ausgeführt. Dabei handelt es sich um Befehle aus dem Befehlssatz der JVM. JVM-Befehle entstehen beim Kompilieren von Methoden des Quellcodes. Sie sind Bestandteil von Bytecodedateien. Im Rahmen dieser Arbeit ist es wichtig zu verstehen, dass Referenzen innerhalb von Frames der JVM entstehen. Es kann gefolgert werden, dass Referenzen, die in einem Frame entstehen, sich lediglich auf Elemente der Menge der Lokalen Variablen oder des Constant-Pools beziehen können. Es ist vom ausgeführten Befehl abhängig, worauf sich eine Referenz bezieht. Daher ist es notwendig, den Befehlssatz der JVM genauer zu betrachten (siehe Kapitel 3.3.7) Die Execution Engine Die Execution Engine stellt den eigentlichen virtuellen Prozessor der JVM dar. Sie führt die Befehle des Bytecodes aus und bedient sich dabei des JVM Stacks. Neben dem Laden der Operanden eines Befehls und der Steuerung des PC-Registers gehört es auch noch zu ihren Aufgaben, den Befehl in nativen Maschinencode umzuwandeln und auf dem physikalischen Prozessor auszuführen. Die Ausführung eines Bytecode Befehls durch die Execution Engine ist in folgender Abbildung dargestellt. 24

25 Der JVM Bytecode Abbildung 4: Execution Engine Zyklus Zu beachten ist dabei, dass die Execution Engine innerhalb eines Frames arbeitet. Hier hat sie Zugriff auf die lokalen Variablen und die Parameter der Methode. Über eine Referenz auf die Method Area der korrespondierenden Klasse kann auf den Bytecode der Methode und auf weitere Referenzen der korrespondierenden Klasse bzw. über den Runtime Constant-Pool auf andere Klassen zugegriffen werden Typen der JVM Die JVM unterscheidet bei den Datentypen zwischen zwei verschiedenen Grundtypen, den Primitiven Typen und den Referenztypen Die Primitiven Typen Wie aus der nachstehenden Tabelle hervorgeht, werden Primitive Typen in weitere Subtypen unterteilt [JVMS][ 3.3 ff.]. Dabei entsprechen die Numerischen Typen den entsprechenden Basis Typen des Class-Files (siehe auch ). Die Integral-Typen werden dabei intern als Integer abgelegt. Der Boolean Typ wird ebenfalls innerhalb der JVM wie ein Integer behandelt. Dabei wird das Literal true durch den Wert 1 und das Literal false durch den Wert 0 repräsentiert. Bei diesen Typen handelt es sich um automatisch in die JVM integrierte Typen. Sie werden nicht in irgendeiner Form über den Bytecode deklariert sonder sind schon da. Für diese Arbeit bedeutet das, dass es Referenzen auf Typen geben kann, die nicht explizit deklariert worden sind. Daher werden diese in dem zu implementierenden Programm so behandelt, als wären sie im Bytecode deklariert worden. Sie werden standardmäßig den vorhandenen Typen eines Programms hinzugefügt. 25

26 Der JVM Bytecode Primitive Typen numerische Typen Integral-Typen Byte (8 Bit, vorzeichenbehaftete Integer) Boolean Tabelle 9: Primitive Typen der JVM Die Referenz-Typen FloatingPoint-Typen Referenz-Typen unterteilen sich in folgende Subtypen [JVMS][ 3.4]: Referenztypen Klassen Typen Interface Typen Tabelle 10: Referenztypen der JVM Array Typen (diese Klassen werden dynamisch von der JVM erzeugt) Aufzählungstypen (diese Klassen werden vom Compiler erzeugt) Char (werden automatisch zu Integer erweitert) Short (16 Bit, vorzeichenbehaftete Integer) Int (32 Bit, vorzeichenbehaftete Integer) Long (64 Bit, vorzeichenbehaftete Integer, 2 JVM Worte) Float (32 Bit) Double (64 Bit, 2 JVM Worte) Die Referenz null ist eine spezielle Referenz, die keinen Laufzeittyp hat. Diese kann jedoch zu allen Referenztypen gecastet werden. Auch hier muss wiederum unterschieden werden, welche Deklarationen aus dem Bytecode ablesbar sind und welche implizit schon vorhanden sind. Die Deklarationen von Klassen- und Interface- Typen können natürlich in Class-Files gefunden werden. Aufzählungstypen (in Java Enum`s) werden vom Compiler in Bytecodedateien als Klasse deklariert. Sie können also wie Klassen und Interfaces in Bytecodedateien gefunden werden. Anders verhält es sich mit Arrays. Sie werden von der JVM ebenfalls als Klasse oder Typ betrachtet. Allerdings sind solche Deklarationen nicht in der Bytecodedatei zu finden. Sie werden erst durch den ClassLoader der JVM generiert und können daher nicht im Bytecode gefunden werden [JVMS][ 5.3]. Genau wie bei den impliziten Typen werden deklarierte Arrays daher wie deklarierte Typen betrachtet. 26

27 Der JVM Bytecode Befehlssatz der JVM Dieses Kapitel gibt einen Überblick über die Befehle der JVM. Diese werden in Gruppen geordnet und hinsichtlich der Referenzbildung bewertet. Detaillierte Informationen zu einzelnen Befehlen können der JVM Spezifikation im Kapitel 3.11ff entnommen werden. Wie schon weiter oben thematisiert, arbeitet die JVM intern wie eine Stackmaschine. Ihre Befehle werden auf dem Operandstack eines Frames ausgeführt. Ein Frame wird wiederum für jeden Methodenaufruf vom JVM-Stack erzeugt (s. Kapitel 3.3.4). Wird ein JVM-Befehl ausgeführt, werden zunächst die hierfür notwendigen Operanden auf den Operandstack des aktiven Frames geladen. Danach wird der Befehl ausgeführt und das Ergebnis auf den Operandstack zurückgeschrieben. Betrachtet man einen Frame zunächst als ein geschlossenes System, so kann man Schnittstellen mit der Außenwelt erkennen. Dies sind [JVMS][ 3.6]: eine Referenz auf den Runtime Constant-Pool ein Array namens LocalVariables. Hierzu gehören: eine Referenz auf die Instanz, zu der die Methode, für die ein Frame erzeugt wurde, gehört (also der this Zeiger) die Parameter der Methode, für die ein Frame erzeugt wurde die lokalen Variablen der Methode der Rückgabewert einer Methode. Dies ist auch genau die Menge von Objekten, auf die Referenzen gebildet werden können. Das Erzeugen einer Referenz stellt sich dabei als ein lesender oder schreibender Bezug auf ein Element der obigen Menge dar. Zu beachten ist, dass der Runtime Constant-Pool selbst eine Menge von Objekten darstellt, auf die nur lesend zugegriffen werden kann. Hierbei handelt es sich ja ausschließlich um Konstanten. Bezüge auf den Constant-Pool sind dabei Referenzen auf Konstanten, Typen, Methoden oder Feldern von Klassen. Auf die Elemente des LocalVariable Arrays kann hingegen lesend und schreibend zugegriffen werden. Einige Befehle des JVM Befehlssatzes bilden keine Referenz im Sinne dieser Arbeit. Sie nehmen lediglich Bezug auf den Stack. Dies an sich hat noch keine Auswirkung auf die Außenwelt eines Frames. Lediglich JVM Befehle, die eine Lade- oder Speicher-Operation ausführen, nehmen Bezug auf die Außenwelt eines Frames und bilden daher Referenzen. Die folgende Tabelle listet alle JVM Befehle auf und ordnet diese in Gruppen ein. Dabei werden die Gruppen dahingehend geordnet, ob sie Referenzen bilden oder nicht. 27

28 Der JVM Bytecode bilden Referenzen ja nein Gruppe Operation Befehl Laden und Speichern Zugriff auf Objekte Zugriff auf Typen Arithmetik Flusskontrolle Konstante Stack LocalVariable Stack Stack LocalVariable Arraywert Stack Stack Arraywert Variablen Arrays Objekte Exceptions Methoden Typumwandlung Stack Stack Ganzzahlen Gleitkomma Bitweise Sprünge Unterprogramme Tabellen Threads aconst_null, iconst_<n> (iconst_m1, iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5), lconst_<n> (lconst_0, lconst_1), fconst_<n> (fconst_0, fconst_1, fconst_2), dconst_<n> (dconst_0, dconst_1) bipush, sipush, ldc, ldc_w, ldc2_w, iload, iload_<n> (iload_0, iload_1, iload_2, iload_3) lload, lload_<n> (lload_0, lload_1, lload_2, lload_3) fload, fload_<n> (fload_0, fload_1, fload_2, fload_3) dload, dload_<n> (dload_0, dload_1, dload_2, dload_3) aload, aload_<n> (aload_0, aload_1, aload_2, aload_3) istore, istore_<n> (istore_0, istore_1, istore_2, istore_3) lstore, lstore_<n> (lstore_0, lstore_1, lstore_2, lstore_3) fstore, fstore_<n> (fstore_0, fstore_1, fstore_2, fstore_3) dstore, dstore_<n> (dstore_0, dstore_1, dstore_2, dstore_3) astore, astore_<n> (astore_0, astore_1, astore_2, astore_3) iaload, laload, faload, daload, aaload, baload, caload, saload iastore, lastore, fastore, dastore, aastore, bastore, castore, sastore iinc, wide newarray, anewarray, arraylength, multianewarray getstatic, putstatic, getfield, putfield, new, checkcast, instanceof athrow invokevirtual, invokespecial, invokestatic, invokeinterface, ireturn, lreturn, freturn, dreturn, areturn, return i2l, i2f, i2d, i2b, i2c, i2s, l2i, l2f, l2d, f2i, f2l, f2d, d2i, d2l, d2f nop, pop, pop2, dup, dup_x1, dup_x2, dup2, dup2_x1, dup2_x2, swap iadd, isub, imul, idiv, irem, ineg, ladd, lsub, lmul, ldiv, lrem, lneg fadd, fsub, fmul, fdiv, frem, fneg, dadd, dsub, dmul, ddiv, drem, dneg ishl, ishr, iushr, iand, ior, ixor, lshl, lshr, lushr, land, lor, lxor lcmp, fcmpl, fcmpg, dcmpl, dcmpg, ifeq, ifne, iflt, ifge, ifgt, ifle, if_icmpeq, if_icmpne, if_icmplt, if_icmpge, if_icmpgt, if_icmple, if_acmpeq, if_acmpne, ifnull, ifnonnull, goto, goto_w jsr, ret, jsr_w tableswitch, lookupswitch monitorenter, monitorexit Tabelle 11: JVM Befehle 28

29 Bytecode Framework Bibliotheken 4 Bytecode Framework Bibliotheken In vielen Forschungsprojekten werden durch Erweiterung der JVM mit Metaprogrammen Verbesserungen erzielt, so z.b. in der Programmiersprache Java. Die aspektorientierte Programmierung ist beispielsweise eine solche Entwicklung. Hierbei handelt es sich um Metaprogramme, die eine Bytecodedatei manipulieren, bevor diese von der JVM geladen wird. Hierdurch können einem Programm zusätzliche Aspekte hinzugefügt werden. Um dies zu erreichen, muss ein Programm nicht neu kompiliert werden. Die Programmerweiterung erfolgt genau dann, wenn die Bytecodedatei geladen wird, also nach dem Kompiliervorgang. Für solche Zwecke, aber auch zur Analyse von Bytecodedateien, wurden eine Reihe von Frameworks entwickelt. Eines dieser Frameworks ist ASM [ASM] vom OW2 Consortium. Hierbei handelt es sich um ein Framework, welches vor allem für die Manipulation von Bytecodedateien vorgesehen ist. Es wurde besonderer Wert auf ein schlankes Design und eine performance-optimierte Ausführung gelegt. Aber auch die Untersuchung von Bytecodedateien wird durch den Einsatz des Vistitor-Patterns gut unterstützt. Dieses Framework ist sehr gut dokumentiert, allerdings weist es eine geringe Abstraktion zum Bytecode auf, was die Einarbeitung ein wenig erschwert. Javassist ist ein Framework, welches als Unterprojekt des JBoss open Source SOA Projektes entwickelt wurde [Javassist]. Es handelt sich um eine recht große Bibliothek mit einem sehr hohen Abstraktionsgrad zum Bytecode. Integriert ist ein eigener Compiler, welcher es ermöglicht, kleinere Snippets anstatt ganzer Dateien zu verarbeiten. Der Fokus bei der Entwicklung dieses Frameworks lag in der Manipulation des Bytecodes und der leichten Erlernbarkeit desselben. Dagegen stand die Untersuchung von Bytecodedateien wohl nicht im Vordergrund. BCEL stellt einen Kompromiss zwischen den oben genannten Frameworks dar. Auf der einen Seite bietet es einen sehr hohen Abstraktionsgrad zum Bytecode. Im Besonderen können die verwendeten Klassen intuitiv den entsprechenden Elementen einer Bytecodedatei zugeordnet werden. Dies macht das Erlernen dieses Frameworks sehr einfach. Auf der anderen Seite wird die Untersuchung von Bytecodedateien durch intensiven Einsatz des Vistitor-Patterns sehr gut unterstützt. Die Dokumentation des Frameworks ist ausreichend gut. BCEL ist Bestandteil jedes JRE s, welches von SUN ausgeliefert wird. Zur Lösung der Aufgabenstellung habe ich daher das BCEL Framework als Basis gewählt. 4.1 BCEL BCEL besteht hauptsächlich aus drei Teilen, einem Package, welches die statischen Abhängigkeiten eines Class-Files repräsentiert, einem Package, welches für Codemanipulationen genutzt werden kann und verschiedenen Werkzeugen und Codebeispielen. Die statischen Abhängigkeiten einer Bytecodedatei werden durch Objekte im Package org.apache.bcel.classfile repräsentiert. Hier sind alle in der JVM Spezifikation [JVMS] beschriebenen Komponenten und Datenstrukturen auf Klassen gemappt. Unter Voraussetzung der Kenntnis des Aufbaus von Bytecodedateien ist die Klassenhierarchie des 29

30 Bytecode Framework Bibliotheken BCEL Frameworks daher sehr leicht verständlich. Ein Objekt namens JavaClass ist die Wurzel der Klassenhierarchie von BCEL. Hierbei handelt es sich um ein Kompositum aus Feld- und Methodenobjekten, Referenzen auf die Superklasse und den von einer Klasse implementierten Interfaces. Der interne Aufbau der Klasse entspricht der unter Kapitel beschriebenen Class-File Struktur. Eigenschaften von Klassenobjekten manifestieren sich in Objekten vom Typ Attribut. Sie können Objekten des Typs JavaClass, Field, Method oder Code zugeordnet sein. Enthält eine Java-Klasse beispielsweise innere Klassen, dann besitzt diese auch genau ein Attribut vom Typ InnerClass. Dieses enthält dann Verweise auf Elemente des Constant-Pools, in welchen die Eigenschaften der Inneren Klasse(n) beschrieben werden. Abbildung 5: Bcel JavaClass Objektdiagramm (aus [BCEL]) Der ConstantPool wird durch ein eigenes Objekt repräsentiert. Wie im Kapitel beschrieben, handelt es sich hierbei um eine Liste aus Konstanten, die auf Objekte vom Typ Constant gemappt werden. Der Typ Constant ist die Oberklasse aller Objekte, die einen Konstantentyp repräsentieren. Jedes JavaClass Objekt hat einen Member vom Typ ConstantPool. 30

31 Bytecode Framework Bibliotheken Abbildung 6: Bcel Constant-Pool Objektdiagramm (aus [BCEL]) Methoden, sofern sie implementiert sind, besitzen ein Attribut vom Typ Code. Dieses enthält unter anderem einen Member namens Code vom Typ byte[]. Dieser Member repräsentiert eine Liste der in dieser Methode auszuführenden JVM Befehle. Hierbei handelt es sich allerdings nur um den Opcode der JVM Befehle und nicht um Klassen, die z.b. mittels eines Visitors untersucht werden könnten. Dieser Nachteil wird jedoch durch die Klassen des Package org.apache.bcel.generic behoben. Die Klassen in diesem Package sind dafür vorgesehen, Bytecodedateien dynamisch zu erzeugen und zu manipulieren. Wurzel der Objekthierarchie der generic Klassen ist eine Klasse vom Typ ClassGen. Sie basiert auf einem JavaClass Objekt aus dem Package org.apache.bcel.classfile. Eine Instanz von JavaClass muss dem Konstruktor von ClassGen als Parameter übergeben werden. Das ClassGen Objekt besitzt im Gegensatz zum JavaClass Objekt Getter und Setter, mittels derer Klassenelemente hinzugefügt, verändert oder gelöscht werden können. Dasselbe gilt für alle anderen Objekte in diesem Package, die eine Entsprechung zu einer Klasse im Package org.apache.bcel.classfile haben. Die oben erwähnte Code Liste von Methoden wird in einem MethodGen Objekt durch eine Liste vom Typ InstructionList repräsentiert. Diese enthält Instanzen von Klassen, die die entsprechenden JVM Befehle abstrahieren. Jeder JVM Befehl ist auf eine gleichnamige Klasse gemappt. JVM Befehle sind per Subtyping mittels Interfaces gruppiert. Die Gruppen entsprechen dabei größtenteils der Einteilung der Befehlsgruppen in der JVM Spezifikation [JVMS][ 3.11ff]. Die Interfaces enthalten Funktionen, durch welche Informationen zum entsprechenden JVM Befehl ermittelt werden können. Alle Instruktionen können mittels eines Visitors traversiert werden. Dabei rufen die accept Methoden der einzelnen Instruktionen implizit die accept Methoden ihrer Superklassen auf. Dies erlaubt es, im Visitor vistit Methoden zu implementieren, die Gruppen von Instruktionen gleich behandeln. 31

32 Bytecode Framework Bibliotheken Abbildung 7: Bcel ClassGen Objektdiagramm (aus [BCEL]) Während - wie oben beschrieben - die ClassGen Objekte mittels der korrespondierenden JavaClass Instanz erzeugt werden, übernimmt diese Aufgabe für JavaClass Objekte ein Class Parser. Dieser gehört ebenfalls zum BCEL Framework. Im Package org.apache.bcel.generic existiert darüber hinaus eine kleine Objekthierarchie, die die möglichen Datentypen der JVM Spezifikation abstrahiert [JVMS][ 3.2ff]. Es wird zwischen Basic Types (JVM Spec Primitive Types) und Reference Types unterschieden. Die Signaturen von Typen können dabei mittels dieser Objekte ermittelt werden. Diese Klassen und eine Hilfsklasse namens Utilitys erleichtern den Umgang mit Deskriptoren, falls diese aus dem Constant-Pool gelesen werden müssen. 32

33 Der FaktenExtraktor 5 Der FaktenExtraktor Mittels des Bcel Frameworks ist es nun möglich, die gewünschten Mengen der Deklarationen und der Referenzen aus Bytecodedateien zu generieren. Hierzu wird zunächst eine Instanz des Objektes vom Typ FaktenExtraktor erzeugt. Instanzen von diesem Typ besitzen je einen Member vom Typ DeclarationFactory und ReferenceFactory. Diese Member werden im Konstruktor vom FaktenExtraktor initialisiert. Abbildung 8: FaktenExtraktor Objekte Die DeclarationFactory ist dabei für die Bildung von Objekten vom Typ Declaration und die ReferenceFactory für die Bildung von Objekten vom Typ Reference zuständig. Instanzen vom Typ Declaration bzw. Reference repräsentieren dabei jeweils eine Deklaration bzw. Referenz in einer Bytecodedatei. Die wichtigsten Member einer Referenz sind die Deklaration, die referenziert wird, der Receiver, dem die Referenz zugewiesen wird und der Ort, an dem sich die Referenz befindet. Orte an denen Referenzen und Deklarationen auftreten, werden durch eine Deklaration beschrieben. Daher ist die Eigenschaft location einer Referenz oder einer Deklaration ein Objekt vom Typ IDeclaration. Dabei entstehen die meisten Referenzen innerhalb von Methoden (siehe auch Kapitel 2). 33

34 Der FaktenExtraktor Der Receiver einer Referenz ist in einem eigenen Objekt vom Typ Receiver gekapselt. Es handelt sich dabei im Prinzip um einen Wrapper eines Objektes vom Typ ITypeDeclaration. Dieses besitzt zusätzlich noch weitere Eigenschaften, die eine TypeDeklaration weiter spezifizieren. Sowohl Referenzen als auch Deklarationen müssen innerhalb der entsprechenden Mengen eindeutig sein. Für Referenzen wird dies erreicht, indem verhindert wird, dass eine Bytecodedatei mehrmals eingelesen wird. Deklarationen dagegen werden in Strukturen vom Typ Map gespeichert. Als Schlüssel der Map dient die Eigenschaft Id von Deklarationen. Deklarationen können daher nur einmal in dieser abgelegt werden. Die Id von Deklarationen ist das Element, mit dem Deklarationen und Referenzen miteinander verknüpft werden können. Sie sind ähnlich dem Prinzip des FullQualifiedNames aufgebaut (siehe Kapitel 5.2). Die Informationen, die zur Verfügung stehen, wenn eine Referenz in einer Methode erzeugt wird, erlauben es, die Id einer Deklaration aufzubauen und das entsprechende ITypeDeclaration Objekt in der Menge der Deklarationen zu finden (siehe Kapitel 5.1). 5.1 Der Programmablauf Ausgehend von einer Bytecodedatei werden die Mengen aller Referenzen und aller Deklarationen gebildet. Sollten sich in dieser Bytecodedatei Bezüge zu Typen befinden, die nicht Bestandteil dieser Bytecodedatei sind, werden die entsprechenden Dateien ebenfalls geladen. Derart nachgeladene Dateien werden jedoch nur hinsichtlich der enthaltenen Deklarationen untersucht. Referenzen, die in diesen Klassen gebildet werden, werden nicht betrachtet. Zunächst werden die Deklarationen in einer Bytecodedatei ermittelt. Dies ist notwendig, da sich Referenzen auf Deklarationen beziehen. Diese müssen daher abrufbar sein. Diese Aufgabe wird von der DeclarationFactory durchgeführt. Deklarationen der Datentypen, die nicht explizit deklariert wurden (siehe Kapitel 3.3.6), werden ebenfalls durch die DeclarationFactory behandelt. Sie erzeugt beim Programmstart Deklarationsinstanzen mit Bezug auf die Basistypen und fügt diese der Menge der Deklarationen hinzu. Arrays werden innerhalb der JVM ebenfalls wie ein eigener Typ behandelt (siehe Kapitel 3.3.6). Daher wird eine Deklarationsinstanz mit Bezug auf einen Array-Typ genau dann generiert, wenn bei der Untersuchung der Bytecodedatei ein Array-Typ festgestellt wird. Im nächsten Schritt werden dann die Referenzen ermittelt. Hierfür ist die ReferenceFactory zuständig. Ihre Aufgabe besteht darin, die in den Methoden der zu untersuchenden Bytecodedateien enthaltenen JVM Befehle hinsichtlich Referenzen zu analysieren. Die nachfolgenden Diagramme stellen die Prozesse schematisch dar. Zunächst ein Überblick des Gesamtprozesses der Bildung von Referenzen und Deklarationen. 34

35 Der FaktenExtraktor Abbildung 9: Deklarations- und Referenz-Mengen bilden Im folgenden Diagramm wird die Ermittlung von Deklarationen schematisch dargestellt. 35

36 Der FaktenExtraktor Abbildung 10: Deklarationen ermitteln Die Deklarationen für Basistypen werden in einer Funktion namens initbasictypedeklarations generiert und der Menge der Deklarationen hinzugefügt. Diese Funktion wird nur einmal im Konstruktor der DeclarationFactory aufgerufen. 36

37 Der FaktenExtraktor Die Funktion builddeklarations dagegen kann beliebig oft aufgerufen werden. Als Parameter erhält diese ein JavaClass Objekt, welches die zu untersuchende Bytecodedatei repräsentiert (siehe auch Abbildung 9). Das Hinzufügen der Deklarationen einer Bytecodedatei erfolgt aus der Klasse FaktenExtraktor heraus. Diese ist für das Parsen der Bytecodedatei und das Erzeugen einer Instanz von JavaClass zuständig. Wie schon erwähnt, werden Deklarationen in einer Sammlung vom Typ Map abgelegt. Diese wird von der DeclarationFactory verwaltet (siehe auch Abbildung 8). Werden bei der Ermittlung von Deklarationen mittels einer der Suchfunktionen der Klasse DeclarationFactory Typen erkannt, die noch nicht im Deklarationspool enthalten sind, laden diese Funktionen die entsprechende Bytecodedatei nach und rufen ebenfalls builddeklarations auf. Dies kann während der Aktionen Methoden des Typs ermitteln, Lokale Variablen und Methodenparameter ermitteln und/oder Felder der Klasse ermitteln der Fall sein. Denn diese Elemente können sich auf einen Typ beziehen, der noch nicht der Menge der Deklarationen hinzugefügt wurde. Im folgenden Diagramm wird schematisch beschrieben, wie Referenzen ermittelt werden. Dieser Prozess wird immer von einer Instanz von FaktenExtraktor aus initiiert. Dabei wird die Methode buildreferences der Klasse ReferenceFactory aufgerufen. Als Parameter wird eine Instanz von Typ JavaClass übergeben. Diese Instanz repräsentiert die Klasse, deren Referenzen ermittelt werden. 37

38 Der FaktenExtraktor Abbildung 11: Referenzen ermitteln 38

39 Der FaktenExtraktor Die ReferenceFactory kontrolliert dabei nicht nur den Ablauf des Prozesses zur Ermittlung der Referenzen sondern ermittelt diese auch. Zu diesem Zweck ist ReferenceFactory von EmptyVisitor abgeleitet. EmptyVisitor implementiert zu jedem JVM Befehl eine leere Visitor-Methode mittels derer alle JVM Befehle traversiert werden können. Die Klasse EmptyVisitor wird vom BCEL Framework bereitgestellt. Visitor-Methoden, die zu einem JVM Befehl gehören, der zur Laufzeit Referenzen erzeugt, werden in ReferenceFactory überschrieben. Ihre Aufgabe besteht darin, ID s für Referenzen zu den jeweils referenzierten Deklarationen zu erzeugen. Die so erzeugten ID s werden durch Aufruf der Funktion findoraddtypedeclarationbyid der DeclarationFactory in entsprechende Deklarationsobjekte aufgelöst. Falls dabei festgestellt wird, dass die zugehörige Bytecodedatei noch nicht geparst worden ist, wird diese nachgeladen (siehe auch Abb. 10). Die Funktion addnewreferene der ReferenceFactory hat die Aufgabe, ein Objekt vom Typ IReference zu erzeugen und zu initialisieren. Dabei wird anhand des Typs der Deklaration, auf welche sich die Referenz bezieht, der Receiver und der Typ der Referenz abgeleitet. Diese Referenz wird anschließend der Menge der Referenzen hinzugefügt. 5.2 Deklarations-ID Um die Bezüge von Referenzen auf eine Deklaration ermitteln zu können, müssen diese aus der Menge der Deklarationen ausgewählt werden können. Wichtig dabei ist, dass Deklarationen eindeutig in dieser Menge identifizierbar sind. Bei der Verknüpfung von mehreren Referenzen mit einer Deklaration muss daher eine 1:n Beziehung zwischen der Deklaration und der Menge der Referenzen entstehen. Um Deklarationen effektiv innerhalb einer Menge finden zu können, werden diese in einer HashTable abgelegt. Als Key wird hierzu eine ID zu jeder Deklaration generiert. Die ID besteht in den meisten Fällen aus dem Full-Qualified-Name des entsprechenden Elements. Im Falle von lokalen Variablen, zu denen ja auch Methodenparameter gehören, wird der Variablenname durch den Index der Variablen in der LocalVariableTable ersetzt. Die LocalVariableTable enthält alle Objekte, die die Methodenparameter und die lokalen Variablen einer Methode repräsentieren. Sie ist zur Laufzeit des Programms Bestandteil eines jeden Frames (siehe Kapitel 3.3.4). JVM Befehle können Parameter nur durch Bezüge auf die Einträge der LocalVariableTable ermitteln. Alle Referenzen, die innerhalb einer Methode erzeugt werden können, werden also über die LocalVariableTable bezogen. Der Zugriff auf einen Eintrag in der LocalVariableTable durch einen JVM Befehl erfolgt über den Index des Eintrags. Die LocalVariableTable ist jedoch nicht immer Bestandteil einer Bytecodedatei. Dies hängt von den Einstellungen des Compilers ab. Meist besitzen Klassen, die per.jar in eine Anwendung importiert werden, keine LocalVariableTable. Hierdurch kann die Dateigröße von Bytecodedateien erheblich reduziert werden. Die JVM generiert dann zur Laufzeit die entsprechende LocalVariableTable. Die Namen der lokalen Variablen befinden sich in der LocalVariableTable, falls diese vorhanden ist. Daher kann für lokale Variablen der Full-Qualified-Name nicht immer gebildet 39

40 Der FaktenExtraktor werden. Der Index aus der LocalVariableTable, auf den ein JVM Befehl zugreift, kann jedoch immer ermittelt werden. Daher enthalten ID s von Deklarationen, die auf lokale Variablen oder Methodenparameter beruhen, statt ihren Namen den Index innerhalb der LocalVariableTable, zu der sie gehören. Der restliche Teil der Id ist nach den Regeln des Full-Qualified-Names aufgebaut. Für den Fall einer Bytecodedatei, die keine LocalVariableTable enthält, können die Deklarationen der Methodenparameter nur aus der Methodensignatur ermittelt werden. Um in diesen Fällen die ID mit dem richtigen Index aufzubauen, ist die Kenntnis des Aufbaus der entsprechenden LocalVariableTable einer Methode notwendig. Dieser ist abhängig von der Methode, für die sie erzeugt wurde. Hier ergeben sich Unterschiede zwischen statischen Methoden, Klassen-Methoden und Methoden, die zu Inneren oder Anonymen Klassen gehören. Die Einträge der LocalVariable Tabellen enthalten alle Elemente in der Reihenfolge, wie sie in den Methoden auftreten. Für die einzelnen Methoden-Typen sieht das wie folgt aus: statische Methoden Methodenparameter lokale Variablen Klassen-Methoden Referenz auf die Klasse, zu der die Methode gehört (this Zeiger) Methodenparameter lokale Variablen Methoden von Inneren/Anonymen Klassen Referenz auf die äußere Klasse Referenz auf die Klasse, zu der die Methode gehört (this Zeiger) Methodenparameter lokale Variablen Entsprechend wird der Index für die Einträge vergeben. Die lokalen Variablen, die innerhalb eines Methodenrumpfes definiert sind, können in diesen Fällen ignoriert werden. Denn Bytecodedateien, deren Methoden keine LocalVariableTable enthalten, sind immer Bestandteil eines.jars. Diese Klassen können daher nicht refaktorisiert werden, und auf eine lokale Methoden-Variable kann außerhalb der Methode keine Referenz existieren. Für Klassen, die Gegenstand einer Analyse der Referenzen und Deklarationen sind, ist jedoch die richtige Einstellung des Compilers essentiell. Für die Eclipse Entwicklungsplattform lassen sich die notwendigen Einstellungen folgendermaßen vornehmen: 40

41 Der FaktenExtraktor Abbildung 12: Compiler Einstellung Diese Einstellung entspricht der Compiler-Option -g:{vars. 5.3 Interface zu Referenzen und Deklarationen Die ermittelten Mengen der Referenzen und der Deklarationen können über mehrere Interfaces abgefragt werden. Alle Interfaces zusammen sind hierarchisch aufgebaut. Die Wurzel des Baumes wird durch ein Interface namens ISourceCodeElement gebildet. Dieses Interface wird von allen Referenzen und allen Deklarationen implementiert. Abbildung 13: Interface Hierarchie Wurzel 41

42 Der FaktenExtraktor Folgende Elemente können deklariert werden: Packages Typen (Klassen) Felder Methoden Methodenparameter Lokale Methodenparameter Bis auf Packages werden alle oben aufgeführten Elemente einer Bytecodedatei weiter unterteilt. Typen können Interfaces oder Klassen sein. Klassen wiederum können Enums, Innere Klassen oder Anonyme Klassen sein. Tager-Interfaces markieren die Deklarationen entsprechend. Bei den Methoden wird zusätzlich unterschieden, ob es sich um einen Konstruktor handelt oder um eine Klassenmethode. Methodenparameter sind lokale Methoden-Variablen. Solche Deklarationen werden mittels des IMethodParameter Interface gekennzeichnet. Dieses ist von IlocalVariableDeklaration abgeleitet. Felder werden in statische und nicht statische Felder eingeteilt. Gemeinsame Eigenschaften von Typen, Methoden und Feldern werden in ein Interface namens IDeclarationWithAccessibility ausgelagert. Das nachfolgende Diagramm gibt einen Überblick über die Interface Hierarchie von Deklarationen. 42

43 Der FaktenExtraktor Abbildung 14: Interface Hierarchie Deklarationen 43

44 Der FaktenExtraktor Die Hierarchie der Referenzen ist etwas einfacher aufgebaut. Referenzen leiten sich aus dem Zugriff auf Deklarationen ab. Dementsprechend gibt es für Referenzen die Interfaces für Typen, Methoden, Konstruktoren, Lokale Variablen und Felder. Mittels der Methode getdeclaration() kann von einer Referenz aus auf die entsprechende Deklaration navigiert werden. Abbildung 15: Interface Hierarchie Referenzen 44

45 Der FaktenExtraktor 5.4 Das FaktenExtraktor Interface Der FaktenExtraktor ist dazu vorgesehen, als Bibliothek in Projekten verwendet zu werden. Daher wird dieser zu diesem Zweck als Jar-Datei bereitgestellt. Innerhalb eines Projektes muss dann eine Instanz des FakenExtraktors erzeugt werden. Dies erfolgt mit: IFaktenExtraktor faktenextraktor = new FaktenExtraktor(); Der weitere Zugriff erfolgt dann über das Interface IFaktenExtrator. Die hierin enthaltenen Methoden werden im Folgenden kurz beschrieben. Zu analysierende Bytecodedateien können dem Faktenanalysator auf folgende Weise zugeführt werden: mit einem Classpath als Argument, der nach Bytecodedateien durchsucht wird: faktenxtraktor.addalldeclarationsinfolder(string classpath); mit einem Clathpath und einer Auflistung von zu untersuchenden Verzeichnissen als Argumente: faktenextraktor.addalldeclarationsinclasspath(string classpath, String... foldernames); mit einem Classpath als Argument, der nach Bytecodedateien durchsucht wird: faktenextraktor.addallreferencesinclasspath(string classpath); mit einem Clathpath und einer Auflistung von zu untersuchenden Verzeichnissen als Argumente: faktenextraktor.addallreferencesinclasspath(string classpath, String... foldernames); mit einem Objekt vom Typ class als Argument: faktenextraktor.adddeklarations(classfile); mit einem Objekt vom Typ JavaClass (BECEL Typ) als Argument: faktenextraktor.adddeklarations(javaclass); mit einem Klassennamen als Argument, falls die Klasse im Classpath der Anwendung liegt: faktenextraktor.adddeklarations(classname); mit einem Objekt vom Typ class als Argument: faktenextraktor.addreferences(classfile); mit einem Objekt vom Typ JavaClass (BECEL Typ) als Argument: faktenextraktor.addreferences(javaclass); mit einem Klassennamen als Argument, falls die Klasse im Classpath der Anwendung liegt: faktenextraktor.addreferences(classname); Auf die dann entstandene Menge der Deklarationen bzw. Referenzen kann folgendermaßen zugegriffen werden: auf die Deklarationen mit: Collection<IDeclaration> decl = faktenextraktor.getdeclarations(); 45

46 Der FaktenExtraktor auf die Referenzen mit: Collection<IReference> ref = faktenextraktor.getreferences(); auf alle Elemente in einer Liste vereint mit: Collection<ISourceCodeElement> allelements = faktenextraktor.getallelements(); Die Elemente, welche in den so entstanden Listen enthalten sind, implementieren dann die passenden Interfaces. Um eine bestimmte Deklaration in der Menge der Deklarationen zu suchen, kann sich folgender Methoden bedient werden: falls ein class-objekt der gesuchten Deklaration vorliegt: faktenextraktor.finddeclarationbyclass(class); falls die Id der gesuchten Deklaration bekannt ist (siehe auch Kapitel 5.2): faktenextraktor.finddeclarationbyid(string id); falls das BECEL-JavaClass-Objekt der gesuchten Klasse vorliegt: faktenextraktor.finddeclarationbyjavaclass(javaclass jc); 46

47 Eine Anwendung 6 Eine Anwendung Der FaktenExtraktor lässt sich zur Prüfung von Vorbedingungen für Refactoring Werkzeuge einsetzen. Hierfür müssen für das jeweilige Refactoring geeignete Vorbedingungen formuliert werden und die Mengen der Referenzen und Deklarationen auf geeignete Weise untersucht werden. Am Beispiel des recht komplexen Replace Inheritence with Delegation Refactorings wird in diesem Kapitel demonstriert, wie Vorbedingungen für Refactorings überprüft werden können. Das RIWD- Refactoring ist das Ergebnis einer Entwicklung, die am Lehrgebiet für Programmiersysteme der FernUni Hagen durchgeführt wurde [RIWD]. Für dieses Refactoring existiert eine Liste mit bekannten Fehlern [riwd Bugs]. Es handelt sich um Spezialfälle, für welche keine geeignete Vorbedingung des Refactorings formuliert wurde. Anhand der aufgeführten Fehler werden Vorbedingungen formuliert und mittels FaktenExtraktors geprüft. 6.1 Beispiel 1: Offene Rekursion Folgende Klassen stellen die Ausgangssituation dar: class Super { Super() { m(); void m() { void n() { class Sub extends Super { Sub() {super(); void m() { n(); Mittels eines JUnit Tests kann überprüft werden, ob eine Instanz der Klasse Sub erzeugt werden public void createsub() throws Exception { Sub sub = new Sub(); Bevor das Refactoring ausgeführt wird, ist der JUnit Test erfolgreich. Nach der Ausführung des Refactorings stellt sich der Sourcecode wie folgt dar: public class Sub { protected final Delegatee delegatee; public Sub() { delegatee = new Delegatee(); void m() { n(); void n() { delegatee.n(); protected class Delegatee extends Super { Delegatee() { super(); void m() { Sub.this.m(); protected void n() { super.n(); 47

48 Eine Anwendung public class Super { protected Super() { m(); void m() { protected void n() { Die Vererbungsbeziehung wurde also an eine Innere Klasse delegiert. Wird der oben angegebene JUnit Test erneut ausgeführt, schlägt dieser nun fehl. Es kommt zu einer java.lang.nullpointerexception in der Methode createsub(). Der Grund hierfür ist eine implizite offene Rekursion, die erst bei genauerer Analyse der Klassen klar wird. Beim Erzeugen einer Instanz der refaktorierten Klasse Sub wird vom Konstruktor folgender Aufrufstack erzeugt: Sub() Delegatee() Super() Delegatee.m() Da der Konstruktor von Delegatee jedoch noch nicht komplett abgearbeitet wurde, existiert noch keine gültige Instanz von Delegatee, womit der Aufruf von Delegatee.m() im Konstruktor von Super zu einer java.lang.nullpointerexception führt. Denn hierbei handelt es sich um eine offene Rekursion, die eben Delegatee.m() aufruft. Die Vorbedingung, die daraus abgeleitet werden kann, lautet: Im Aufrufstack der Konstruktoren der zu refaktorisierenden Klasse dürfen keine Funktionen von Superklassen aufgerufen werden, die sich per offener Rekursion auf Funktionen der zu refaktorisierenden Klasse beziehen. Um dies zu prüfen, wird ein JUnit Test implementiert, der erfolgreich sein soll, falls keine derartige Rekursion besteht und nicht erfolgreich sein soll, falls das Refactoring nicht angewendet werden darf. Die Prüfung dieser Bedingung ist mit Hilfe des FaktenExtraktors leicht zu bewerkstelligen. Zunächst werden zwei Mengen gebildet: die Menge der Methoden der zu refaktorisierenden Klasse, die Methoden der Superklasse überschreiben rekursiv, die Menge der Methoden, die durch die Konstruktoren der zu refaktorisierenden Klasse aufgerufen werden Danach werden die ermittelten Mengen miteinander verglichen. Gibt es eine Entsprechung, so existiert eine schädliche offene Rekursion. In diesem Falle ist die Vorbedingung nicht erfüllt. Folgender Junit Testcase prüft die Vorbedingung: public class riwdcheckopenrecursion extends TestCase { Collection<IMethodAccess> byconstruktorreferencedmethods; Collection<IMethodDeclaration> byclassmethodsoverriddenmethods; public void testcheckopenrecursion() throws Exception { // die zu refaktorisierende Klasse 48

49 Eine Anwendung Class cl = Sub.class; FaktenExtraktor prg = new FaktenExtraktor(cl); byconstruktorreferencedmethods = new Vector<IMethodAccess>(); byclassmethodsoverriddenmethods = new Vector<IMethodDeclaration>(); // ermittle die Methoden, die Methoden der Ausgangsklasse überschreiben for (IDeclaration declaration : prg.getdeclarations()) { if (declaration.isfromsource() && declaration.getid().contains(cl.getname())&& declaration.getdeclarationkind().equals(declarationkind.classdeclaration)) { IClassDeclaration cd = (IClassDeclaration)declaration; Collection<IMethodDeclaration> methodes = cd.getmethods(); for (Iterator<IMethodDeclaration> iterator = methodes.iterator(); terator.hasnext();) { IMethodDeclaration imethoddeclaration = iterator.next(); byclassmethodsoverriddenmethods.addall(imethoddeclaration.getoverriddenmethods()); // falls es keine überschriebenen Methoden gibt, ist die Vorbedingung erfüllt if (byclassmethodsoverriddenmethods.size() == 0) { asserttrue("no methods are overridden",byclassmethodsoverriddenmethods.size() == 0); // ermittle für jeden Konstruktor rekursiv alle Methodenreferenzen for (IDeclaration declaration : prg.getdeclarations()) { if (declaration.isfromsource() && declaration.getid().contains(cl.getsimplename())&& declaration.getdeclarationkind().equals(declarationkind.constructordeclaration)) { IConstructorDeclaration cd = (IConstructorDeclaration) declaration; addmethodreferences(cd.getuses()); if (byconstruktorreferencedmethods.size() == 0) { asserttrue("no Constructor uses a method",byconstruktorreferencedmethods.size() == 0); // vergleiche die Mengen der referenzierten Methoden mit der Menge der überschreibenden Methoden for (Iterator<IMethodAccess> iterator = byconstruktorreferencedmethods.iterator(); iterator.hasnext();) { IMethodAccess ma = iterator.next(); Collection<IMethodDeclaration> overriddenmethods = ma.getdeclaration().getoverriddenmethods(); for (Iterator<IMethodDeclaration> iterator2 = overriddenmethods.iterator(); iterator2.hasnext();) { IMethodDeclaration imethoddeclaration = iterator2.next(); assertfalse("open recrution, activated in a construktor, detected",overriddenmethods.contains(imethoddeclaration)); private void addmethodreferences(collection<imethodaccess> mrefs){ // alle von diesen Methoden referenzierten Methoden // der byconstruktorreferencedmethods Collection hinzufügen 49

50 Eine Anwendung byconstruktorreferencedmethods.addall(mrefs); // für jede Referenz prüfen ob weitere Methoden // byconstruktorreferencedmethods hinzuzufügen sind... for (Iterator<IMethodAccess> iterator = mrefs.iterator(); iterator.hasnext();) { IMethodAccess imethodaccess = iterator.next(); addmethodreferences(imethodaccess.getdeclaration().getuses()); Wie gewünscht, scheitert der JUnit Test, wenn dieser auf die Ausgangssituation dieses Beispiels angewendet wird. 6.2 Beispiel 2: Down-Cast Die Ausgangssituation stellt sich wie folgt dar: public interface DownCastInterface { public class DownCastSub extends DownCastSuper { DownCastInterface make() { return new DownCastSub(); public void cast() { DownCastSuper o = (DownCastSuper) make(); public static void main(string[] args) { new DownCastSub().cast(); public class DownCastSuper implements DownCastInterface { Mittels eines JUnit-Tests testen wir die Funktionalität der cast public void createandcast() throws Exception { new DownCastSub().cast(); Vor dem Refactoring wird der JUnit Test erfolgreich absolviert. Nach dem Refactoring stellt sich der Sourcecode wie folgt dar: public interface DownCastInterface { public class DownCastSub { protected final Delegatee delegatee; public DownCastSub() { delegatee = new Delegatee(); 50

51 Eine Anwendung DownCastInterface make() { return new DownCastSub(); public void cast() { DownCastSuper o = (DownCastSuper) make(); public static void main(string[] args) { new DownCastSub().cast(); protected class Delegatee extends DownCastSuper { public class DownCastSuper implements DownCastInterface { Nach dem Refactoring schlägt der JUnit-Test fehl. An der Stelle DownCastSuper o = (DownCastSuper) make(); kommt es nun zu einer java.lang.classcastexception. Der Grund hierfür ist der Down-Cast, der nun nicht mehr funktionieren kann, da die Vererbungsbeziehung entfernt wurde. Hieraus kann folgende Vorbedingung abgeleitet werden: Es dürfen keine Down-Casts von Instanzen vom Typ der zu refaktorisierenden Klasse vorgenommen werden. Diese Regel gilt natürlich für jedes Element, welches den zu refaktorisierenden Typ referenziert. Um die Regel zu prüfen, wird in der Menge der Referenzen nach einer Referenz gesucht, die: 1. vom Typ CAST_ACCESS ist, 2. in einen Typ vom Typ eines Supertypen der zu refaktorisierenden Klasse casten möchte 3. das zu castende Element vom Typ eines Supertypen des Carstparameters (also des 'Typs zu dem gecastet werden soll) ist. Sind alle drei Bedingungen erfüllt, liegt ein DownCast des zu refaktorisierenden Typs vor. Die Vorbedingung wäre dann nicht erfüllt. Folglich müsste ein entsprechender JUnit Test scheitern. Folgender JUnit Test überprüft, ob Down-Casts der zu refaktorisierenden Klasse durchgeführt werden. public void testcheckdowncasts() throws Exception { Class cl = DownCastSub.class; FaktenExtraktor faktenextraktor = new FaktenExtraktor(cl); IClassDeclaration torefactorclass = null; // ermittle die Deklaration der Klasse, die refaktorisiert werden soll 51

52 Eine Anwendung torefactorclass = (IClassDeclaration) faktenextraktor.finddeclarationbyclass(cl); // ermittle alle Referenzen vom Typ CAST_ACCESS, die // auf eine Superklasse der Ausgangsklasse casten, // wobei die zu castende Klasse eine Superklasse des Castarguments sein soll for (IReference reference : faktenextraktor.getreferences()) { if ( reference.getreferencekind() == ReferenceKind.CAST_ACCESS && (torefactorclass.getsupertypes().contains(reference.getreferenceddeclaration()))&& (((ItypeDeclaration)reference.getReferencedDeclaration()). getsupertypes().contains(((castoperation)reference).gettobecastedtype()))){ assertfalse("downcast occured", true); Wie gewünscht, scheitert der JUnit Test, wenn dieser auf die Ausgangssituation dieses Beispiels angewendet wird. 6.3 Bemerkung Um diesen Test implementieren zu können, wurde das ursprüngliche Framework um das Interface ICastOperation und die Klasse CastOperation erweitert. Beide liegen in der Hierarchie unterhalb von ITypeAccess bzw. TypeAccess. Ein Referenz vom Typ CastOperation entsteht dabei immer dann, wenn der JVM Befehl CHECKCAST von der ReferenzFactory innerhalb einer Methode gefunden wird. Der Typ, in den gecastet werden soll, kann dabei dem Objekt CHECKCAST entnommen werden. Der zu castende Typ kann nicht direkt ermittelt werden. Allerdings können folgende Fakten dennoch dazu genutzt werden, um diesen Typ zu ermitteln: 1. Die JVM Cast-Operation konsumiert genau eine Referenz vom aktuellem Operand-Stack. 2. Eine entsprechende JVM-Operation, die eine solche Referenz erzeugt, taucht unmittelbar vor der Cast-Operation in der fraglichen Methode auf. 3. Der Typ, den diese Reference repräsentiert, ist der Typ, der gecastet werden soll. Man kann also davon ausgehen, dass die gesuchte Referenz unmittelbar vor der Typ-Referenz, die durch die Cast-Operation selbst entstanden ist, der Liste der Referenzen hinzugefügt wurde. Dazwischen liegen lediglich die Referenzen einer Reihe von Klassen, die build in Exceptions der Cast-Operation darstellen. Ihre Anzahl ist konstant. Es handelt sich um acht Exceptions, die durch die Cast-Operation aufgelöst werden können. Wird also der achtletzte Eintrag der Liste der Referenzen ermittelt, bevor die Referenz auf den zu Castenden Typ hinzugefügt wird, handelt es sich um die gesuchte Referenz, deren Typ den Typ darstellt, der gecastet werden soll. Gefährlich hieran ist, dass, falls zukünftige Compiler der Cast-Operation weitere Exceptions hinzufügen, dies zu einem falschem Ergebnis führen würde. Daher ist dieser Lösungsansatz als kritisch zu betrachten. Ein besser Ansatz wäre es, die gesuchte Referenz anhand der LineNumberTable innerhalb der Menge der Referenzen zu suchen. Hierfür müssen dann jedoch gegebenenfalls bestimmte Compilereinstellungen berücksichtigt werden. Die LineNumberTable ist ansonsten nicht Teil der Bytecodedatei. 52

53 Eine Anwendung Eine Eigenschaft LineNumber, die den Ort einer Referenz genauer spezifizieren würde, könnte auch für andere Fälle von Bedeutung sein. Daher könnte es interessant sein, die Eigenschaft Location einer Referenz um ein Attribute LineNumber zu erweitern. 53

54 Evaluierung 7 Evaluierung AST Parser sind Werkzeuge der Sourcecode-Analyse, wie sie von der Eclipse- Entwicklungsumgebung genutzt werden. Sie werden von vielen Refaktorisierungs-Werkzeugen zur Überprüfung der Vorbedingungen eingesetzt. Ein Vergleich des Analyse-Ergebnisses des FaktenExtraktors mit andern Analysewerkzeugen ist ohne großen Aufwand nicht möglich. Um dennoch eine Aussage zur der Performance des Faktenanalysators zu tätigen, wurde dieser mit dem im Anhang beschriebenen rudimentären AST Parser plus Visitor für Methodendeklarationen und Felddeklarationen verglichen. Die Aufgabe des hier eingesetzten AST-Parsers besteht lediglich darin, alle CompilationUnits eines Projekts zu ermitteln und zu parsen. Aus diesen müssen dann alle AST Nodes, die eine Methodendeklaration oder eine Felddeklarationen darstellen, extrahiert werden. Im Gegensatz dazu ermittelt der FaktenExtraktor alle Deklarationen und Referenzen desselben Projektes und betrachtet dabei auch die vom Projekt referenzierten Jar Dateien. Die Evaluierung wurde auf einem PC mit i7 (8 Core) Prozessor, 6 GB RAM und Windows 7 durchgeführt. Als erstes Testprojekt wurde das OpenSource Projekt jaxen von Codehaus [jaxen] gewählt. Dieses Projekt besteht aus 200 Klassen. Tool AST-Parser FaktenExtraktor Zeit [sec] 2,13 1,38 Gefundene Elemente 1658 Methoden + Felder Deklarationen Referenzen Geschwindigkeit / Element [ms] 1,5 0,02 Tabelle 12: Ergebnis Evaluierung mit Projekt jaxen Das zweite Testprojekt enthält wesentlich weniger Klassen mit deutlich weniger Felder und Methoden. Es handelt sich um das OpenSource Projekt Jester 1.37b [Jester]. Tool AST-Parser FaktenExtraktor Zeit [sec] 0,49 1,12 Gefundene Elemente 291 Methoden + Felder Deklarationen Referenzen Geschwindigkeit / Element [ms] 1,6 0,02 Tabelle 13: Ergebnis Evaluierung mit Projekt Jester 1.37b 54

55 Evaluierung Als drittes Testprojekt wurde das Open Source Projekt Commons Codec von Apache gewählt [Commons Codec]. Tool AST-Parser FaktenExtraktor Zeit [sec] 0,92 0,87 Gefundene Elemente 825 Methoden + Felder Deklarationen Referenzen Geschwindigkeit / Element [ms] 1,1 0,02 Tabelle 14: Ergebnis Evaluierung mit Projekt Commons Codec Die Zeit zur Ermittlung einer Deklaration bzw. einer Referenz ist beim FaktanExtraktor sehr konstant. Sie liegt bei 0,02 ms. Die Zeit pro Element bei einem AST Parser liegt in etwa bei 1,4 ms. Daraus ergibt sich, dass der FaktenExtraktor ca. 70 mal schneller Elemente aus dem Bytecode extrahieren kann als ein AST Parser aus dem Sourcecode. 55

56 Installation 8 Installation Da im Programm einige Jars aus dem JDK genutzt werden, die als restricted deklariert sind, müssen entsprechende Fehlermeldungen unterdrückt werden. Abbildung 16: Compiler-Einstellungen für restricted API 56

57 Installation Damit die erzeugten Class-Files alle benötigten Informationen enthalten, werden des weiteren folgende Compilereinstellungen benötigt: Abbildung 17: Compilereinstellung für zusätzliche Informationen in Class-Files 57

Java Virtual Machine (JVM) Übersicht

Java Virtual Machine (JVM) Übersicht Java Virtual Machine (JVM) Alan Dingwall dingwall@gmx.net Übersicht Was ist die Java Virtual Machine DasClass File Format Aufbau der JVM Kompilation.java.class Fazit Quellennachweise Was ist die JVM Abstrakter

Mehr

Inhaltsverzeichnis 1

Inhaltsverzeichnis 1 Inhaltsverzeichnis 1 Kapitel 1 Bytecode, JVM, Dynamische Compilierung Am Beispiel des IBM Jalapeno-Compilers (besser als SUN!) 1 1 Abbildungen aus: IBM Systems Journal, Vol 39 Nr 1 2 1.1. LAUFZEITORGANISATION

Mehr

Kapitel 1. Bytecode, JVM, Dynamische Compilierung. Am Beispiel des IBM Jalapeno-Compilers (besser als SUN!) 1

Kapitel 1. Bytecode, JVM, Dynamische Compilierung. Am Beispiel des IBM Jalapeno-Compilers (besser als SUN!) 1 Kapitel 1 Bytecode, JVM, Dynamische Compilierung Am Beispiel des IBM Jalapeno-Compilers (besser als SUN!) 1 1 Abbildungen aus: IBM Systems Journal, Vol 39 Nr 1 1 1.1. LAUFZEITORGANISATION 1. Bytecode,

Mehr

J.5 Die Java Virtual Machine

J.5 Die Java Virtual Machine Java Virtual Machine Die Java Virtual Machine 22 Prof. Dr. Rainer Manthey Informatik II Java-Compiler und Java Virtual Machine Quellcode-Datei class C... javac D.java Java-Compiler - Dateien class class

Mehr

Java Virtual Machine

Java Virtual Machine Seite 1 von 9 1 Was ist die JavaVM Java Virtual Machine Die JavaVM könnte man als einen virtuellen Computer betrachten, der speziell dafür kompilierten Java-Code ausführen kann. Der Begriff "virtuell"

Mehr

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {... PIWIN I Kap. 8 Objektorientierte Programmierung - Vererbung 31 Schlüsselwort: final Verhindert, dass eine Methode überschrieben wird public final int holekontostand() {... Erben von einer Klasse verbieten:

Mehr

Objektorientierte Programmierung. Kapitel 12: Interfaces

Objektorientierte Programmierung. Kapitel 12: Interfaces 12. Interfaces 1/14 Objektorientierte Programmierung Kapitel 12: Interfaces Stefan Brass Martin-Luther-Universität Halle-Wittenberg Wintersemester 2012/13 http://www.informatik.uni-halle.de/ brass/oop12/

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Objektorientierte Programmierung 1 Geschichte Dahl, Nygaard: Simula 67 (Algol 60 + Objektorientierung) Kay et al.: Smalltalk (erste rein-objektorientierte Sprache) Object Pascal, Objective C, C++ (wiederum

Mehr

Programmieren in Java

Programmieren in Java Programmieren in Java objektorientierte Programmierung 2 2 Zusammenhang Klasse-Datei In jeder *.java Datei kann es genau eine public-klasse geben wobei Klassen- und Dateiname übereinstimmen. Es können

Mehr

Java Virtual Machine (JVM) Bytecode

Java Virtual Machine (JVM) Bytecode Java Virtual Machine (JVM) durch Java-Interpreter (java) realisiert abstrakte Maschine = Softwareschicht zwischen Anwendung und Betriebssystem verantwortlich für Laden von Klassen, Ausführen des Bytecodes,

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags keine Pommes... Praktikum A 230 C 207 (Madeleine + Esma) F 112 F 113

Mehr

Praktikum Compilerbau Sitzung 9 Java Bytecode

Praktikum Compilerbau Sitzung 9 Java Bytecode Praktikum Compilerbau Sitzung 9 Java Bytecode Prof. Dr.-Ing. Gregor Snelting Matthias Braun und Sebastian Buchwald IPD Snelting, Lehrstuhl für Programmierparadigmen KIT Universität des Landes Baden-Württemberg

Mehr

Datensicherung. Beschreibung der Datensicherung

Datensicherung. Beschreibung der Datensicherung Datensicherung Mit dem Datensicherungsprogramm können Sie Ihre persönlichen Daten problemlos Sichern. Es ist möglich eine komplette Datensicherung durchzuführen, aber auch nur die neuen und geänderten

Mehr

Beuth Hochschule Die virtuelle Java Maschine (JVM) WS13/14

Beuth Hochschule Die virtuelle Java Maschine (JVM) WS13/14 Inhaltsverzeichnis Die virtuelle Java Maschine (JVM)...1 1. Harte und weiche Maschinen...1 2. Ein Bytecode-Programm...2 3. Java-Assembler-Dateien...5 4. Die Maschinenbefehle der JVM...6 5. Alle Maschinenbefehle,

Mehr

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala Das Typsystem von Scala 1 Eigenschaften Das Typsystem von Scala ist statisch, implizit und sicher 2 Nichts Primitives Alles ist ein Objekt, es gibt keine primitiven Datentypen scala> 42.hashCode() res0:

Mehr

3 Objektorientierte Konzepte in Java

3 Objektorientierte Konzepte in Java 3 Objektorientierte Konzepte in Java 3.1 Klassendeklarationen Fragen an die Klassendeklaration: Wie heißt die Klasse? Wer darf auf die Klasse und ihre Attribute/Methoden zugreifen? Ist die Klasse eine

Mehr

Grundlagen von Python

Grundlagen von Python Einführung in Python Grundlagen von Python Felix Döring, Felix Wittwer November 17, 2015 Scriptcharakter Programmierparadigmen Imperatives Programmieren Das Scoping Problem Objektorientiertes Programmieren

Mehr

C# im Vergleich zu Java

C# im Vergleich zu Java C# im Vergleich zu Java Serhad Ilgün Seminar Universität Dortmund SS 03 Gliederung Entstehung von C# und Java Überblick von C# und Java Unterschiede und Gemeinsamkeiten Zusammenfassung und Ausblick Entstehung

Mehr

Vorkurs C++ Programmierung

Vorkurs C++ Programmierung Vorkurs C++ Programmierung Klassen Letzte Stunde Speicherverwaltung automatische Speicherverwaltung auf dem Stack dynamische Speicherverwaltung auf dem Heap new/new[] und delete/delete[] Speicherklassen:

Mehr

4D Server v12 64-bit Version BETA VERSION

4D Server v12 64-bit Version BETA VERSION 4D Server v12 64-bit Version BETA VERSION 4D Server v12 unterstützt jetzt das Windows 64-bit Betriebssystem. Hauptvorteil der 64-bit Technologie ist die rundum verbesserte Performance der Anwendungen und

Mehr

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Java Kurs für Anfänger Einheit 4 Klassen und Objekte Java Kurs für Anfänger Einheit 4 Klassen und Ludwig-Maximilians-Universität München (Institut für Informatik: Programmierung und Softwaretechnik von Prof.Wirsing) 13. Juni 2009 Inhaltsverzeichnis klasse

Mehr

Kompilieren und Linken

Kompilieren und Linken Kapitel 2 Kompilieren und Linken Bevor wir uns auf C++ selbst stürzen, brauchen wir einiges Vorgeplänkel, wie man komfortabel ein größeres C++- kompilieren kann. Mit Java stellt sich der Kompiliervorgang

Mehr

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Objektorientierte Programmierung für Anfänger am Beispiel PHP Objektorientierte Programmierung für Anfänger am Beispiel PHP Johannes Mittendorfer http://jmittendorfer.hostingsociety.com 19. August 2012 Abstract Dieses Dokument soll die Vorteile der objektorientierten

Mehr

Übung: Verwendung von Java-Threads

Übung: Verwendung von Java-Threads Übung: Verwendung von Java-Threads Ziel der Übung: Diese Übung dient dazu, den Umgang mit Threads in der Programmiersprache Java kennenzulernen. Ein einfaches Java-Programm, das Threads nutzt, soll zum

Mehr

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = 0.51129 Euro ergeben.

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = 0.51129 Euro ergeben. Aufgabe 1.30 : Schreibe ein Programm DM_in_Euro.java zur Umrechnung eines DM-Betrags in Euro unter Verwendung einer Konstanten für den Umrechnungsfaktor. Das Programm soll den DM-Betrag als Parameter verarbeiten.

Mehr

Java Kurs für Anfänger Einheit 5 Methoden

Java Kurs für Anfänger Einheit 5 Methoden Java Kurs für Anfänger Einheit 5 Methoden Ludwig-Maximilians-Universität München (Institut für Informatik: Programmierung und Softwaretechnik von Prof.Wirsing) 22. Juni 2009 Inhaltsverzeichnis Methoden

Mehr

Leitfaden zur Installation von Bitbyters.WinShutdown

Leitfaden zur Installation von Bitbyters.WinShutdown Leitfaden zur Installation von Bitbyters.WinShutdown für Windows 32 Bit 98/NT/2000/XP/2003/2008 Der BitByters.WinShutDown ist ein Tool mit dem Sie Programme beim Herunterfahren Ihres Systems ausführen

Mehr

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck Javadoc Programmiermethodik Eva Zangerle Universität Innsbruck Überblick Einführung Java Ein erster Überblick Objektorientierung Vererbung und Polymorphismus Ausnahmebehandlung Pakete und Javadoc Spezielle

Mehr

Einführung in Eclipse und Java

Einführung in Eclipse und Java Universität Bayreuth Lehrstuhl für Angewandte Informatik IV Datenbanken und Informationssysteme Prof. Dr.-Ing. Jablonski Einführung in Eclipse und Java Dipl.Inf. Manuel Götz Lehrstuhl für Angewandte Informatik

Mehr

Tutorium Informatik 1. Aufgabe 2: Formatierte Ein- und Ausgabe

Tutorium Informatik 1. Aufgabe 2: Formatierte Ein- und Ausgabe Tutorium Informatik 1 Aufgabe 2: Formatierte Ein- und Ausgabe Fachbereich: Elektrotechnik Inhaltsverzeichnis 1 Aufgabe 1 2 Benötigte Funktionen und Schlüsselwörter 2 Robert Halas / FH Regensburg - 2003

Mehr

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf http://informatik.swoke.de. Seite 1 von 22

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf http://informatik.swoke.de. Seite 1 von 22 Kapitel 19 Vererbung, UML Seite 1 von 22 Vererbung - Neben der Datenabstraktion und der Datenkapselung ist die Vererbung ein weiteres Merkmal der OOP. - Durch Vererbung werden die Methoden und die Eigenschaften

Mehr

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten In dem Virtuellen Seminarordner werden für die Teilnehmerinnen und Teilnehmer des Seminars alle für das Seminar wichtigen Informationen,

Mehr

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren Lineargleichungssysteme: Additions-/ Subtraktionsverfahren W. Kippels 22. Februar 2014 Inhaltsverzeichnis 1 Einleitung 2 2 Lineargleichungssysteme zweiten Grades 2 3 Lineargleichungssysteme höheren als

Mehr

Einführung in die Programmierung

Einführung in die Programmierung Technische Universität München WS 2003/2004 Institut für Informatik Prof. Dr. Christoph Zenger Testklausur Einführung in die Programmierung Probeklausur Java (Lösungsvorschlag) 1 Die Klasse ArrayList In

Mehr

In 12 Schritten zum mobilen PC mit Paragon Drive Copy 11 und Microsoft Windows Virtual PC

In 12 Schritten zum mobilen PC mit Paragon Drive Copy 11 und Microsoft Windows Virtual PC PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Stephan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

Ordner Berechtigung vergeben Zugriffsrechte unter Windows einrichten

Ordner Berechtigung vergeben Zugriffsrechte unter Windows einrichten Ordner Berechtigung vergeben Zugriffsrechte unter Windows einrichten Was sind Berechtigungen? Unter Berechtigungen werden ganz allgemein die Zugriffsrechte auf Dateien und Verzeichnisse (Ordner) verstanden.

Mehr

Fachdidaktik der Informatik 18.12.08 Jörg Depner, Kathrin Gaißer

Fachdidaktik der Informatik 18.12.08 Jörg Depner, Kathrin Gaißer Fachdidaktik der Informatik 18.12.08 Jörg Depner, Kathrin Gaißer Klassendiagramme Ein Klassendiagramm dient in der objektorientierten Softwareentwicklung zur Darstellung von Klassen und den Beziehungen,

Mehr

Modellierung und Programmierung 1

Modellierung und Programmierung 1 Modellierung und Programmierung 1 Prof. Dr. Sonja Prohaska Computational EvoDevo Group Institut für Informatik Universität Leipzig 19. November 2015 Gültigkeitsbereich (Scope) von Variablen { int m; {

Mehr

Vererbung & Schnittstellen in C#

Vererbung & Schnittstellen in C# Vererbung & Schnittstellen in C# Inhaltsübersicht - Vorüberlegung - Vererbung - Schnittstellenklassen - Zusammenfassung 1 Vorüberlegung Wozu benötigt man Vererbung überhaubt? 1.Um Zeit zu sparen! Verwendung

Mehr

Compilerbau. Martin Plümicke WS 2018/19

Compilerbau. Martin Plümicke WS 2018/19 Compilerbau Martin Plümicke WS 2018/19 Agenda I. Überblick Vorlesung Literatur II. Compiler Überblick III. Überblick Funktionale Programmierung Einleitung Haskell-Grundlagen IV. Compiler Scanner Semantische

Mehr

Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken

Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken Dateiname: ecdl5_01_00_documentation_standard.doc Speicherdatum: 14.02.2005 ECDL 2003 Basic Modul 5 Datenbank - Grundlagen

Mehr

Folge 19 - Bäume. 19.1 Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Folge 19 - Bäume. 19.1 Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12 Grundlagen: Folge 19 - Bäume 19.1 Binärbäume - Allgemeines Unter Bäumen versteht man in der Informatik Datenstrukturen, bei denen jedes Element mindestens zwei Nachfolger hat. Bereits in der Folge 17 haben

Mehr

VBA-Programmierung: Zusammenfassung

VBA-Programmierung: Zusammenfassung VBA-Programmierung: Zusammenfassung Programmiersprachen (Definition, Einordnung VBA) Softwareentwicklung-Phasen: 1. Spezifikation 2. Entwurf 3. Implementierung Datentypen (einfach, zusammengesetzt) Programmablaufsteuerung

Mehr

Erstellen einer digitalen Signatur für Adobe-Formulare

Erstellen einer digitalen Signatur für Adobe-Formulare Erstellen einer digitalen Signatur für Adobe-Formulare (Hubert Straub 24.07.13) Die beiden Probleme beim Versenden digitaler Dokumente sind einmal die Prüfung der Authentizität des Absenders (was meist

Mehr

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen Binäre Bäume 1. Allgemeines Binäre Bäume werden grundsätzlich verwendet, um Zahlen der Größe nach, oder Wörter dem Alphabet nach zu sortieren. Dem einfacheren Verständnis zu Liebe werde ich mich hier besonders

Mehr

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007 Fachhochschule Bonn-Rhein-Sieg University of Applied Sciences Fachbereich Informatik Prof. Dr. Peter Becker Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Mehr

1 Mathematische Grundlagen

1 Mathematische Grundlagen Mathematische Grundlagen - 1-1 Mathematische Grundlagen Der Begriff der Menge ist einer der grundlegenden Begriffe in der Mathematik. Mengen dienen dazu, Dinge oder Objekte zu einer Einheit zusammenzufassen.

Mehr

5 DATEN. 5.1. Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

5 DATEN. 5.1. Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu Daten Makro + VBA effektiv 5 DATEN 5.1. Variablen Variablen können beliebige Werte zugewiesen und im Gegensatz zu Konstanten jederzeit im Programm verändert werden. Als Variablen können beliebige Zeichenketten

Mehr

Software Engineering Interaktionsdiagramme

Software Engineering Interaktionsdiagramme Software Engineering Interaktionsdiagramme Prof. Adrian A. Müller, PMP, PSM 1, CSM Fachbereich Informatik und Mikrosystemtechnik 1 Nachrichtenaustausch Welche Nachrichten werden ausgetauscht? (Methodenaufrufe)

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags Pommes... Praktikum A 230 C 207 (Madeleine) F 112 F 113 (Kevin) E

Mehr

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden.

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden. Einfache Ein- und Ausgabe mit Java 1. Hallo-Welt! Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden. /** Die Klasse hello sendet einen

Mehr

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek Programmieren I Dr. Klaus Höppner Hochschule Darmstadt Wintersemester 2008/2009 1 / 22 2 / 22 Strategie zum Entwurf von Klassen Beispiele Objektorientierte Sichtweise: Mit welchen Objekten habe ich es

Mehr

.procmailrc HOWTO. zur Mailfilterung und Verteilung. Stand: 01.01.2011

.procmailrc HOWTO. zur Mailfilterung und Verteilung. Stand: 01.01.2011 .procmailrc HOWTO zur Mailfilterung und Verteilung Stand: 01.01.2011 Copyright 2002-2003 by manitu. Alle Rechte vorbehalten. Alle verwendeten Bezeichnungen dienen lediglich der Kennzeichnung und können

Mehr

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3 Handbuch Fischertechnik-Einzelteiltabelle V3.7.3 von Markus Mack Stand: Samstag, 17. April 2004 Inhaltsverzeichnis 1. Systemvorraussetzungen...3 2. Installation und Start...3 3. Anpassen der Tabelle...3

Mehr

Typumwandlungen bei Referenztypen

Typumwandlungen bei Referenztypen Typumwandlungen bei Referenztypen Genau wie es bei einfachen Typen Typumwandlungen gibt, gibt es auch bei Referenztypen Umwandlungen von einem Referenztypen in einen anderen Referenztypen, die wie bei

Mehr

Einrichtung des Cisco VPN Clients (IPSEC) in Windows7

Einrichtung des Cisco VPN Clients (IPSEC) in Windows7 Einrichtung des Cisco VPN Clients (IPSEC) in Windows7 Diese Verbindung muss einmalig eingerichtet werden und wird benötigt, um den Zugriff vom privaten Rechner oder der Workstation im Home Office über

Mehr

Übungen zur Softwaretechnik

Übungen zur Softwaretechnik Technische Universität München Fakultät für Informatik Lehrstuhl IV: Software & Systems Engineering Markus Pister, Dr. Bernhard Rumpe WS 2002/2003 Lösungsblatt 9 17. Dezember 2002 www4.in.tum.de/~rumpe/se

Mehr

Einführung in Java. PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005

Einführung in Java. PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005 Einführung in Java PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005 Gliederung 1. Was ist Java / Geschichte von Java 2. Prinzip der Plattformunabhängigkeit 3. Wie kommt man vom Quellcode zum Programm

Mehr

13 OOP MIT DELPHI. Records und Klassen Ein Vergleich

13 OOP MIT DELPHI. Records und Klassen Ein Vergleich 13 OOP MIT DELPHI Delphi war früher "Object Pascal". Dieser Name impliziert eine Funktionalität, welche in der Welt der Programmierung nicht mehr wegzudenken ist: die objektorientierte Programmierung,

Mehr

SafeRun-Modus: Die Sichere Umgebung für die Ausführung von Programmen

SafeRun-Modus: Die Sichere Umgebung für die Ausführung von Programmen SafeRun-Modus: Die Sichere Umgebung für die Ausführung von Programmen Um die maximale Sicherheit für das Betriebssystem und Ihre persönlichen Daten zu gewährleisten, können Sie Programme von Drittherstellern

Mehr

Innere Klassen in Java

Innere Klassen in Java Innere Klassen in Java SS 2012 Prof. Dr. Margarita Esponda Innere Klassen Klassen- oder Interfacedefinitionen können zur besseren Strukturierung von Programmen verschachtelt werden Eine "Inner Class" wird

Mehr

Speicher in der Cloud

Speicher in der Cloud Speicher in der Cloud Kostenbremse, Sicherheitsrisiko oder Basis für die unternehmensweite Kollaboration? von Cornelius Höchel-Winter 2013 ComConsult Research GmbH, Aachen 3 SYNCHRONISATION TEUFELSZEUG

Mehr

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren: 5. Abstrakte Klassen Beispiel 5. Abstrakte Klassen 5. Abstrakte Klassen Beispiel Beispiel (3) Angenommen, wir wollen die folgende Klassenhierarchie implementieren: Probleme des Implementierungsvorschlags:

Mehr

Kommunikations-Parameter

Kommunikations-Parameter KNX App knxpresso für Android Tablets/Phones Kommunikations-Parameter Ausgabe Dokumentation: Mai. 2015 Doku Version V1.0.0 - Seite 1/8 Inhaltsverzeichnis 1.1 Nützliche Links... 3 1.2 Beschreibung der Kommunikations-Datei...

Mehr

DOKUMENTATION VOGELZUCHT 2015 PLUS

DOKUMENTATION VOGELZUCHT 2015 PLUS DOKUMENTATION VOGELZUCHT 2015 PLUS Vogelzucht2015 App für Geräte mit Android Betriebssystemen Läuft nur in Zusammenhang mit einer Vollversion vogelzucht2015 auf einem PC. Zusammenfassung: a. Mit der APP

Mehr

Die Bedeutung abstrakter Datentypen in der objektorientierten Programmierung. Klaus Kusche, September 2014

Die Bedeutung abstrakter Datentypen in der objektorientierten Programmierung. Klaus Kusche, September 2014 Die Bedeutung abstrakter Datentypen in der objektorientierten Programmierung Klaus Kusche, September 2014 Inhalt Ziel & Voraussetzungen Was sind abstrakte Datentypen? Was kann man damit grundsätzlich?

Mehr

Kommunikations-Management

Kommunikations-Management Tutorial: Wie importiere und exportiere ich Daten zwischen myfactory und Outlook? Im vorliegenden Tutorial lernen Sie, wie Sie in myfactory Daten aus Outlook importieren Daten aus myfactory nach Outlook

Mehr

schnell und portofrei erhältlich bei beck-shop.de DIE FACHBUCHHANDLUNG mitp/bhv

schnell und portofrei erhältlich bei beck-shop.de DIE FACHBUCHHANDLUNG mitp/bhv Roboter programmieren mit NXC für Lego Mindstorms NXT 1. Auflage Roboter programmieren mit NXC für Lego Mindstorms NXT schnell und portofrei erhältlich bei beck-shop.de DIE FACHBUCHHANDLUNG mitp/bhv Verlag

Mehr

Informatik 1 Tutorial

Informatik 1 Tutorial ETH Zürich, D-INFK/D-BAUG Herbstsemester 2014 Dr. Martin Hirt Christian Badertscher Informatik 1 Tutorial Dieses Tutorial hat zum Ziel, die notwendigen Tools auf dem eigenen Computer zu installieren, so

Mehr

.NET Code schützen. Projekt.NET. Version 1.0

.NET Code schützen. Projekt.NET. Version 1.0 .NET Code schützen Projekt.NET Informationsmaterial zum Schützen des.net Codes Version 1.0 Autor: Status: Ablage: Empfänger: Seiten: D. Hoyer 1 / 6 Verteiler : Dokument1 Seite 1 von 1 Änderungsprotokoll

Mehr

Java Reflection. Meta-Programmierung mit der java.lang.reflection API. Prof. Dr. Nikolaus Wulff

Java Reflection. Meta-Programmierung mit der java.lang.reflection API. Prof. Dr. Nikolaus Wulff Java Reflection Meta-Programmierung mit der java.lang.reflection API. Prof. Dr. Nikolaus Wulff Java Reflection Die Java Reflection API liefert per Introspection Informationen über Klassen => Meta-Daten.

Mehr

! " # $ " % & Nicki Wruck worldwidewruck 08.02.2006

!  # $  % & Nicki Wruck worldwidewruck 08.02.2006 !"# $ " %& Nicki Wruck worldwidewruck 08.02.2006 Wer kennt die Problematik nicht? Die.pst Datei von Outlook wird unübersichtlich groß, das Starten und Beenden dauert immer länger. Hat man dann noch die.pst

Mehr

EasyWk DAS Schwimmwettkampfprogramm

EasyWk DAS Schwimmwettkampfprogramm EasyWk DAS Schwimmwettkampfprogramm Arbeiten mit OMEGA ARES 21 EasyWk - DAS Schwimmwettkampfprogramm 1 Einleitung Diese Präsentation dient zur Darstellung der Zusammenarbeit zwischen EasyWk und der Zeitmessanlage

Mehr

Prinzipien Objektorientierter Programmierung

Prinzipien Objektorientierter Programmierung Prinzipien Objektorientierter Programmierung Valerian Wintner Inhaltsverzeichnis 1 Vorwort 1 2 Kapselung 1 3 Polymorphie 2 3.1 Dynamische Polymorphie...................... 2 3.2 Statische Polymorphie........................

Mehr

Computeranwendung und Programmierung (CuP)

Computeranwendung und Programmierung (CuP) Computeranwendung und Programmierung (CuP) VO: Peter Auer (Informationstechnologie) UE: Norbert Seifter (Angewandet Mathematik) Organisatorisches (Vorlesung) Vorlesungszeiten Montag 11:15 12:45 Freitag

Mehr

Software Engineering Klassendiagramme Assoziationen

Software Engineering Klassendiagramme Assoziationen Software Engineering Klassendiagramme Assoziationen Prof. Adrian A. Müller, PMP, PSM 1, CSM Fachbereich Informatik und Mikrosystemtechnik 1 Lesen von Multiplizitäten (1) Multiplizitäten werden folgendermaßen

Mehr

Um zu prüfen welche Version auf dem betroffenen Client enthalten ist, gehen Sie bitte wie folgt vor:

Um zu prüfen welche Version auf dem betroffenen Client enthalten ist, gehen Sie bitte wie folgt vor: Client-Installation ec@ros2 ASP-Server 1. Allgemeine Informationen Für den Einsatz von ec@ros2 ist auf den Clients die Software Java Webstart (enthalten im Java Runtime Environment (JRE)) notwendig. Wir

Mehr

Willkommen zur Vorlesung. Objektorientierte Programmierung Vertiefung - Java

Willkommen zur Vorlesung. Objektorientierte Programmierung Vertiefung - Java Willkommen zur Vorlesung Objektorientierte Programmierung Vertiefung - Java Zum Dozenten Mein Name: Andreas Berndt Diplom-Informatiker (TU Darmstadt) Derzeit Software-Entwickler für Web- Applikationen

Mehr

Snippets - das Erstellen von "Code- Fragmenten" - 1

Snippets - das Erstellen von Code- Fragmenten - 1 Snippets - das Erstellen von "Code- Fragmenten" Das Erstellen von "Code- Fragmenten", welche mit dem TinyMCE ausgewählt werden können. Grundlegendes: Die Datei, welche die in Folge erklärten Daten und

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Universität der Bundeswehr Fakultät für Informatik Institut 2 Priv.-Doz. Dr. Lothar Schmitz FT 2006 Zusatzaufgaben Lösungsvorschlag Objektorientierte Programmierung Lösung 22 (Java und UML-Klassendiagramm)

Mehr

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java Objektorientierte Programmierung mit Java Eine praxisnahe Einführung mit BlueJ Klassenentwurf Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? 1.0 Zentrale Konzepte

Mehr

Artikel Schnittstelle über CSV

Artikel Schnittstelle über CSV Artikel Schnittstelle über CSV Sie können Artikeldaten aus Ihrem EDV System in das NCFOX importieren, dies geschieht durch eine CSV Schnittstelle. Dies hat mehrere Vorteile: Zeitersparnis, die Karteikarte

Mehr

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken.

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken. Seite erstellen Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken. Es öffnet sich die Eingabe Seite um eine neue Seite zu erstellen. Seiten Titel festlegen Den neuen

Mehr

In 15 einfachen Schritten zum mobilen PC mit Paragon Drive Copy 10 und Microsoft Windows Virtual PC

In 15 einfachen Schritten zum mobilen PC mit Paragon Drive Copy 10 und Microsoft Windows Virtual PC PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Stephan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

Objektorientierte Programmierung OOP

Objektorientierte Programmierung OOP Objektorientierte Programmierung OOP Objektorientierte Programmierung OOP Ronja Düffel WS2012/13 08. Oktober 2013 Objektorientierte Programmierung OOP Objektorientierte Programmierung Objektorientierte

Mehr

Javakurs zu Informatik I. Henning Heitkötter

Javakurs zu Informatik I. Henning Heitkötter Javakurs zu Informatik I Arrays vergleichen Implementieren Sie folgende Methode, die prüft, ob die Elemente der beiden Arrays an jeder Position übereinstimmen: public static boolean identisch(int[] a,

Mehr

Programmierkurs Java

Programmierkurs Java Programmierkurs Java Dr. Dietrich Boles Aufgaben zu UE16-Rekursion (Stand 09.12.2011) Aufgabe 1: Implementieren Sie in Java ein Programm, das solange einzelne Zeichen vom Terminal einliest, bis ein #-Zeichen

Mehr

Installation der SAS Foundation Software auf Windows

Installation der SAS Foundation Software auf Windows Installation der SAS Foundation Software auf Windows Der installierende Benutzer unter Windows muss Mitglied der lokalen Gruppe Administratoren / Administrators sein und damit das Recht besitzen, Software

Mehr

Diplomarbeit. Konzeption und Implementierung einer automatisierten Testumgebung. Thomas Wehrspann. 10. Dezember 2008

Diplomarbeit. Konzeption und Implementierung einer automatisierten Testumgebung. Thomas Wehrspann. 10. Dezember 2008 Konzeption und Implementierung einer automatisierten Testumgebung, 10. Dezember 2008 1 Gliederung Einleitung Softwaretests Beispiel Konzeption Zusammenfassung 2 Einleitung Komplexität von Softwaresystemen

Mehr

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1 CMS.R. Bedienungsanleitung Modul Cron Revision 1 Copyright 10.09.2009 www.sruttloff.de CMS.R. - 1 - WOZU CRON...3 VERWENDUNG...3 EINSTELLUNGEN...5 TASK ERSTELLEN / BEARBEITEN...6 RECHTE...7 EREIGNISSE...7

Mehr

Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10. Technische Informationen (White Paper)

Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10. Technische Informationen (White Paper) Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10 Technische Informationen (White Paper) Inhaltsverzeichnis 1. Über dieses Dokument... 3 2. Überblick... 3 3. Upgrade Verfahren... 4

Mehr

Zugriff auf die Modul-EEPROMs

Zugriff auf die Modul-EEPROMs MAX-P- und P-Bibliotheken EEPROM-Zugriff 1 Zugriff auf die Modul-EEPROMs Jedes X-Bus-Modul verfügt über ein EEPROM, in dem modulspezifische Daten gespeichert werden. Neben einigen Bereichen, die vom Betriebssystem

Mehr

Suche schlecht beschriftete Bilder mit Eigenen Abfragen

Suche schlecht beschriftete Bilder mit Eigenen Abfragen Suche schlecht beschriftete Bilder mit Eigenen Abfragen Ist die Bilderdatenbank über einen längeren Zeitraum in Benutzung, so steigt die Wahrscheinlichkeit für schlecht beschriftete Bilder 1. Insbesondere

Mehr

M. Graefenhan 2000-12-07. Übungen zu C. Blatt 3. Musterlösung

M. Graefenhan 2000-12-07. Übungen zu C. Blatt 3. Musterlösung M. Graefenhan 2000-12-07 Aufgabe Lösungsweg Übungen zu C Blatt 3 Musterlösung Schreiben Sie ein Programm, das die Häufigkeit von Zeichen in einem eingelesenen String feststellt. Benutzen Sie dazu ein zweidimensionales

Mehr

In 15 Schritten zum mobilen PC mit Paragon Drive Copy 11 und VMware Player

In 15 Schritten zum mobilen PC mit Paragon Drive Copy 11 und VMware Player PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Schritthan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

Numerische Datentypen. Simon Weidmann

Numerische Datentypen. Simon Weidmann Numerische Datentypen Simon Weidmann 08.05.2014 1 Ganzzahlige Typen 1.1 Generelles Bei Datentypen muss man immer zwei elementare Eigenschaften unterscheiden: Zuerst gibt es den Wertebereich, zweitens die

Mehr

Zahlensysteme: Oktal- und Hexadezimalsystem

Zahlensysteme: Oktal- und Hexadezimalsystem 20 Brückenkurs Die gebräuchlichste Bitfolge umfasst 8 Bits, sie deckt also 2 8 =256 Möglichkeiten ab, und wird ein Byte genannt. Zwei Bytes, also 16 Bits, bilden ein Wort, und 4 Bytes, also 32 Bits, formen

Mehr

CADEMIA: Einrichtung Ihres Computers unter Windows

CADEMIA: Einrichtung Ihres Computers unter Windows CADEMIA: Einrichtung Ihres Computers unter Windows Stand: 21.02.2015 Java-Plattform: Auf Ihrem Computer muss die Java-Plattform, Standard-Edition der Version 7 (Java SE 7) oder höher installiert sein.

Mehr

4 Aufzählungen und Listen erstellen

4 Aufzählungen und Listen erstellen 4 4 Aufzählungen und Listen erstellen Beim Strukturieren von Dokumenten und Inhalten stellen Listen und Aufzählungen wichtige Werkzeuge dar. Mit ihnen lässt sich so ziemlich alles sortieren, was auf einer

Mehr