Überblick. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/ / 831

Ähnliche Dokumente
Abschnitt 9: Schnittstellen: Interfaces

Kapitel 6. Vererbung

Kapitel 6. Vererbung

Probeklausur: Programmierung WS04/05

1 Polymorphie (Vielgestaltigkeit)

Kapitel 6. Vererbung

Java Virtual Machine (JVM) Bytecode

Javakurs für Anfänger

Java für Computerlinguisten

3 Objektorientierte Konzepte in Java

Java Kurs für Anfänger Einheit 5 Methoden

Objektorientierte Programmierung. Kapitel 12: Interfaces

Java Schulung (Java 2 Java Development Kit 5 / 6)

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

3 Objektorientierte Konzepte in Java

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

Datenbankanwendungsprogrammierung Crashkurs Java

Dr. Monika Meiler. Inhalt

Software Engineering Klassendiagramme Einführung

Java: Eine Übersicht. Dennis Giffhorn. Lehrstuhl für Programmierparadigmen Universität Karlsruhe

Java Einführung VARIABLEN und DATENTYPEN Kapitel 2

Einführung in die. objektorientierte Programmierung

C# im Vergleich zu Java

Java Einführung Methoden in Klassen

Vorkurs C++ Programmierung

einkonto.zahle(+100); //Transaktion Einzahlung einkonto.zahle(-20); //Transaktion Auszahlung einkonto.zahle(+30); //Transaktion Einzahlung

Programmieren in Java

5.6 Vererbung. Vererbung

5.4 Klassen und Objekte

5.5.8 Öffentliche und private Eigenschaften

Objektorientierte Programmierung

Vererbung. Vererbung von Methoden und Instanzvariablen. Vererbung als Realisierung einer is-a Beziehung.

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12. Kapitel 8. Arrays. Arrays

J.5 Die Java Virtual Machine

Meeting C++ C++11 R-Value Referenzen

Algorithmen und Datenstrukturen

EINI WiMa/LW. Einführung in die Informatik für Naturwissenschaftler und Ingenieure. Vorlesung 2 SWS WS 11/12

VIII: Vererbung. Unterklassen einer Klasse. Vererbung von Methoden und Instanzvariablen. Überschreiben von Methoden

5. Tutorium zu Programmieren

Grundlagen der Informatik. Prof. Dr. Stefan Enderle NTA Isny

Javakurs 2013 Objektorientierung

Einführung in die Programmierung Arrays, Zeiger, Strings. Arvid Terzibaschian

Übersicht. Informatik 2 Teil 3 Anwendungsbeispiel für objektorientierte Programmierung

Objektorientiertes Programmieren für Ingenieure

Objektorientierte Programmierung. Objektorientierte Programmierung. Klasse. Objekt. Beispiel: Sportfest1. Methode. Eine Einführung mit BlueJ

Algorithmen und Datenstrukturen 07

Objekt-Orientierte Programmierung

Programmiersprachen Einführung in C. Unser erstes C-Programm. Unser erstes C-Programm. Unser erstes C-Programm. Unser erstes C-Programm

7. Objektorientierte Softwareentwicklung/3. Informatik II für Verkehrsingenieure

Deklarationen in C. Prof. Dr. Margarita Esponda

Grundlagen von Python

Einheit Variablen in der Programmiersprache C Variablen-Modell, Variablen-Vereinbarungen

Einführung in die Java- Programmierung

Tutorium Java Ein Überblick. Helge Janicke

PIWIN I. Praktische Informatik für Wirtschaftsmathematiker, Ingenieure und Naturwissenschaftler I. Vorlesung 3 SWS WS 2007/2008

Eine Klasse beschreibt Objekte mit gleichen Attributen und Methoden.

Einfache Arrays. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

Vererbung & Schnittstellen in C#

Repetitorium Informatik (Java)

Modellierung und Programmierung 1

Willkommen zur Vorlesung. Objektorientierte Programmierung Vertiefung - Java

Innere Klassen in Java

Vorlesung Informatik II

Computeranwendung und Programmierung (CuP)

Objektorientierte Programmierung

Tutorium Rechnerorganisation

Java: Vererbung. Teil 3: super()

Test zu Grundlagen der Programmierung Leitung: Michael Hahsler. 21. November 2003

