• Keine Ergebnisse gefunden

Info B VL 4: Konstruktoren und Vererbung

N/A
N/A
Protected

Academic year: 2021

Aktie "Info B VL 4: Konstruktoren und Vererbung"

Copied!
30
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Info B VL 4: Konstruktoren und Vererbung

Objektorientiere Programmierung in Java 2003

Ute Schmid (Vorlesung) Elmar Ludwig ( ¨ Ubung)

FB Mathematik/Informatik, Universit¨at Osnabr¨uck

(2)

Konstruktoren

Spezielle Funktion zur Erzeugung von Objekten Ursprünglich: in funktionaler Programmierung und Typtheorie als Symbol zur Erzeugung eines

algebraischen Datentyps Beispiel in ML:

datatype ’a list = nil | :: of ’a * ’a list

Ausdrücke, die nur Konstruktoren enthalten sind in Normalform (werden nicht weiter

ausgewertet/reduziert)

Funktionen über algebraischen DTs können pattern matching 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

(3)

Konstruktoren in OO-Sprachen

mit C++ eingeführt

Konstruktor wird von einer Klasse zur Verfügung gestellt und dient der Initialisierung eines Objekts

da neue Objekte meist über Konstruktoraufruf erzeugt werden kann Initialisierung nicht vergessen werden

In C++ und Java: Konstruktornamen gleich Klassennamen

In C++: Destrukturen als Gegenstück (Freigabe von Ressourcen)

In Java kaum notwendig wegen Garbage Collector

(4)

Konstruktor-Definition

Konstruktoren haben keinen Rückgabetyp (auch nicht void )

Wird für eine Klasse kein Konstruktor definiert, so wird ein Default Konstruktor (auch “no-arg constructor”)

angelegt

Der Default Konstruktor hat keine Argumente

Alle Konstruktoren haben implizit eine Referenz zum neu erzeugten Objekt ( this ) als Argument

Im Konstruktor-Körper werden die Initialisierungen des this -Objekts vorgenommen.

Beispiel: Initialisierung eines Circle -Objekts

public Circle(double r) { this.r = r; } ...

Circle c = new Circle(2.0);

Info B VL 4: Konstruktoren und Vererbung – p.86

(5)

Definition mehrerer Konstruktoren

Möglichkeit, Objekt auf verschiedene Art zu initialisieren

public Circle() { r = 1.0; }

public Circle(double r) { this.r = r; }

Wie bei Methoden gilt overloading: gleicher Name aber unterschiedliche Signaturen (Anzahl und Typ der

Argumente)

Ein Konstruktor kann andere Konstruktoren aufrufen:

this() als Konstruktoraufruf; welcher Konstruktor aktiviert wird, hängt wieder von Anzahl und Typ der Argumente ab.

Verwendung von this() ist gute Strategie, wenn die Konstruktoren Teile der Initialisierung gemeinsam

haben

this() darf nur als erste Anweisung in einem

Konstruktor vorkommen Info B VL 4: Konstruktoren und Vererbung – p.87

(6)

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

(7)

Default Werte

Lokale Variablen (innerhalb von Methoden definiert) haben keine Default-Werte

Werden lokale Variablen nicht vor ihrer Verwendung initialisiert, liefert der Java-Compiler eine

Fehlermeldlung!

(Klassen- und Instanz-) Felder sind automatisch mit Default-Werten initialisiert

Übliche Deklaration mit Zuweisung eines initialen Wertes ist ebenfalls möglich

public static final double PI = 3.14159;

public double r = 1.0;

(8)

Default Werte für Felder

Typ Default

boolean false

char ‘ u0000’

byte , short , int , long 0 float , double 0.0

reference null

Info B VL 4: Konstruktoren und Vererbung – p.90

(9)

Initialisierung von Instanz-Feldern

Konstruktoren

Java Compiler erzeugt Initialisierungscode für

Instanz-Felder und fügt sie in Konstruktor(en) ein

Reihenfolge: die im Programm angegebene (Nutzung von bereits initialisierten Feldern bei der Initialisierung weiterer Felder möglich)

Wenn ein Konstruktor mit this() Anweisung beginnt, dann wird in diesen Konstruktor die Initialisierung nicht eingefügt, sondern in denjenigen Konstruktor, der

durch 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ügt

werden können; üblich: direkt nach Feld; benutzt vor

allem für anonyme innere Klassen

(10)

Beispiel

public 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 zu

public 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

(11)

Initialisierung von Klassen-Feldern (1)

Statische Initialisierungs-Bl ¨ocke

Klassen-Felder existieren auch wenn kein Objekt erzeugt wird

Initialisierung vor Konstruktoraufruf notwendig

Java Compiler erzeugt

Klassen-Initialisierungs-Methode (interne, versteckte Methode clinit

), in der alle Klassen-Felder

initialisiert werden.

Diese Methode wird genau einmal ausgewertet, nämlich wenn die Klasse das erstemal benutzt (geladen) wird.

Initialisierung wieder in der im Programm

angegebenen Reihenfolge

(12)

Init. von Klassen-Feldern (2)

