420 likes | 515 Views
Software-Engineering II. Einführung / Objektorientierung. This is a dummy text to make powerpoint think, the slide is landscape. Einführung. Objektorientierung Aspektorientierung Vorgehensmodelle UML Analyse- & Entwurfsmuster Objektorientiertes Testen Versionsverwaltung Refactoring
E N D
Software-Engineering II Einführung / Objektorientierung
This is a dummy text to make powerpoint think, the slide is landscape
Einführung • Objektorientierung • Aspektorientierung • Vorgehensmodelle • UML • Analyse- & Entwurfsmuster • Objektorientiertes Testen • Versionsverwaltung • Refactoring • Labor (Praktischer Teil)
Objektorientierung (OOP) Java ist auch eine Insel Christian Ullenboom Galileo Press 1478 Seiten ISBN: 3-8362-1146-7 (Deutsch)
Objektorientierung (OOP) • Programmierparadigma (Prinzip) • Ziel: Nachbildung der realen Welt in Programmiersprachen • Klassen sind abstrakte Beschreibungen von Daten und Aktionen • Objekte sind Instanzen von Klassen
Klassen und Objekte • Es können beliebig viele Instanzen von Klassen (also Objekte) erstellt werden • Der Zustand von Objekten wird durch Inhalte von Attributen (Variablen) bestimmt • Durch das Ausführen von Methoden (Funktionen) kann der Zustand der Attribute geändert werden
class DHBWStudent { String name; String geburtsDatum; double note; void setName( String name ) { this.name = name; } void setNote( double note ) { this.note = note; } /* … */ } class DHBWDozent { String name; String geburtsDatum; void setName( String name ) { this.name = name; } void benote( BAStudent st ) { st.setNote( … ); } /* … */ } Beispiel
class DHBWStudent { String name; String geburtsDatum; double note; void setName( String name ) { this.name = name; } void setNote( double note ) { this.note = note; } /* … */ } class DHBWDozent { String name; String geburtsDatum; void setName( String name ) { this.name = name; } void benote( DHBWStudent st ) { st.setNote( … ); } /* … */ } Beispiel gemeinsame Eigenschaften
Vererbung I class DHBWPerson { String name; String geburtsDatum; void setName( String name ) { this.name = name; } void setGeburtsdatum( String geburtsDatum ) { this.geburtsDatum = geburtsDatum; } }
class DHBWStudent extends DHBWPerson { double note; void setNote( double note ) { this.note = note; } } class DHBWDozent extends DHBWPerson { void benote( DHBWStudent st ) { double note = Math.Random() * 5; note++; st.setNote( note ); } } Vererbung II class DHBWPerson { … void setName( String name ) { … } void setGeburtsdatum( String geburtsDatum ) { … } }
Packages • In vielen objektorientierten Programmiersprachen kann man Klassen in Gruppen, sogenannten Packages, organisieren • Ziele: • Strukturierung • Sichtbarkeitseinschränkung (durch Access Modifier) • Achtung: • In Java wird jede Klasse, die keinem Package zugewiesen wurde dem default package zugewiesen • Da dabei die Übersichtlichkeit im Projekt verloren geht, werden gute Package-Definitionen empfohlen
Access Modifiers • Man kann in Java Klassen, Methoden und Attributen die Access Modifierspublic, protected oder private zuweisen: • public Alle Klassen • protected Sub-Klassen, selbes Package • [ohne] Alle Klassen des Packages • private Aktuelle Klasse
Mit dem Schlüsselwort static markierte Methoden und Attribute sind nicht an eine Instanz einer Klasse gebunden class DHBWDozent extends DHBWPerson { static double notenBereich[] = { 1, 6 }; // Verwendung eines Array für die Speicherung static void benote( DHBWStudent st ) { double note = Math.Random(); double spanne = DHBWDozent.notenBereich[1] – DHBWDozent.notenBereich[0]; note *= spanne; note += DHWBDozent.notenBereich[0]; st.setNote( note ); } } static
Tritt in einem Programm eine Ausnahme ein, kann diese mit der catch-Anweisung abgefangen werden class Demo { public static void main( String[] args ) { try { // Datei öffnen o.ä. } catch( java.io.FileNotFoundException e ) { System.out.println( “Fehler!“ ); } } } Exceptions (I)
Exceptions (II) • Exceptions können mit dem Befehl throwausgelöst werden • Jede Exception muss von der Klasse java.lang.Throwable erben • Methoden, die Exceptions auslösen, müssen dies durch throws bekanntgeben • Hat eine Methode eine Exception in throws notiert, muss jede aufrufende Methode diese Exception mit try…catch behandeln • Dies macht es möglicht, dass in Java Fehler seltener zum Programmabsturz führen class Demo { void f() throws MyException { throw new MyException(); } void x() { this.f(); // nicht erlaubt ohne // try…catch } } class MyException extends Exception { // … }
Exceptions (III) • Fehler werden generell mit Exceptions signalisiert • Bei normalen Operationen kann es auch zu Fehlerfällen kommen • NullPointerException (Bei Zugriff auf Null-Variable) • ArithmeticException (Bsp.: Division durch 0) • ClassCastException (Typecast auf falschen Klassentyp) • IndexOutOfBoundsException (Fehlerhafter Array-Zugriff) • Damit man nicht um jede Zeile try..catch schreiben muss: • Unchecked Exceptions • Müssen nicht mit throws deklariert werden • Erben von java.lang.RuntimeException • Beispiele: Siehe oben • Checked Exceptions • Alle anderen Exceptions • Mit try..catch abfangen oder throws weiter werfen!
Speicherverwaltung • Die Virtual Machine speichert Variableninhalte an zwei verschiedenen Stellen: • Stack • Die Menge des allokierten Speichers kann nicht geändert werden • Speichert primitive Datentypen • Funktioniert als Stapel und speichert die Variablen aller Methoden in Reihenfolge • Heap • Kann Elemente, die ihre Größe ändern, speichern • Objekte werden hier abgespeichert • Auf die Stelle des Objektes notiert der Stack eine Referenz ..FF 0 1 2 0 ... int x = 12; boolean y = false; String z = “Hallo“; ... 1 „Hallo“-String-Objekt R: 00000100 B: FALSE .. I: 00000012 Stack Heap
Method Calls • Bei einem Methodenaufruf werden die Werte auf dem Stack der aufrufenden Methode übergeben • Dadurch erhalten Methoden bei • primitiven Datentypen den tatsächlichen Wert • Objekten eine Referenz auf das Objekt • Nur wenn die aufgerufene Methode eine Referenz erhält hat sie Zugriff auf die ursprüngliche Variable und kann deren Inhalte verändern ..FF 0 1 2 void method1() { int x = 12; String y = “Y“; method2( x, y ); } 0 R: 00000100 1 „Y“-String-Objekt m2{ I: 00000012 R: 00000100 m1{ .. I: 00000012 Stack Heap
Garbage Collector • Java ist „Managed Code“ • Die Speicherverwaltung wird vom System automatisch übernommen • Vgl. C++: Jede auf dem Heap reservierte Speicherstelle muss explizit wieder freigegeben werden • Bei Java erledigt dies der Garbage Collector • Stellen im Heap, auf die vom Stack aus nicht mehr referenziert werden, können entfernt werden • Der Garbage Collector läuft regelmäßig im Hintergrund
Speicherüberlauf • Der Heap ist begrenzt: • Natürliche Grenze durch die Menge an Arbeitsspeicher • Künstliche Grenze der Virtual Machine zum Schutz anderer Programme • Wenn der Heap voll ist, wird der Garbage Collector explizit aktiviert • Reicht die gewonnene Speichermenge nicht aus, schlägt die aktuelle Anweisung mit einem OutOfMemoryError fehl
Konstruktor/Destruktor • Konstruktoren/Destruktoren sind Methoden, die beim Erzeugen/Zerstören eines Objektes aufgerufen werden • Um einen Konstruktor zu definieren, implementiert man in Java eine Methode, die den Namen der Klasse trägt • Eigentliche Destruktoren gibt es in Java nicht, es wird jedoch die Methode finalize() aufgerufen, wenn ein Objekt vom Garbage Collector zerstört wird • Performance-Einbußen • Aufruf nicht garantiert class BADozent extends BAPerson { BADozent( String name ) { /* * Diese Methode wird aufgerufen, sobald * eine neue Instanz dieser Klasse erzeugt wird. */ } }
Polymorphismus class DHBWVerwaltung { void addPerson( DHBWPerson person ) {…} void bezahleGehalt( DHBWDozent dozent ) {…} } DHBWVerwaltung verwaltung = new DHBWVerwaltung(); DHBWDozent dozent = new DHBWDozent( ); DHBWStudent student = new DHBWStudent(); verwaltung.addPerson( student ); // DHBWStudent: Subklasse von DHBWPerson verwaltung.addPerson( dozent ); // DHBWDozent: Subklasse von DHBWPerson verwaltung.bezahleGehalt( dozent ); // DHBWDozent wird erwartet… verwaltung.bezahleGehalt( student ); // nicht erlaubt - DHBWStudent ist // keine Subklasse von DHBWDozent Die Eigenschaft, dass man Subklassen an jeder Stelle statt ihrer Superklassen einsetzen darf, wird Polymorphismus genannt.
Overriding • Als overriding bezeichnet man das Überschreiben von vererbten Methoden • Methoden, die final markiert sind, können nicht überschrieben werden class DHBWPerson { private String name; public void setName( String name ) { this.name = name; } … } class DHBWDozent extends DHBWPerson { public void setName( String name ) { super.setName(“[Dozent] “ + name); } }
Overloading • Mehrere Methoden mit demselben Namen können in Java gleichzeitig deklariert werden: • Solange sie unterschiedliche Übergabeparameter besitzen • Rückgabewerte sind hier nicht ausschlaggebend class DHBWDozent extends DHBWPerson { void benote( DHBWStudent st ) { this.benote( st, true ); } void benote( DHBWStudent st, boolean fair ) { float max = 6; float min = fair ? 1 : 4; st.setNote( ( Math.Random() * (max-min) ) + min ); } }
Abstrakte Methoden • Abstrakte Methoden enthalten keine Implementierung • Klassen, die abstrakte Methoden beinhalten, müssen ebenfalls als abstrakt markiert werden • Abstrakte Klassen können nicht instanziert werden • Zweck: Subklassen von abstrakten Klassen implementieren die abstrakten Methoden und bilden so eine instanzierbare Klasse abstract class DHBWPerson { abstract void inVorlesungSein(); } class DHBWStudent extends DHBWPerson { void inVorlesungSein() { System.out.println( “Zuhören…“ ); } } class DHBWDozent extends DHBWPerson { void inVorlesungSein() { System.out.println( “Erzählen…“ ); } }
Mehrfachvererbung I abstract class PartyPerson { // jeder feiert auf seine Art abstract void feiern(); } abstract class DHBWPerson { abstract void inVorlesungSein(); public void setName( String name ) {…} } class Schueler extends PartyPerson { void feiern() { System.out.println( “Dance till 12…“ ); } }
Mehrfachvererbung II abstract class PartyPerson { // jeder feiert auf seine Art abstract void feiern(); } abstract class DHBWPerson { abstract void inVorlesungSein(); public void setName( String name ) {…} } class Schueler extends PartyPerson { void feiern() { System.out.println( “Dance till 12…“ ); } } class DHBWStudent extends DHBWPerson, PartyPerson { void inVorlesungSein() { System.out.println( “Zuhören…“ ); } void feiern() { System.out.println( “Dance all night…“ ); } }
Mehrfachvererbung III • Java verbietet Mehrfachvererbung • Grund: • Zwei Basisklassen implementieren eine gleich benannte Methode • Überschreibt die Subklasse die Methode der Superklassen nicht, ist unklar, welche Methode verwendet werden soll • Alternative: Interfaces • Alle Methoden sind automatisch abstrakt • Alle Attribute sind static und final
Interfaces interface PartyPerson { // jeder feiert auf seine Art void feiern(); } abstract class DHBWPerson { abstract void inVorlesungSein(); public void setName( String name ) {…} } class Schueler implements PartyPerson { void feiern() { System.out.println( “Dance till 12…“ ); } } class DHBWStudent extends DHBWPerson implements PartyPerson { void inVorlesungSein() { System.out.println( “Zuhören…“ ); } void feiern() { System.out.println( “Dance all the night…“ ); } }
Generische Programmierung • Bestandteil von Java seit 5.0 • Dient dazu, Algorithmen möglichst unabhängig von den Datenstrukturen zu implementieren • Ziel: Wieder verwendbare Bibliotheken • Typsicherheit, da keine Typecasts
java.util.Vector in Java 1.4 • Speichert eine Menge von Elementen • Wichtigste Methoden • void addElement( Object element ) • void removeElement( Object element ) • Object elementAt( int position ) • int size()
java.util.Vector in Java 1.4 • Der Return-Typ von elementAt(int) ist Object • Damit Klassenspezifische Methoden aufgerufen werden können, ist ein Typecast nötig • Wird aus Versehen ein falsches Element hinzugefügt, entsteht dann eine ClassCastException void doSomething() { Vector kurs = new Vector(); kurs.addElement( new DHBWStudent( ”Max Mustermann” ) ); kurs.addElement( new DHBWStudent( ”Klaus Müller” ) ); kurs.addElement( new DHBWDozent( ”Timo Holzherr” ) ); Object element = kurs.elementAt( 2 ); DHBWStudent stud = (DHBWStudent) element; stud.inVorlesungSein(); } Laufzeitfehler!!
java.util.Vector in Java 5.0 • Signatur der vorherigen Methoden • void addElement( <E> element ) • void removeElement( <E> element ) • <E> elementAt( int position ) • int size() • <E> steht für einen generischen Typ • „Generischer Typparameter“ • Beim Instanzieren des Vectors wird der Typ angegeben
java.util.Vector in Java 5.0 • Der Return-Typ von elementAt(int) ist <E>, also DHBWStudent • Damit klassenspezifische Methoden aufgerufen werden können, ist kein Typecast nötig • Es kann kein falsches Element hinzugefügt werden, dies würde in einem Compile-Error führen • Bei Java 1.4 würde das Programm kompilieren aber mit einer Exception abstürzen void doSomething() { Vector<DHBWStudent> kurs = new Vector<DHBWStudent>(); kurs.addElement( new DHBWStudent( ”Max Mustermann” ) ); kurs.addElement( new DHBWStudent( ”Klaus Müller” ) ); kurs.addElement( new DHBWDozent( ”Timo Holzherr” ) ); DHBWStudent stud = kurs.elementAt( 0 ); stud.inVorlesungSein(); } Compile-Error!!
Deklaration generischer Klassen • Durch die Angabe einer Typvariable in der Klasse wird eine Klasse generisch • Diese Typvariable kann jederzeit an Stelle eines Typs verwendet werden class MyClass<E> { public E forceNotNull( E element ) throws Exception { if( element == null ) { throw new Exception( ”Element ist null” ); } return element; } }
Mehrere generische Typparameter • Es können mehrere generische Typparameter eingeführt werden • Bsp: java.util.HashMap<K,V> • K = Hash-Key • V = Hash-Value class MyHashMap<K,V> { … }
Generics und Polymorphismus • Herkömmlicher Polymorphismus kann natürlich auch bei generischen Klassen verwendet werden • Es können Subklassen der Parameterklasse eingesetzt werden DHBWStudent student = new DHBWStudent( ”Max Mustermann” ); DHBWDozent dozent = new DHBWDozent( ”Timo Holzherr” ); Vector<DHBWStudent> kurs = new Vector<DHBWPerson>(); kurs.addElement( student ); Kurs.addElement( dozent );
Grenzen des Polymorphismus • Polymorphismus gilt jedoch nicht für den generischen Typparameter Vector<DHBWStudent> studs = new Vector<DHBWStudent>(); Vector<DHBWPerson> persons = studs; Nicht erlaubt • Ist das Objekt Vector<DHBWStudent> einmal initialisiert, erwartet es Objekte vom Typ DHBWStudent oder von Subklassen dessen • Könnte man es einer Variable vom Typ Vector<DHBWPerson> zuweisen, wäre es nun bspw. möglich, Elemente vom Typ DHBWDozent in den Vector zu legen, obwohl er im Objekt studs als Vector<DHBWStudent> verwendet wird
Wildcards • Mithilfe von Wildcards ist es möglich, den Typ frei zu lassen • Der generische Typparameter der Klasse wird bei Return-Typen wie Object behandelt • Sind generische Typen in Methodenparametern enthalten, so sind diese Methoden nicht mehr verwendbar Vector<DHBWStudent> studs = new Vector<DHBWStudent>(); Vector<?> persons = studs; Object firstPerson = persons.elementAt( 0 ); persons.addElement( “A string is an object” ); Nicht erlaubt
Upper Bound Wildcard • Wildcards ohne Typ sind oft zu unspezifisch • Der Return-Typ muss wie Object behandelt werden • Wieder ist ein Type-Cast nötig • Mithilfe einer Upper Bound Wildcard kann angegeben werden, von welchem Typ der generische Parameter mindestens sein muss Vector<DHBWStudent> studs = new Vector<DHBWStudent>(); Vector<? extends DHBWPerson> persons = studs;
Upper Bound Wildcard • Bei Return-Typen wird dann der generische Typ-Parameter (<E>) durch den Typ der Upper Bound Wildcard ersetzt • Sind generische Typen in Methodenparametern enthalten, so sind auch bei Upper Bound Wildcards diese Methoden nicht mehr verwendbar Vector<DHBWStudent> studs = new Vector<DHBWStudent>(); Vector<? extends DHBWPerson> persons = studs; DHBWPerson firstPerson = persons.elementAt( 0 ); persons.addElement( new DHBWDozent( “Timo Holzherr” ) ); Nicht erlaubt
@Annotationen • Zusatzinformationen für Klassen und Methoden • Erlaubt Einbinden von Metadaten in den Quellcode • Bsp. • @Override void toString(){...} • Diese Methode überschreibt eine Methode der Superklasse. Sollte dies nicht der Fall sein, gibt der Compiler einen Fehler aus • @Deprecated class MyJLabel { ... } • Kennzeichnet Klassen oder Methoden, dass sie nicht mehr verwendet werden sollen • Wird oft von Frameworks verwendet • Beispiele: • AspectJ: (e.g. @Before("call(* *.*(*))“) • JPA: @Column(name="uid", nullable=false, length=512) • JAX-WS: @Path("/customers") • JAX-B: @XmlRootElement(namespace="http://...") • Spring: @Inject