Propädeutikum zur Programmierung

Prüfungszeuch im Fach Objektorientierte Programmierung WS 2000

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

Klassen in Java. Klassen

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

Gliederung. Tutorium zur Vorlesung. Gliederung. Gliederung. 1. Gliederung der Informatik. 1. Gliederung der Informatik. 1. Gliederung der Informatik

Programmieren. 10. Tutorium 4./ 5. Übungsblatt Referenzen

Ein erstes Java-Programm

3. Konzepte der objektorientierten Programmierung

Einführung Datentypen Verzweigung Schleifen Funktionen Dynamische Datenstrukturen. Java Crashkurs. Kim-Manuel Klein

Typumwandlungen bei Referenztypen

Programmieren in Java

Java Tipps für Lehrer. Table des matières. Einleitung

PIWIN 1 Übung Blatt 5

Java-Schulung Grundlagen

Primitive Datentypen

C++ - Einführung in die Programmiersprache Polymorphismus und Vererbung. Eltern

Programmieren in C++ Arrays, Strings und Zeigerarithmetik

Studentische Lösung zum Übungsblatt Nr. 7

Klassendefinitionen verstehen

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

Klassenbeziehungen & Vererbung

Android will doch nur spielen. Java Eine kurze Einführung

Teil 1: Grundeigenschaften von Rechnern und Software

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI

Objektorientierte Programmierung

2. Semester, 2. Prüfung, Lösung

Informationsverarbeitung im Bauwesen

Autor: Michael Spahn Version: 1.0 1/10 Vertraulichkeit: öffentlich Status: Final Metaways Infosystems GmbH

Programmierkurs Java

Dynamische Sprachen auf der JVM

Aufgabe 1. »Programmieren«, WS 2006/2007. Nino Simunic M.A.

Transkript:

Aufzählungstypen (Enumerations) Überblick 8. Grundlagen der objektorientierten Programmierung 8.1 Abstrakte Datentypen I: Benutzereigene Strukturen 8.2 Abstrakte Datentypen II: von Structures zu Klassen 8.3 Das objektorientierte Paradigma 8.4 Klassen und Objekte in Java 8.5 Aufzählungstypen (Enumerations) 8.6 8.7 Ein ausführliches Beispiel Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 625 / 831

Aufzählungstypen (Enumerations) Motivation Klassen stellen ein mächtiges Werkzeug dar, eigene, komplex strukturierte Datentypen zu modellieren und bereit zu stellen. Die Literale dieser Datentypen sind die entsprechend strukturierten Objekte. In der Praxis hat man es aber auch häufig mit Datentypen zu tun, deren Werte (Literale) aus einem konstanten Wertevorrat stammen (so wie eigentlich auch die primitiven Datentypen). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 626 / 831

Aufzählungstypen (Enumerations) Motivation Beispiele für solche Datentypen (Werte-Mengen): Die Menge der Jahreszeiten: {FRÜHLING, SOMMER, HERBST, WINTER} Die Menge der Monate: {JANUAR,FEBRUAR,...,DEZEMBER} Die Menge der Farben: {ROT, GRÜN, BLAU,... } Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 627 / 831

Aufzählungstypen (Enumerations) Motivation Rein vom Konzept her ist das wie gesagt nichts Neues: In unseren Modulen, in denen wir die Grunddatentypen und deren Operationen definiert haben, haben wir die Literale ja auch als konstante Funktionen spezifiziert. Das ist letztlich auch die Idee, wie man diese Wertemengen definiert. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 628 / 831

