OOP Basics Arthur Zaczek Aug 2015 OOP Basics 1 Was sind “Objekte”? 1.1 Ein Java-Beispiel public class Pet { private int _weight; public int getWeight() { return _weight; } public Pet() { _weight = 100; } public void eat(int amount) { _weight += amount; } public abstract string sound(); } 1.2 Ein C#-Beispiel public class Pet { private int _weight; public int Weight { get { return _weight; } } public Pet() { _weight = 100; } public virtual void Eat(int amount) { _weight += amount; } public abstract string Sound(); } 1.3 Was sind “Klassen”? Eine Klasse ist eine Übereinkunft über das Verhalten von Instanzen • Daten: – Weight • Methoden: – Eat(), Sound() 1 OOP Basics 1.4 Was sind “Instanzen”? Eine Instanz ist ein konkretes “Objekt” einer Klasse Pet tom = new Pet(); Pet jerry = new Pet(); tom.Eat(50); tom.Weight == 150; jerry.Weight == 100; 1.5 Was sind “Objekte”? • “Objekt” ist ein Überbegriff für Klassen und Instanzen, wird typischerweise anstelle von “Instanz” verwendet • “Objekt-orientiert” sind Programmiermethoden, die Daten und Methoden als Einheit sehen • Objekt-orientierte Programmiersprachen unterstützen diesen Ansatz mit ihren Features 2 Kapselung 2.1 Kapselung • Als Kapselung bezeichnet man in der Programmierung das Verbergen von Implementierungsdetails. • Der direkte Zugriff auf die interne Datenstruktur wird unterbunden und erfolgt statt dessen über definierte Schnittstellen. • Objekte können den internen Zustand anderer Objekte nicht in unerwarteter Weise lesen oder ändern. • Ein Objekt hat eine Schnittstelle, die darüber bestimmt, auf welche Weise mit dem Objekt interagiert werden kann. 2.2 Beispiel ohne Kapselung public class Pet { public int Weight; } Pet tom = new Pet(); tom.Weight = -100; // Was nun? 2.3 Beispiel mit Kapselung public class Pet { private int _weight; public int Weight { get { return _weight; } } } 2 OOP Basics Pet tom = new Pet(); tom.Weight = -100; // Compilererror 2.4 Sinn • Implementor: Innerhalb der privaten Teile der Klasse kann man sich darauf verlassen, dass nur lokale Methoden den Zustand der Instanz ändern. • Benutzer: Muss sich nicht um Implementationsdetails der verwendeten Klasse kümmern. 3 Vererbung 3.1 Vererbung • Verknüpft Klassen in einer Hierarchie • Abgeleitete Klassen können überall eingesetzt werden wo eine ihrer Basisklassen erwartet wird • Abgeleitete Klassen erweitern und verändern Funktionalität • Basisklassen stellen allgemeine Funktionalität zur Verfügung 3.2 C#: Java: Beispiel Ableitung public class Cat : Pet public class Cat extends Pet { public void Scratch(object furniture) { // ... } } Cat tom = new Cat(); Pet jerry = new Pet(); tom.Eat(50); jerry.Eat(5); tom.Scratch(chair); jerry.Scratch(chair); // error: no Cat 3.3 Interpretation • Objekte vom Typ “Cat” haben alle Daten und Funktionen des Typs “Pet” • Klasse “Cat” erweitert “Pet” um die Funktion “Scratch()” 3.4 Sinn • Definierte Eingriffe in gekapselte Funktionalität • Erweiterung von Funktionalität ohne Details kennen zu müssen 3 OOP Basics 3.5 Methoden überschreiben Manchmal ist es notwendig oder praktisch, in abgeleiten Klassen zu ersetzen • Java: Überschreibung mit @Override, verhindern mit final • C#: Methode muss als virtual gekennzeichnet sein, Überschreibung mit override, verhindern mit sealed 3.6 Methoden überschreiben Die Implementierung der Basisklasse kann dann immer noch benutzt werden • Java: super.Methode(...) ruft Implementierung der Parent-Klasse auf • C#: base.Methode(...) ruft Implementierung der Parent-Klasse auf 3.7 Methoden überschreiben - Java public class Pet { public void eat(int amount) { } } public class Cat extends Pet { @Override public void eat(int amount) { // cats need much energy super.eat(amount / 2); } } Pet fritz = new Cat(); fritz.eat(50); // fritz.Weight == 125 3.8 Methoden überschreiben - CS public class Pet { public virtual void Eat(int amount) { } } public class Cat : Pet { public override void Eat(int amount) { // cats need much energy base.Eat(amount / 2); } } Pet fritz = new Cat(); fritz.Eat(50); // fritz.Weight == 125 4 OOP Basics 3.9 C++: Mehrfachableitung • Im Gegensatz zu C# und Java kann C++ auch von mehreren Basisklassen ableiten • Die resultierende Klasse muss alle Eigenschaften aller Basisklassen beachten • In manchen Fällen sind dazu komplexe Auflösungsregeln erforderlich 4 Schnittstellen 4.1 • • • • 4.2 Schnittstellen Definiert Funktionen ohne Implementierung Wirkt als einfacher Vertrag zwischen Komponenten Kann immer statt einer spezifischen Klasse als Variablentyp eingesetzt werden Vermeidet Bindung an spezifische Implementierung Polymorphismus • Objekte mit der gleichen Schnittstelle können benutzt werden ohne ihren spezifischen Typ zu kennen • Ermöglicht durch Vererbung • Eine Klasse kann mehrere Schnittstelle implementieren • Vereinfacht durch Schnittstellen http://www.complang.tuwien.ac.at/franz/objektorientiert/skript07-1seitig.pdf 4.3 Beispiel public interface Feedable { /* Let the instance eat an amount of food */ void eat(int amount); } 4.4 Java-Implementierung public class Pet implements Feedable { public void eat(int amount) { // ... } } public class StarShip implements Feedable { public void eat(int amount) { // ... } } void feed(Feedable something, int amount) { something.eat(amount); } 5 OOP Basics Cat tom = new Cat(); StarShip enterprise = new StarShip(); feed(tom, 50); feed(enterprise, 50); 4.5 C#-Implementierung public class Pet : IFeedable { public void Eat(int amount) { // ... } } public class StarShip : IFeedable { public void Eat(int amount) { // ... } } void Feed(IFeedable something, int amount) { something.Eat(amount); } Pet tom = new Pet(); StarShip enterprise = new StarShip(); Feed(tom, 50); Feed(enterprise, 50); 4.6 Sinn Erlaubt es Funktionalität ohne Rücksicht auf tatsächlichen Typ des Objektes zu implementieren 4.7 C# Spezifisches • Interfaces werden mit einem I am Anfang benannt IFeedable • Interfaces können auch explizit implementiert werden. Die Klasse beinhaltet dann die Methoden nicht, eine Instanz lässt sich aber in den Typ der Schnittstelle casten. public class Duck : IFeedable { void IFeedable.Eat(int amount) { // ... } } Duck daffy = new Duck(); daffy.Eat(50); // Compile error 6 OOP Basics IFeedable f = (IFeedable)daffy; f.Eat(50); // Legal 5 Sprachfeatures 5.1 Gruppieren von Klassen • namespaces (C#) oder packages (Java) gruppieren Klassen in Namensräumen • Ansprechen von “Fremd-”Klassen über using bzw. import oder absoluten Namen 5.2 Beispiel: namespace namespace Animals { public class Pet { /* ... */ } public class Cat : Pet { /* ... */ } } Animals.Cat tom; using Animals; Cat tom; 5.3 Beispiel: package package Animals; public class Cat extends Pet { /* ... */ } Animals.Cat tom; import Animals.Cat; import Animals.*; Cat tom; 5.4 Accessibility • public: Teil der öffentlichen - für alle erreichbaren - Schnittstelle • protected: nur für die Klasse und ihre Erben sichtbar • private: nur für die Klasse sichtbar • C#: internal: nur für Mitglieder der aktuellen DLL/EXE Assembly sichtbar • Java: ohne Schlüsselwort, nur für Mitglieder des aktuellen Packages sichtbar 5.5 Fields private float _weight; • Felder halten den unmittelbaren Zustand einer Instanz • Sollten immer private sein 7 OOP Basics 5.6 Properties CS public float Weight { get { return _weight; } protected set { _weight = value; } } • Daten können geprüft, geändert oder konvertiert werden • In der Regel ist auch der Setter public. Der protected Setter ist hier nur ein Beispiel. • In Spezialfällen, zB bei der Verwendung von Listen, kann er auch als private markiert werden oder ganz weggelassen werden. 5.7 Properties Java public float getWeight() { return _weight; } protected void setWeight(float value) { _weight = value; } • Java unterstützt keine besondere Property-Syntax • Konvention: get* und set* Methoden 5.8 Methods • Eine Methode kapselt ein Stück prozeduralen Code • Argumente sind die erwarteten Informationen • Parameter sind die tatsächlich übergebenen Werte • Rückgabewerte oder void • this: Zugriff auf die aktuelle Instanz • base bzw. super: Zugriff auf die übergeordnete Instanz 5.9 Überladen Um elegantere Schnittstellen zu erzeugen, erlauben C# und Java Methoden mit gleichem Namen aber unterschiedlichen Argumentlisten. public void Feed(Cat c) { /* ... */ } public void Feed(Dog d) { /* ... */ } Dog spike = new Dog(); Feed(spike); // ruft richtige Methode auf Der Rückgabetyp muss immer gleich sein. 8 OOP Basics 5.10 Klassenvariablen: static Manche Informationen oder Funktionen sind nicht Instanz-spezifisch sondern arbeiten auf der gesamten Klasse. Diese werden mit static markiert: public class Pet { private static HashSet _allPets = new HashSet(); public static Set getAllPets() { return (Set)_allPets.clone(); } public Pet() { _allPets.add(this); } } Pet.getAllPets().size() 5.11 Operator overloading In C# können Operatoren durch Klassen überladen werden: public class Complex { public static Complex operator +(Complex a, Complex b) { // ... } } 6 Exceptions 6.1 Beispiel try { throw new ArgumentNullException(„arg“); } catch(ArgumentException aex) { ... } catch(InvalidOperationException opex) { ... } catch(Exception ex) { ... } finally { ... } 6.2 catch • Einen Catch – Block immer dort einbauen, wo man die Exception auch behandeln kann • Niemals Exceptions „schlucken“, d.H. fangen und nicht reagieren • Nach Möglichkeit sollten allg. Exceptions nicht gefangen werden, sondern nur konkrete z.B.: – SQLException 9 OOP Basics – FormatException • Nur das stellt sicher, dass man den „richtigen“ Fehler behandelt 6.3 finally • finally Blöcke helfen, Ressourcen wieder frei zu geben • Damit ist man immun gegen Ressource- bzw. Memoryleaks 6.4 Exceptions werfen • Immer die passende Exception werfen z.B.: – FileNotFoundException – ArgumenNullException • Stellt das Framework/Sprache keine passende Exception zur Verfügung -> selber implementieren – Nur das stellt sicher, dass im Fehlerfall alle wichtigen Informationen gesammelt und ausgewertet werden können. 6.5 Beispiele java.net.UnknownHostException: dasz.a2t at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:177) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) at java.net.Socket.connect(Socket.java:525) at java.net.Socket.connect(Socket.java:475) at java.net.Socket.<init>(Socket.java:372) at java.net.Socket.<init>(Socket.java:186) at javasockets.Main.read(Main.java:36) at javasockets.Main.main(Main.java:30) 6.6 Beispiele Exception in thread "Thread-7" java.lang.NullPointerException at java.util.LinkedList.remove(LinkedList.java:791) at java.util.LinkedList.remove(LinkedList.java:226) at javathreads.LockThread.run(LockThread.java:37) Code: if (!strings.isEmpty()) { String str = strings.peek(); System.out.println(str); // Do some work Thread.sleep(20); strings.remove(str); } 10 OOP Basics 6.7 Beispiele System.IO.FileNotFoundException: Could not load file or assembly ‚Zetbox.Objects' or one of its de File name: 'Zetbox.Objects' at System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCas at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase at System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, at System.Type.GetType(String typeName, Boolean throwOnError) at Zetbox.API.FrozenContext.TryInit() in p:\Zetbox\API\FrozenContext.cs:line 101 6.8 Beispiel System.ArgumentNullException was unhandled Message="Value cannot be null.\r\nParameter name: stream" Source="CSSockets" ParamName="stream" StackTrace: at CSSockets.Program.Write(NetworkStream stream) in D:\data\FH\SWE1\Beispiele zu den Folien at CSSockets.Program.Read() in D:\data\FH\SWE1\Beispiele zu den Folien\CSSockets\CSSockets\ at CSSockets.Program.Main(String[] args) in D:\data\FH\SWE1\Beispiele zu den Folien\CSSocke at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback at System.Threading.ThreadHelper.ThreadStart() 7 Abstrakte Klassen 7.1 • • • • • • 7.2 Abstrakte Klassen Diese Klassen können nicht instanziiert werden Dienen als Basisklassen Stellen einer abgeleiteten Klasse Basisfunktionalität zur Verfügung Im Unterschied zu Schnittstellen Stellen auch einen Vertrag dar Können die Implementierung von Methoden und Eigenschaften erzwingen Beispiel abstrakte Klassen public abstract class Pet { public abstract void MakeSound(); public virtual void Eat(float amount) { } } 8 Lifecycle 8.1 Constructor • Bringt das Objekt nach der Speicherzuweisung in definierten Grundzustand 11 OOP Basics • Aufruf mittels new Klasse(. . . ) • hat keine Rückgabe • heisst immer wie die Klasse in der er definiert ist 8.2 Beispiel Constructor public class Pet { public Pet(string name) { this._name = name; } } 8.3 Destructor • Wird in C#, Java und C++ komplett unterschiedlich gehandhabt • Werden bei Beenden des Programmes normalerweise nicht ausgeführt 8.4 C#: Finalizer public class Pet { ~Pet() { /* ... */ } } • • • • werden in eigenem Thread ausgeführt können nur noch eingeschränkte Operationen machen können von der Laufzeitumgebung abgebrochen werden (zB bei zu langer Ausführung) Besser: IDispose implementieren und using() verwenden: using (BigObject obj = new BigObject()) { // obj verwenden } // obj.Dispose() wird automatisch aufgerufen 8.5 Java: finalize() public class Pet { protected void finalize() throws Throwable { // ... } } • werden in eigenem Thread ausgeführt • Besser: close() implementieren und try { } finally { } verwenden: try { BigObject obj = new BigObject(); // obj verwenden } finally { obj.close(); } 12 OOP Basics 8.6 Java 8: try () try (BigObject obj = new BigObject()) { // obj verwenden } // obj.close(); 8.7 C++: Destruktor public class Pet { ~Pet() { // ... } } werden sofort bei der Deallokation ausgeführt { BigObject obj; // obj verwenden } // automatische Ausführung des Destruktors // bei Verlassen des Scopes Sonst, bei Aufruf von delete 13