Explizite Initialisierung von Klassen-Feldern mit static initializer Block: static ...

, der an jeder Stelle der Klasse stehen kann, wo Komponenten stehen können

Es kann mehrere solche Initialisierungs-Blöcke geben Initialisierungs-Blöcke werden vom Compiler in die

Klassen-Initialisierungs-Methode integriert

Statische Initialisierung ist wie eine Klassen-Methode, also keine Verwendung von this möglich, keine

Nutzung von Instanz-Komponenten möglich

Info B VL 4: Konstruktoren und Vererbung – p.94

(13)

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);

} } }

(14)

Garbage Collection (1)

Mit new werden neue Objekte erzeugt (heap)

Wenn ein Objekt nicht länger benutzt wird, wird der Speicherplatz automatisch freigegeben (garbage collection)

Der Java Interpreter weiss, welche Objekte und Arrays er angelegt (allocated) hat, und kann ermitteln, welche Objekte und lokale Variablen auf andere Objekte

verweisen.

Wenn kein Verweis auf ein Objekt existiert, kann es zerstört werden; dito für nicht mehr referenzierte Verweis-Zyklen

Info B VL 4: Konstruktoren und Vererbung – p.96

(15)

Garbage Collection (2)

Garbage Collector läuft immer im Hintergrund als low priority thread; wird im Normalfall immer aktiv, wenn nichts Wichtiges passiert (z.B. beim Warten auf Input), ausser: wenn kaum noch freier Speicher vorhanden ist Garbage Collection kann nie so effizient sein wie gute selbstgeschriebene Speicherverwaltung ( free() ,

delete ); aber es verhindert Fehler (z.B. memory

leaks) und erlaubt schnellere Entwicklung von Code.

(16)

Finalization

Freigabe von bestimmten Resourcen, die ein Objekt benutzt, wird nicht vom Garbage Collector erledigt (z.B. temporäre Dateien löschen)

Finalizer ist Instanz-Methode, Gegenstück zu

Konstruktor (“Destruktor”); wird vom Garbage Collector aufgerufen; keine Argumente, kein Rückgabewert

Es darf nur einen Finalizer pro Klasse geben.

protected void finalize()

Selbstgeschriebene Klassen benötigen selten explizite Finalizer (Ausnahme native finalize für

Schnittstellen zu Code, der nicht unter Kontrolle des Garbage Collectors ist)

Info B VL 4: Konstruktoren und Vererbung – p.98

(17)

Exkurs: Semantische Netze

Bird

has wings can fly

has feathers

Fish

has fins can swim has gills Animal

has skin

can move around eats

breathes

Ostrich

has thin long legs is tall

Canary

is yellow can sing

Shark

can bite

is dangerous

Salmon

is pink is edible swims upriver

to lay eggs

can’t fly

(18)

Kognitive Ökonomie

Objekte sind hierarchisch organisiert

Eigenschaften werden nur einmal gespeichert und vererbt

Psychologische Experimente: Antwortzeiten (Collins &

Quillian)

Prolog: flache, logische Repräsentation, Vererbung via expliziert Transitivitätsregel

“natürlicher”: OO-Sprache, Ober-/Unterklassen werden nur je einmal angegeben

Info B VL 4: Konstruktoren und Vererbung – p.100

(19)

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, ... */

(20)

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

(21)

Erweiterung von ‘Circle’

Beispielcode: PlaneCircle.java

+ isInside PlaneCircle cy

cx Circle PI r

+ radiansToDegrees + area

+ circumference

(22)

Erweiterung einer Klasse

Funktionale Erweiterung von Klassen durch

Unterklassenbildung ist zentral für objekt-orientierte Programmierung

class Name

extends SName

{ ... }

Felder und Methoden der Oberklasse werden automatisch vererbt, Konstruktoren nicht!

Unterklassen-Konstruktor kann Konstruktor der Oberklasse durch super() aufrufen (analog zu this() )

Weitere Felder und Methoden können für die Unterklasse definiert werden.

Info B VL 4: Konstruktoren und Vererbung – p.104

(23)

Typkonversion

Typkonversion zwischen Unter- und Oberklassen:

von Unterklasse zu Oberklasse (upcasting), Objekt wird allgemeiner (verliert Zugriff auf spezielle Felder und Methoden) ohne Casting;

von Oberklasse zu Unterklasse (downcasting): Casting notwendig (und Prüfung zur Laufzeit durch die VM)

(vergleiche widening und narrowing bei primitiven Datentypen)

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);

(24)

Kapslung

Wichtige objekt-orientierte Technik: Information-Hiding, Encapsulation:

Daten nur über Methoden zugänglich machen

Daten und interne (private) Methoden sind sicher in der Klasse eingeschlossen und können nur von

vertrauenswürdigen Nutzern (also über ordentlich definierte öffentliche Methoden der Klasse) benutzt werden.

Schutz der Klasse gegen absichtliche oder unabsichtliche Eingriffe

Verstecken interner Implementations-Details. Ändern der Implementation, ohne dass genutzter Code dieser Klasse betroffen ist.

Übersichtlichkeit durch kleine Menge öffentlicher Information

