Info B VL 4: Konstruktoren undVererbung
Objektorientiere Programmierung in Java2003
Ute Schmid (Vorlesung)
Elmar Ludwig (Übung)
FB Mathematik/Informatik, Universität Osnabrück
Info B VL 4: Konstruktoren und Vererbung – p.83
Konstruktoren
Spezielle Funktion zur Erzeugung von Objekten
Ursprünglich: in funktionaler Programmierung undTyptheorie als Symbol zur Erzeugung einesalgebraischen Datentyps
Beispiel in ML:
datatype ’a list = nil | :: of ’a * ’a list
Ausdrücke, die nur Konstruktoren enthalten sind inNormalform (werden nicht weiterausgewertet/reduziert)
Funktionen über algebraischen DTs können patternmatching verwenden:
fun f(nil) = nil
| f(x::l) = if even(x) then f(l) else x::f(l);
Info B VL 4: Konstruktoren und Vererbung – p.84
Konstruktoren in OO-Sprachen
mit C++ eingeführt
Konstruktor wird von einer Klasse zur Verfügunggestellt und dient der Initialisierung eines Objekts
� � da neue Objekte meist über Konstruktoraufruferzeugt werden kann Initialisierung nicht vergessenwerden
In C++ und Java: Konstruktornamen gleichKlassennamen
In C++: Destrukturen als Gegenstück (Freigabe vonRessourcen)In Java kaum notwendig wegen Garbage Collector
Info B VL 4: Konstruktoren und Vererbung – p.85
Konstruktor-Definition
Konstruktoren haben keinen Rückgabetyp (auch nichtvoid)
Wird für eine Klasse kein Konstruktor definiert, so wirdein Default Konstruktor (auch “no-arg constructor”)angelegt
Der Default Konstruktor hat keine Argumente
Alle Konstruktoren haben implizit eine Referenz zumneu erzeugten Objekt (this) als Argument
Im Konstruktor-Körper werden die Initialisierungen desthis-Objekts vorgenommen.
Beispiel: Initialisierung eines Circle-Objektspublic Circle(double r) { this.r = r; }
...
Circle c = new Circle(2.0);Info B VL 4: Konstruktoren und Vererbung – p.86
Definition mehrerer KonstruktorenMöglichkeit, Objekt auf verschiedene Art zuinitialisierenpublic Circle() { r = 1.0; }
public Circle(double r) { this.r = r; }
Wie bei Methoden gilt overloading: gleicher Name aberunterschiedliche Signaturen (Anzahl und Typ derArgumente)
Ein Konstruktor kann andere Konstruktoren aufrufen:this() als Konstruktoraufruf; welcher Konstruktoraktiviert wird, hängt wieder von Anzahl und Typ derArgumente ab.
Verwendung von this() ist gute Strategie, wenn dieKonstruktoren Teile der Initialisierung gemeinsamhaben
this() darf nur als erste Anweisung in einemKonstruktor vorkommen Info B VL 4: Konstruktoren und Vererbung – p.87
Beispiel ‘Circle’
// This is the basic constructor:
// initialize the radius
public Circle(double r) { this.r = r; }
// This constructor uses this() to invoke
// the constructor above
public Circle() { this(1.0); }
Info B VL 4: Konstruktoren und Vererbung – p.88
Default Werte
Lokale Variablen (innerhalb von Methoden definiert)haben keine Default-Werte
Werden lokale Variablen nicht vor ihrer Verwendunginitialisiert, liefert der Java-Compiler eineFehlermeldlung!
(Klassen- und Instanz-) Felder sind automatisch mitDefault-Werten initialisiert
Übliche Deklaration mit Zuweisung eines initialenWertes ist ebenfalls möglich
public static final double PI = 3.14159;
public double r = 1.0;
Info B VL 4: Konstruktoren und Vererbung – p.89
Default Werte für Felder
Typ Defaultboolean false
char ‘
�
u0000’
byte, short, int, long 0float, double 0.0reference null
Info B VL 4: Konstruktoren und Vererbung – p.90
Initialisierung von Instanz-FeldernKonstruktoren
Java Compiler erzeugt Initialisierungscode fürInstanz-Felder und fügt sie in Konstruktor(en) ein
Reihenfolge: die im Programm angegebene (Nutzungvon bereits initialisierten Feldern bei der Initialisierungweiterer Felder möglich)
Wenn ein Konstruktor mit this() Anweisung beginnt,dann wird in diesen Konstruktor die Initialisierung nichteingefügt, sondern in denjenigen Konstruktor, derdurch this() aktiviert wird
ab Java 1.1: Initialisierungsblöcke für Instanz-Felder:
�
...
�
, die an beliebiger Stelle (an der
Komponenten stehen können) in die Klasse eingefügtwerden können; üblich: direkt nach Feld; benutzt vorallem für anonyme innere Klassen
Info B VL 4: Konstruktoren und Vererbung – p.91
Beispielpublic class TestClass {
public int len = 10;
public int[] table = new int[len];
public TestClass(){
for (int i = 0; i < len; i++) table[i] = i;
} }
Ist äquivalent zupublic class TestClass {
public int len;
public int[] table;
public TestClass() {
len = 10;
table = new int[len];
for (int i = 0; i < len; i++) table[i] = i;
} } Info B VL 4: Konstruktoren und Vererbung – p.92
Initialisierung von Klassen-Feldern (1)
Statische Initialisierungs-Blöcke
Klassen-Felder existieren auch wenn kein Objekterzeugt wird
Initialisierung vor Konstruktoraufruf notwendig
� � Java Compiler erzeugtKlassen-Initialisierungs-Methode (interne, versteckteMethode �clinit � ), in der alle Klassen-Felderinitialisiert werden.Diese Methode wird genau einmal ausgewertet,nämlich wenn die Klasse das erstemal benutzt(geladen) wird.
Initialisierung wieder in der im Programmangegebenen Reihenfolge
Info B VL 4: Konstruktoren und Vererbung – p.93
Init. von Klassen-Feldern (2)
Explizite Initialisierung von Klassen-Feldern mit staticinitializer Block: static
�
...
�
, der an jeder
Stelle der Klasse stehen kann, wo Komponentenstehen können
Es kann mehrere solche Initialisierungs-Blöcke geben
Initialisierungs-Blöcke werden vom Compiler in dieKlassen-Initialisierungs-Methode integriert
Statische Initialisierung ist wie eine Klassen-Methode,also keine Verwendung von this möglich, keineNutzung von Instanz-Komponenten möglich
Info B VL 4: Konstruktoren und Vererbung – p.94
Beispiel
// We can draw the outline of a circle using trigonometric functions
// Trigonometry is slow, though, so we precompute a bunch of values
public class TrigCircle {
// Here are our static lookup tables and their own simple initializers
private static final int NUMPTS = 500;
private static double sines[] = new double[NUMPTS];
private static double cosines[] = new double[NUMPTS];
// Here’s a static initializer that fills in the arrays
static {
double x = 0.0;
double delta_x = (Circle.PI/2)/(NUMPTS-1);
for (int i = 0; i < NUMPTS; i++, x += delta_x) {
sines[i] = Math.sin(x);
cosines[i] = Math.cos(x);
} } }
Info B VL 4: Konstruktoren und Vererbung – p.95
Garbage Collection (1)
Mit new werden neue Objekte erzeugt (heap)
Wenn ein Objekt nicht länger benutzt wird, wird derSpeicherplatz automatisch freigegeben (garbagecollection)
Der Java Interpreter weiss, welche Objekte und Arrayser angelegt (allocated) hat, und kann ermitteln, welcheObjekte und lokale Variablen auf andere Objekteverweisen.
Wenn kein Verweis auf ein Objekt existiert, kann eszerstört werden; dito für nicht mehr referenzierteVerweis-Zyklen
Info B VL 4: Konstruktoren und Vererbung – p.96
Garbage Collection (2)
Garbage Collector läuft immer im Hintergrund als lowpriority thread; wird im Normalfall immer aktiv, wennnichts Wichtiges passiert (z.B. beim Warten auf Input),ausser: wenn kaum noch freier Speicher vorhanden ist
Garbage Collection kann nie so effizient sein wie guteselbstgeschriebene Speicherverwaltung (free(),delete); aber es verhindert Fehler (z.B. memoryleaks) und erlaubt schnellere Entwicklung von Code.
Info B VL 4: Konstruktoren und Vererbung – p.97
Finalization
Freigabe von bestimmten Resourcen, die ein Objektbenutzt, wird nicht vom Garbage Collector erledigt(z.B. temporäre Dateien löschen)
Finalizer ist Instanz-Methode, Gegenstück zuKonstruktor (“Destruktor”); wird vom Garbage Collectoraufgerufen; keine Argumente, kein Rückgabewert
Es darf nur einen Finalizer pro Klasse geben.
protected void finalize()
Selbstgeschriebene Klassen benötigen selten expliziteFinalizer (Ausnahme native finalize fürSchnittstellen zu Code, der nicht unter Kontrolle desGarbage Collectors ist)
Info B VL 4: Konstruktoren und Vererbung – p.98
Exkurs: Semantische Netze
Birdhas wingscan flyhas feathers
Fishhas finscan swimhas gills
Animal
has skincan move aroundeatsbreathes
Ostrichhas thin long legsis tallCanary
is yellow
can singShark
can bite
is dangerousSalmon
is pinkis edible
swims upriverto lay eggs
can’t fly
Info B VL 4: Konstruktoren und Vererbung – p.99
Kognitive Ökonomie
Objekte sind hierarchisch organisiert
Eigenschaften werden nur einmal gespeichert undvererbt
Psychologische Experimente: Antwortzeiten (Collins &Quillian)
Prolog: flache, logische Repräsentation, Vererbung viaexpliziert Transitivitätsregel
“natürlicher”: OO-Sprache, Ober-/Unterklassen werdennur je einmal angegeben
Info B VL 4: Konstruktoren und Vererbung – p.100
Prolog
/* Fakten */
isa(canary, bird).
isa(ostrich, bird).
isa(bird, animal).
isa(shark, fish).
isa(salmon, fish).
isa(fish, animal).
has(skin, animal).
does(eat, animal).
...
/* Inferenzregeln */
is_a(A,B) :- isa(A,B). /* direkter Fall */
is_a(A,C) :- isa(A,B), is_a(B,C). /* Transitivitaet */
/* analog fuer has, does, ... */
Info B VL 4: Konstruktoren und Vererbung – p.101
Java
class Animal {
boolean hasSkin = true;
boolean canEat = true;
}
class Bird extends Animal {
boolean hasWings = true;
boolean canFly = true; // default,
// gilt nicht fuer alle Voegel
}
class Ostrich extends Bird {
Ostrich() { canFly = false; }
}
Info B VL 4: Konstruktoren und Vererbung – p.102
Erweiterung von ‘Circle’
Beispielcode: PlaneCircle.java
+ isInside
PlaneCircle
cycx
Circle
PIr
+ radiansToDegrees+ area+ circumference
Info B VL 4: Konstruktoren und Vererbung – p.103
Erweiterung einer Klasse
Funktionale Erweiterung von Klassen durchUnterklassenbildung ist zentral für objekt-orientierteProgrammierung
class � Name � extends � SName � { ... }
Felder und Methoden der Oberklasse werdenautomatisch vererbt, Konstruktoren nicht!
Unterklassen-Konstruktor kann Konstruktor derOberklasse durch super() aufrufen (analog zuthis())
Weitere Felder und Methoden können für dieUnterklasse definiert werden.
Info B VL 4: Konstruktoren und Vererbung – p.104
Typkonversion
Typkonversion zwischen Unter- und Oberklassen:von Unterklasse zu Oberklasse (upcasting), Objektwird allgemeiner (verliert Zugriff auf spezielle Felderund Methoden) ohne Casting;von Oberklasse zu Unterklasse (downcasting): Castingnotwendig (und Prüfung zur Laufzeit durch die VM)(vergleiche widening und narrowing bei primitivenDatentypen)
PlaneCircle pc = new PlaneCircle(2.0, 5.0, 5.0);
double ratio = pc.circumference() / pc.area();
Circle c = pc; // no access to positioning
PlaneCircle pc2 = (PlaneCircle) c;
boolean oins = ((PlaneCircle) c).isInside(0.0, 0.0);
Info B VL 4: Konstruktoren und Vererbung – p.105
KapslungWichtige objekt-orientierte Technik: Information-Hiding,Encapsulation:
Daten nur über Methoden zugänglich machenDaten und interne (private) Methoden sind sicher inder Klasse eingeschlossen und können nur vonvertrauenswürdigen Nutzern (also über ordentlichdefinierte öffentliche Methoden der Klasse) benutztwerden.
Schutz der Klasse gegen absichtliche oderunabsichtliche Eingriffe
Verstecken interner Implementations-Details. Ändernder Implementation, ohne dass genutzter Code dieserKlasse betroffen ist.
Übersichtlichkeit durch kleine Menge öffentlicherInformation
Info B VL 4: Konstruktoren und Vererbung – p.106
ZugriffskontrollePaket-Zugriff: Nicht Teil von Java selbst (Lesbarkeitvon Dateien, Verzeichnissen)
Klassen-Zugriff: Default ist, dass top-level Klassenpaket-weit zugreifbar sind. public deklarierte Klassensind überall (wo das Paket zugreifbar ist) zugreifbar.
Zugriff auf Komponenten einer Klasse: Komponentensind in jedem Fall in der Klasse selbst zugreifbar;Default: paket-weiter Zugriff;Alle Klassen, die zum selben Paket gehören, dürfenzugreifen. Bei unbenanntem Paket typischerweise alleKlassen im selben Verzeichnis(implementationsabhängig).
Zugriffsmodifikatoren: public, protected, privatefür Felder und Methoden.
Info B VL 4: Konstruktoren und Vererbung – p.107
Zugriffsmodifikatoren
Für Klassen-Komponenten:
public: von überall (wo Paket zugreifbar ist)zugreifbarprotected: paket-weit und aus allen Unterklassen(egal, in welchem Paket sie definiert sind) zugreifbardefault: paket-weit zugreifbar (wenn kein Modifikatorangegeben)private: nur in der Klasse selbst zugreifbar
Accessible to public protected ‘package’ private
Defining class yes yes yes yes
Class in same package yes yes yes no
Subclass in different package yes yes no no
Non-subclass in different package yes no no no
Info B VL 4: Konstruktoren und Vererbung – p.108
Zugriff und Vererbung
Unterklasse erbt alle Instanz-Felder und -Methodender Oberklasse. Manche Komponenten sind aufgrundder Einschränkung der Sichtbarkeit nicht zugreifbar.
Wenn Ober- und Unterklasse im selben Paket: Zugriffauf alle nicht-privaten Felder und Methoden.
Wenn Ober- und Unterklasse in verschiedenenPaketen: Zugriff auf alle public und protectedFelder und Methoden.
private Komponenten und Konstruktoren können nieausserhalb der Klasse zugegriffen werden.
Subtile Probleme: wie verhält sich protected, wennKlasse A und Unterklasse B in verschiedenen Paketenstehen und Klasse B in Klasse A genutzt wird? Wiespielen Casting und Zugriffsmodifikatoren zusammen?
Info B VL 4: Konstruktoren und Vererbung – p.109
Beispiel
Circle mit protected r.PlaneCircle (ist Unterklasse) in anderem Paket.Methode in PlaneCircle:public boolean isBigger (Circle c) {
return (this.r > c.r);
}
Compiler-Fehler: Zugriff auf this.r ist erlaubt, da dasFeld r von der Unterklasse PlaneCircle geerbt wird.Aber: Zugriff auf c.r ist in PlaneCircle nicht erlaubt!
Wäre erlaubt, wenn PlaneCircle c anstelle vonCircle c, oder wenn Circle und PlaneCircle imselben Paket definiert wären
Info B VL 4: Konstruktoren und Vererbung – p.110
DaumenregelnBenutze public nur für Methoden und Konstanten,die den öffentlichen Teil des API der Klasse darstellensollen.Kapsle Felder: als privat deklarieren und Zugriff überpublic Methoden
Benutze protected für Komponenten, die bei derErzeugung von Unterklassen notwendig sein könnten.Achtung: Änderung von protected Komponentenkann im Code der Klasse Inkonsistenzen erzeugen.
Benutze default Sichtbarkeit für Komponenten, dieinterne Implementation realisieren und von Klassen imselben Paket genutzt werden sollen.Nutzung der package Anweisung, um miteinanderkooperierende Klassen in ein Paket zu bündeln.
Sonst benutze private.
Besser zunächst möglichst restriktive Rechte vergeben und
erst wenn nötig lockern.
Info B VL 4: Konstruktoren und Vererbung – p.111
Zugrifffsmethoden
Beispielprogramm: myshapes.Circle
Klasse ist einem Paket zugeordnet (Verzeichnisnamegleich dem Paketnamen).
Methoden sind um Fehlerprüfung erweitert (explizitecheckXX() Methoden).
Zugriff auf Werte von Instanz-Feldern erfolgt überMethoden (setXX(), getXX()).Felder, auf die mit set- und get-Methoden zugegriffenwird, werden auch Properties genannt. Man sprichtvon “Getter”- und “Setter”-Methoden.
Info B VL 4: Konstruktoren und Vererbung – p.112
KonstruktorenKonstruktoren in OO-SprachenKonstruktor-DefinitionDefinition mehrerer KonstruktorenBeispiel `Circle'Default WerteDefault Werte für FelderInitialisierung von Instanz-FeldernBeispielInitialisierung von Klassen-Feldern (1)Init. von Klassen-Feldern (2)BeispielGarbage Collection (1)Garbage Collection (2)FinalizationExkurs: Semantische NetzeKognitive ÖkonomiePrologJavaErweiterung von `Circle'Erweiterung einer KlasseTypkonversionKapslungZugriffskontrolleZugriffsmodifikatorenZugriff und VererbungBeispielDaumenregelnZugrifffsmethoden