Aufzählungstypen (Enumerations) Motivation Die einfachste Möglichkeit solche Wertemengen in einer Programmiersprache zu vereinbaren, wäre, die einzelnen Werte als (globale) Konstanten eines primitiven Typs (typischerweise int zu vereinbaren. Also in Java z.b. für Monat: static final int JANUAR = 1; static final int FEBRUAR = 2; static final int MAERZ = 3; static final int APRIL = 4;... Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 629 / 831

Aufzählungstypen (Enumerations) Motivation In einigen Programmiersprachen muss man dies tatsächlich so machen und es ist zunächst auch nicht verkehrt (in Java bis Version 5.0 z.b.). Einziges Problem ist, dass man keine Typsicherheit mehr hat: Statt einen eigenen Typ Monat zu haben, arbeitet man mit Werten vom Typ int. Dadurch kann zur Kompilierzeit nicht sicher gestellt werden, dass man z.b. an einen Methodenparameter einen der zulässigen Aufzählungswerte übergibt. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 630 / 831

Aufzählungstypen (Enumerations) Motivation Eine Methode anzahltage(int monat, boolean schaltjahr) nimmt eben nun leider als Eingabe für Monat einen Wert vom Typ int. Würde diese Methode mit anzahltage(30, false) aufgerufen werden, wäre das für den Compiler OK. Den potentiellen Fehler würde man dann erst zur Laufzeit feststellen (oder auch nicht, was vermutlich noch schlimmer ist...) Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 631 / 831

Aufzählungstypen (Enumerations) Aufzählungstypen Für diese Werte-Mengen gibt es in einigen Programmiersprachen (wie gesagt, in Java seit Vers. 5.0) sog. Aufzählungstypen (Enumeration), die es erlauben, bei der Definition solcher Datentypen die Literale (Werte) explizit festzulegen (aufzuzählen). In Java ist dafür ein neues Schlüsselwort verfügbar: enum. Die einfachste Verwendung ist: enum Monat ( JANUAR, FEBRUAR, MAERZ, APRIL,... ) Dies macht einen neuen Typ Monat dem Compiler bekannt, den man nun als Typ für (lokale/globale) Variablen, Eingabeparameter von Methoden und Instanzvariablen (Attribute) verwenden kann. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 632 / 831

Aufzählungstypen (Enumerations) Aufzählungstypen Intern ist dieser Typ in Java als Klasse realisiert, d.h. die einzelnen Literale sind Objekte dieser Klasse. Nützliche Eigenschaften von Aufzählungstypen, die standardmäßig durch Java zur Verfügung gestellt werden: Methode tostring, die den Namen des Literals ausgibt. Beispiel: Monat.JANUAR.toString() ergibt "JANUAR". Methode equals prüft auf Gleichheit. Beispiel: JANUAR.equals(APRIL) ergibt false. Variablen von Aufzählungstypen können in switch-anweisungen verwendet werden (da es letztlich ints sind). Methode values mit der man die einzelnen Werte der Enumeration durchlaufen kann (mittels eines Iterator-Objekts).... Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 633 / 831

Aufzählungstypen (Enumerations) Aufzählungstypen Letztlich steckt dahinter nicht viel Neues, außer, dass die Objekte von der Klasse Monat alle intern eine ID besitzen, die aus der Werte-Menge stammt. Enumerations können in Java tatsächlich fast genauso wie Klassen um Attribute, Methoden und Konstruktoren ergänzt werden. Ein Blick in ein einschlägiges Lehrbuch zu diesem Thema lohnt sich alle mal. Zur Veranschaulichung, was man alles u.a. machen kann, noch ein Beispiel: Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 634 / 831

Aufzählungstypen (Enumerations) Aufzählungstypen: Beispiel public enum Farbe { /* ** Die Literal-Namen mit Initialisierung der Attribute durch den Konstruktor ** */ ROT(255, 0, 0), GRUEN(0, 255, 0), BLAU(0, 0, 255), GELB(255, 255, 0); /* ** Attribute, die die RGB-Werte speichern (Konstanten, da nicht veraenderbar) ** */ private final int r; private final int g; private final int b; /* ** Konstruktor (immer nicht-statisch)** */ public Farbe(int r, int g, int b) { this.r = r; this.g = g; this.b = b; } /* ** Methoden ** */ public int getrotanteil() { return this.r }... } Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 635 / 831

Überblick 8. Grundlagen der objektorientierten Programmierung 8.1 Abstrakte Datentypen I: Benutzereigene Strukturen 8.2 Abstrakte Datentypen II: von Structures zu Klassen 8.3 Das objektorientierte Paradigma 8.4 Klassen und Objekte in Java 8.5 Aufzählungstypen (Enumerations) 8.6 8.7 Ein ausführliches Beispiel Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 636 / 831

Blick hinter die Kulissen Im Folgenden wollen wir kurz die interne Speicherverwaltung von Java (genauer gesagt der JVM) betrachten. Wir bleiben hier aber informell und vereinfachend und betrachten die Zusammenhänge nur, soweit wir sie benötigen, um Phänomene zu verstehen, die uns auf der Ebene der Programmierung beschäftigen können. Wir werden feststellen, dass diese Aspekte leider tatsächlich einige Effekte haben, die wir bei bei der Programmentwicklung berücksichtigt müssen. Ein tieferes Verständnis der hier behandelten Zusammenhänge kann in anderen Vorlesungen erworben werden. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 637 / 831

Speicherumgebung Wir haben gesehen, dass Programme in einer imperativen Sprache wie Java durch Anweisungen charakterisiert sind, die Zustandsübergänge definieren. Zur Erinnerung: ein Zustand ist eine Menge von Paaren (intuitiv: Zetteln) (x, d), die Bindungen (Substitutionen) von Variablen (Bezeichnern) x an ein Literal/Element/Objekt d der Sorte von x spezifizieren (wobei die Zettel auch leer sein dürfen, in diesem Fall ist d = ω). Diese Menge von Bindungen (Zettel) muss von einer Speicherumgebung entsprechend verwaltet werden. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 638 / 831

Speicherumgebung Die Speicherumgebung von Java besteht wie erwähnt aus zwei Einheiten, dem Stack (Keller, Stapel) und dem Heap (Halde). Ein Stack kann Objekte gleicher Größe dynamisch verwalten. Ein Heap dagegen verwaltet Objekte sehr unterschiedlicher Größe dynamisch in einem gemeinsamen Speicherbereich (dynamic storage allocation). Die Speicherumgebung muss Zustandsübergänge (so wie wir sie in Kapitel 5 eingeführt haben) effizient durchführen. Dazu gehört das Anlegen neuer sowie das Ablesen und Verändern bestehender Variablen (Zettel), also Paaren (x, d). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 639 / 831

Speicherumgebung Bemerkung zur Terminologie: Der Stack modelliert die imperative Programmstrukturierung. Blöcke und ihre Schachtelung sind das wichtigste Strukturierungselement (Klassen, Methoden, Kontrollstrukturen etc. bilden stets einen Block). Ein Block führt Namensbindungen (Zettel) ein, die zusätzlich zu den Bindungen (Zetteln) außerhalb des Blocks gelten. Nach Verlassen des Blocks gelten wieder nur noch jene Bindungen, die bereits vor Betreten des Blockes galten. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 640 / 831

Speicherumgebung Bemerkung zur Terminologie: Der Stack erfüllt diese Anforderung: 1. Neue Bindungen werden oft eingefügt und existierende Bindungen werden oft wieder gelöscht. 2. Die Bindungen, die zuletzt hinzukamen, werden als erste wieder entfernt (Last-in-first-out, LIFO). Stack heißt ja nicht um sonst Stapel und am besten stapeln lassen sich gleichgroße Objekte (es gibt je einen Stapel für alle 1-Byte, 2-Byte, 4-Byte und 8-Byte Datentypen). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 641 / 831

Keller für alle Variablen Alle lokalen Variablen, d.h. Paare (Zettel) z =(x, d), eines Zustands S werden grundsätzlich im Keller verwaltet. Der Name einer Variablen x wird intern in eine Speicheradresse des Stacks übersetzt. An dieser Speicheradresse steht deren Inhalt d. Das war bisher unser abstraktes Bild der Zettel. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 642 / 831

Keller für alle Variablen Globalen Variablen sind (zunächst) in jedem Block sichtbar und sind daher in einem eigenen Bereich, auf den von anderen Bereichen zugegriffen werden kann, abgelegt (sog. Constant Pool). Lokale Variablen unterschiedlicher Methoden(/Blöcke) sind innerhalb des Kellers in Bereiche (sog. Frames) angeordnet. Ein Frame wird bei einem Methodenaufruf erzeugt und beinhaltet u.a. die lokalen Variablen einer Methode, die übergebenen (aktuellen) Parameter und den Rückgabewert der Methode (wenn er existiert). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 643 / 831

Keller vs. Halde Der Keller sieht für jeden Eintrag nur begrenzt viel Speicherplatz vor. Die Werte von primitiven Typen können direkt im Keller abgelegt werden (in der entsprechenden Speicherzelle). Objekte/Arrays sind i.d.r viel größer und teilweise ist deren Größe erst zur Laufzeit bei Erzeugung bekannt. Sie werden daher auf dem Heap gespeichert. Dazu steht im Keller in der Speicherzelle statt dem Wert (d.h. dem Objekt), die Speicheradresse des Objekts auf dem Heap. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 644 / 831

Keller vs. Halde Also: für alle lokalen Variablen (Zettel z =(x, d)) eines Zustands ist im Keller der Wert d in einer Speicherzelle, deren Adresse sich aus x ergibt, abgelegt. Abhängig vom Typ der Variablen x (des Zettels z) gilt: ist der Typ ein primitiver Typ, so ist d der tatsächliche Inhalt/Wert der Variablen, d.h. d repräsentiert das entspr. Literal (das Literal steht im Keller). handelt es sich um einen Referenz-Typ (Array, Objekttyp, damit auch String), so ist der tatsächliche Inhalt/Wert auf der Halde gespeichert und d repräsentiert lediglich die Referenz (Pointer) auf die entspr. Adresse auf der Halde (die Referenz (=Adresse) steht im Keller, nicht das Literal/Objekt). So hatten wir unser Zustandsmodell informell erweitert. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 645 / 831

Veranschaulichung: Keller vs. Halde char a = b ; String gruss1 = "Hi"; String gruss2 = "Hello"; String[] gruesse = {gruss1, gruss2}; int[] zahlen = {1, 2, 3}; boolean b = true; int i = 42; Stack: i = 42 b = true Heap: <adr1> : "Hi" <adr2> : "Hallo" <adr3> : { <adr1>, <adr2> } <adr4> : {1, 2, 3 } zahlen = <adr4> gruesse = <adr3> gruss2 = <adr2> gruss1 = <adr1> a = b Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 646 / 831

Der leere Zettel (revisited) Während primitive Typen lediglich deklariert werden, reicht dies bei Referenz-Typen nicht aus, sie müssen mit Hilfe des new-operators oder im Falle von Arrays und Strings durch Zuweisung von Literalen zusätzlich noch explizit erzeugt werden. Wenn eine Variable angelegt (vereinbart) aber nicht initialisiert wird hatten wir bei primitiven Typen die Intuition eines leeren Zettels/einer leeren Speicherzelle, d.h. es wird der leere Wert (ω) auf den Keller gelegt. Solange dies der Fall ist, kann man einer anderen Variablen nicht den Wert einer leeren Speicherzelle zuweisen. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 647 / 831

Der leere Zettel (revisited) Bei Referenztypen passiert im Prinzip das Gleiche: im Keller steht (noch) keine Speicheradresse, ein sog. null-pointer, der in Java durch die Zeichenkette null repräsentiert wird. Eine nicht intitialisierte Variable kann nach wie vor nicht zugewiesen werden, aber die leere Referenz null kann man schon zuweisen: Punkt p1 = null; Punkt p2 = p1; null wird daher oft auch als Literal bezeichnet (und kann als solches z.b. in Ausdrücken verwendet werden): if(a[0]!= null)... Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 648 / 831

Besonderheiten bei Referenztypen Das Verständnis für Referenztypen (Strings, Arrays, Objekte) ist entscheidend für die Programmierung in Java. Referenztypen können prinzipiell genauso benutzt werden wie primitive Typen, da sie jedoch lediglich eine Referenz darstellen, ist die Semantik einiger Operatoren anders als bei primitiven Typen!!! Ein Beispiel hatten wir schon kennengelernt: Array-Konstanten deren einzelne Array-Komponenten aber veränderbar sind. Drei weitere, sehr wichtige Beispiele, die wir im folgenden genauer betrachten: Gleichheit von Objekten Kopieren von Objekten Call-by-reference Effekt bei Methodenaufruf mit Referenztypen Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 649 / 831

Gleichheit von Objekten Gleichheit von Objekten bedeutet, dass sie den selben Zustand haben, also alle Attribute haben die selben Werte. Beispiel: Punkt p1 = new Punkt(1.0,1.0); Punkt p2 = new Punkt(1.0,1.0); boolean vergleich = (p1 == p2); Was ist der Wert der Variablen vergleich? Antwort: false! Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 650 / 831

Gleichheit von Objekten Warum? Sowohl das Objekt p1 als auch das Objekt p2 haben doch identische Attributwerte, also haben sie insgesamt denselben Zustand, oder nicht? Naja, was macht der Operator ==? Intuitiv: für zwei Zettel z 1 =(x 1, d 1 ) und z 2 =(x 2, d 2 ) wird getestet, ob d 1 = d 2 gilt. Da p1 und p2 aber unterschiedliche initialisierte Zettel sind, referenzieren sie unterschiedliche Speicherbereiche auf der Halde (die Objekte dort sind zwar tatsächlich gleich, die Speicheradressen aber nicht!!!) Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 651 / 831

Gleichheit von Objekten Es gibt tatsächlich zwei Arten von Gleichheit bei Referenz-Typen: Gleichheit: Der Zustand der entsprechenden Objekte beider Objektvariablen ist gleich, d.h. die Objekte auf der Halde sind identisch. Identität: Beide Objektvariablen verweisen auf die gleiche Speicheradresse, d.h. der Wert im Keller ist identisch. Der Operator == prüft offenbar den zweiten Fall (Identität). Er kann also i.a. nicht dazu benutzt werden, abzufragen, ob die Objekte zweier Objektvariablen gleich bzgl. ihres Zustands sind. Dies wird oft übersehen und ist daher eine häufige Fehlerquelle! Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 652 / 831

Gleichheit von Objekten Um die Gleichheit zweier Objekte zu testen muss der Programmierer der entsprechenden Klasse also eine entsprechende Methode bereitstellen. In Java ist vorgesehen, dass diese Methode die Signatur boolean equals(object obj) hat 19. Tatsächlich ist diese Methode bereits in der Klasse java.lang.object implementiert, allerdings setzt diese zunächst nur die Identität um, d.h. testet auf die Gleichheit der Referenzen. 19 Achtung: Argument ist tatsächlich vom Typ java.lang.objekt! Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 653 / 831

Gleichheit von Objekten Die java.lang.objekt ist implizit die Oberklasse aller Klassen und vererbt alle ihre Eigenschaften damit implizit auf alle anderen Klassen (siehe dazu auch Vererbung in einem der folgenden Kapitel). Wie erwähnt: diese Klasse kennt die Details einer speziellen Klasse nicht und kann deshalb nur die generische Form (Identität) implementieren. Um die gewünschte Eigenschaft (Gleichheit) in einer eigenen Klasse zu bekommen, muss der Programmierer die Methode equals entsprechend überschreiben (auch dazu später mehr!) Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 654 / 831

Gleichheit von Objekten Die Methode equals in der Klasse Object ist so spezifiziert, dass sie eine Äquivalenz-Relation auf nicht-null Objektreferenzen mit speziellen Eigenschaften implementiert, siehe dazu die Dokumentation unter: http://docs.oracle.com/javase/6/docs/api/java/lang/object.html Diese Vorschrift soll eingehalten werden, wenn man in einer Klasse die Methode equals überschreibt; das ist aber eine semantische Vorschrift, die nicht vom Compiler überprüft, sondern nur vom Programmierer bewiesen werden kann. In Object ist equals durch den Operator == implementiert. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 655 / 831

Gleichheit von Objekten Beispiel: Die Klasse String überschreibt equals so, dass für einen String s und ein Objekt o gilt: s.equals(o) ergibt true g.d.w.: o ist nicht null o ist vom Typ String und o repräsentiert genau die gleiche Zeichenkette wie s (d.h. s und o haben gleich Länge und an jeder Stelle steht der gleiche Character) Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 656 / 831

Gleichheit von Objekten Beispiel für die Klasse Punkt public boolean equals(object obj) { if (obj instanceof Punkt) { Punkt pt = (Punkt) obj; return (this.x == pt.x) && (this.y == pt.y); } else { return false; } Der instanceof-operator kann zur Laufzeit prüfen, ob ein von einem Verweis referenziertes Objekt zuweisungskompatibel zu einer Klasse ist. Man kann wie bei primitiven Typen auch bei Referenztypen einen expliziten Typcast durchführen (allerdings nur entlang einer Vererbungshierarchie). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 657 / 831

Kopieren von Objekten Eine Zuweisung mit einem Referenztyp erzeugt eine Kopie der Referenz (und kein neues Objekt), man spricht auch von Aliasing. Beispiel: Punkt p1 = new Punkt(1.0,1.0); Punkt p2 = p1; // (*) p1.verschiebe(2.0,2.0); p2.verschiebe(1.0,1.0); Nach der Zuweisung (*) verweisen beide Variablen p1 und p2 auf dasselbe Objekt. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 658 / 831

Kopieren von Objekten Warum? Auf dem Zettel (p 1, d 1 ), repräsentiert d 1 die Speicheradresse des Punktes p1 auf dem Heap. Die Vereinbarung/Zuweisung (*) erzeugt einen zweiten Zettel mit Namen p 2 auf dem der Wert von p 1 geschrieben wird, also (p 2, d 1 ), d.h. nur der Verweis wurde kopiert, aber nicht das Objekt selber. Diese Kopie wird auch flache Kopie (shallow copy) genannt. Problem: es ist nicht sichergestellt, dass die Kopie unabhängig vom ursprünglichen Objekt ist! Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 659 / 831

Kopieren von Objekten Auch hier gibt es einen vorgesehenen Workaround in der Klasse java.lang.object: Die Methode Object clone() erzeugt ein Objekt vom Typ Object als Kopie des aktuellen Objekts. In der ursprüngliche Fassung ist das allerdings wiederum die generellste Implementierung: eine flache Kopie. Die Methode clone() muss dazu entsprechend überschrieben werden. Dabei muss man darauf achten, dass die Objekte eines Attributs mit Objekttyp selbst wieder Attribute mit Objekttypen haben können!!! Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 660 / 831

Beispiel: Erstellen einer tiefen Kopie public class DeepCopy { private int zahl; private int[] zahlen; public DeepCopy(int zahl, int[] zahlen) { this.zahl = zahl; this.zahlen = zahlen; } } public Object clone() { int neuezahl = this.zahl; int[] neuezahlen = new int[this.zahlen.length]; for(int i=0; i<this.zahlen.length; i++) { neuezahlen[i] = this.zahlen[i]; } DeepCopy kopie = new DeepCopy(neueZahl, neuezahlen); return kopie; } Was ist hier nicht optimal gelöst? Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 661 / 831

Beispiel: Erstellen einer tiefen Kopie public class DeepCopy implements Cloneable { private int zahl; private int[] zahlen; public DeepCopy(int zahl, int[] zahlen) { this.zahl = zahl; System.arraycopy(zahlen, 0, this.zahlen, 0, zahlen.length); } } public Object clone() { DeepCopy kopie = new DeepCopy(this.zahl, this.zahlen); return kopie; } Den Zusatz implements Clonable in der ersten Zeile bitte zunächst ignorieren! Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 662 / 831

Call-by-reference Effekt Zur Erinnerung: Java übergibt Parameter bei Methodenaufrufen mit call-by-value. In folgendem Beispiel hatte daher der Aufruf von swap keinen Einfluss auf x und y in main. public class Exchange { public static void swap(int i, int j) { int c = i; i = j; j = c; } public static void main(string[] args) { int x = 1; int y = 2; swap(x,y); } } Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 663 / 831

Call-by-reference-Effekt Bei Objekttypen gibt es dagegen einen unerwarteten Effekt: 1 public static void changevalues(int[] zahlen, int index, int wert) 2 { 3 zahlen[index] = wert; 4 } main-frame nach Zeile 6 5 6 public static void main(string[] args) 7 { 8 int[] werte = {0, 1, 2}; 9 changevalues(werte, 1, 3); 10 } args = <adr1> Heap nach Zeile 6 <adr1> : { } Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 664 / 831

Call-by-reference-Effekt Bei Objekttypen gibt es dagegen einen unerwarteten Effekt: 1 public static void changevalues(int[] zahlen, int index, int wert) 2 { 3 zahlen[index] = wert; 4 } main-frame nach Zeile 8 5 6 public static void main(string[] args) 7 { 8 int[] werte = {0, 1, 2}; 9 changevalues(werte, 1, 3); 10 } werte = <adr2> args = <adr1> Heap nach Zeile 8 <adr1> : { } <adr2> :{0,1,2} Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 664 / 831

Call-by-reference-Effekt Bei Objekttypen gibt es dagegen einen unerwarteten Effekt: 1 public static void changevalues(int[] zahlen, int index, int wert) 2 { 3 zahlen[index] = wert; 4 } main-frame nach Zeile 8 5 6 public static void main(string[] args) 7 { 8 int[] werte = {0, 1, 2}; 9 changevalues(werte, 1, 3); 10 } Heap nach Zeile 8 <adr1> : { } <adr2> :{0,1,2} werte = <adr2> args = <adr1> changevalues-frame nach Zeile 1 wert = 3 index = 1 zahlen = <adr2> Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 664 / 831

Call-by-reference-Effekt Bei Objekttypen gibt es dagegen einen unerwarteten Effekt: 1 public static void changevalues(int[] zahlen, int index, int wert) 2 { 3 zahlen[index] = wert; 4 } main-frame nach Zeile 8 5 6 public static void main(string[] args) 7 { 8 int[] werte = {0, 1, 2}; 9 changevalues(werte, 1, 3); 10 } Heap nach Zeile 3 <adr1> : { } <adr2> :{0,3,2} werte = <adr2> args = <adr1> changevalues-frame nach Zeile 3 wert = 3 index = 1 zahlen = <adr2> Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 664 / 831

Call-by-reference-Effekt Bei Objekttypen gibt es dagegen einen unerwarteten Effekt: 1 public static void changevalues(int[] zahlen, int index, int wert) 2 { 3 zahlen[index] = wert; 4 } main-frame nach Zeile 9 5 6 public static void main(string[] args) 7 { 8 int[] werte = {0, 1, 2}; 9 changevalues(werte, 1, 3); 10 } werte = <adr2> args = <adr1> Heap nach Zeile 9 <adr1> : { } <adr2> :{0,3,2} Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 664 / 831

Call-by-reference Effekt Weiteres Beispiel: public class Seiteneffekte { public static void swap(int i, int j) { int c = i; i = j; j = c; } public static void main(string[] args) { int x = 1; int y = 2; swap(x,y); } } Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 665 / 831

Speicherfreigabe Anders als in C und C++, wo der *-Operator zur Dereferenzierung eines Zeigers nötig ist, erfolgt in Java der Zugriff auf Referenztypen in der gleichen Weise wie der auf primitive Typen. Einen expliziten Dereferenzierungsoperator gibt es in Java (i.ggs. zu C/C++) nicht (die Methode finalize in der Klasse Object ist mit Vorsicht zu genießen). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 666 / 831

Speicherfreigabe Anders als in C/C++ verfügt Java auch über ein automatisches Speichermanagement: Die Keller werden schon von ihrer Struktur her automatisch aufgeräumt, d.h. es gibt in Kellern keine Speicherplätze, die belegt sind, obwohl die Lebensdauer des entsprechenden Namens abgelaufen ist. Für die Halde gilt das nicht: Hier wird im Laufe eines Programmes Speicherplatz zugewiesen und belegt, aber nicht automatisch freigegeben, falls die Lebensdauer eines Namens, der für den gespeicherten Wert steht, abgelaufen ist. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 667 / 831

Garbage Collection In vielen Sprachen muss der Programmierer dafür sorgen, dass Speicherplatz, der nicht mehr gebraucht wird, freigegeben wird. Diese explizite Speicherplatzfreigabe birgt allerdings die Gefahr des Speicherlecks: Es könnte passieren, dass Speicherzellen freigegeben werden, die noch benötigt werden, d.h. Werte von Variablen stehen dann nicht mehr zur Verfügung (oder sind vielleicht sogar schon mit anderen Werten überschrieben). Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 668 / 831

Garbage Collection Speziell in modernen Sprachen (auch Java) gibt es dagegen eine automatische Speicherplatzfreigabe (Garbage Collection): Der Heap wird immer wieder durchsucht nach Adressen, auf die nicht mehr zugegriffen werden kann (da kein Name diese Adresse als Wert hat). Problem hier: der Programmierer kann nicht oder nur sehr eingeschränkt kontrollieren, wann dieser Reinigungsprozess läuft. Das ist unter Umständen (z.b. in sekundengenauen, empfindlichen Echtzeitsystemen) nicht akzeptabel. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/17 669 / 831