Info B VL 4: Konstruktoren und Vererbung – p.106

(25)

Zugriffskontrolle

Paket-Zugriff: Nicht Teil von Java selbst (Lesbarkeit von Dateien, Verzeichnissen)

Klassen-Zugriff: Default ist, dass top-level Klassen

paket-weit zugreifbar sind. public deklarierte Klassen sind überall (wo das Paket zugreifbar ist) zugreifbar.

Zugriff auf Komponenten einer Klasse: Komponenten sind in jedem Fall in der Klasse selbst zugreifbar;

Default: paket-weiter Zugriff;

Alle Klassen, die zum selben Paket gehören, dürfen zugreifen. Bei unbenanntem Paket typischerweise alle Klassen im selben Verzeichnis

(implementationsabhängig).

Zugriffsmodifikatoren: public , protected , private

für Felder und Methoden.

(26)

Zugriffsmodifikatoren

Für Klassen-Komponenten:

public : von überall (wo Paket zugreifbar ist) zugreifbar

protected : paket-weit und aus allen Unterklassen (egal, in welchem Paket sie definiert sind) zugreifbar default: paket-weit zugreifbar (wenn kein Modifikator angegeben)

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

(27)

Zugriff und Vererbung

Unterklasse erbt alle Instanz-Felder und -Methoden der Oberklasse. Manche Komponenten sind aufgrund der Einschränkung der Sichtbarkeit nicht zugreifbar.

Wenn Ober- und Unterklasse im selben Paket: Zugriff auf alle nicht-privaten Felder und Methoden.

Wenn Ober- und Unterklasse in verschiedenen Paketen: Zugriff auf alle public und protected Felder und Methoden.

private Komponenten und Konstruktoren können nie ausserhalb der Klasse zugegriffen werden.

Subtile Probleme: wie verhält sich protected , wenn Klasse A und Unterklasse B in verschiedenen Paketen stehen und Klasse B in Klasse A genutzt wird? Wie

spielen Casting und Zugriffsmodifikatoren zusammen?

(28)

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 das Feld r von der Unterklasse PlaneCircle geerbt wird.

Aber: Zugriff auf c.r ist in PlaneCircle nicht erlaubt!

Wäre erlaubt, wenn PlaneCircle c anstelle von

Circle c , oder wenn Circle und PlaneCircle im selben Paket definiert wären

Info B VL 4: Konstruktoren und Vererbung – p.110

(29)

Daumenregeln

Benutze public nur für Methoden und Konstanten, die den öffentlichen Teil des API der Klasse darstellen sollen.

Kapsle Felder: als privat deklarieren und Zugriff über public Methoden

Benutze protected für Komponenten, die bei der

Erzeugung von Unterklassen notwendig sein könnten.

Achtung: Änderung von protected Komponenten kann im Code der Klasse Inkonsistenzen erzeugen.

Benutze default Sichtbarkeit für Komponenten, die

interne Implementation realisieren und von Klassen im selben Paket genutzt werden sollen.

Nutzung der package Anweisung, um miteinander kooperierende 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

(30)

Zugrifffsmethoden

Beispielprogramm: myshapes.Circle

Klasse ist einem Paket zugeordnet (Verzeichnisname gleich dem Paketnamen).

Methoden sind um Fehlerprüfung erweitert (explizite checkXX() Methoden).

Zugriff auf Werte von Instanz-Feldern erfolgt über Methoden ( setXX() , getXX() ).

Felder, auf die mit set- und get-Methoden zugegriffen wird, werden auch Properties genannt. Man spricht von “Getter”- und “Setter”-Methoden.

Info B VL 4: Konstruktoren und Vererbung – p.112

Referenzen

ÄHNLICHE DOKUMENTE

ˆ Der Konstruktor muss daf¨ ur sorgen, dass beim Erzeugen eines Objekts der Klasse TSteckerfolge auch die vier enthaltenen Stecker erzeugt werden:.

Eine Kopie des Circle Objekts in der Java VM, aber zwei Kopien der Referenz auf dieses Objekt.. Info B VL 3: Klassen und ihre Komponenten

Die Behandlung kann in der Methode, in der der Fehler aufgetreten ist, selbst oder in einer der diese Methode aufrufenden Methoden?.

Schreiben in eine Datei und Lesen aus einer Datei kann mit FileWriter und FileReader erledigt werden. Die Angabe von Dateien kann über File -Objekte oder

Problem: Ein Produzent kann produzierte Daten eines anderen Produzenten überschreiben, bevor der. Konsument die Daten

 Wird eine Methode überschrieben, ist die Methode der Superklasse in einer Instanz der Subklasse nicht mehr sichtbar und es wird die „neue“ Version Instanz der Subklasse nicht

Schreiben Sie ein Programm ausgehend von , dass 3 Konstruktoren zur Verfügung stellt; den Konstruktor ohne Argumente, mit einer Variablen soll nur die Energie übergeben

Schreiben Sie ein Programm ausgehend von , dass 3 Konstruktoren zur Verfügung stellt; den Konstruktor ohne Argumente, mit einer Variablen soll nur die Energie übergeben