Teil II - auf Matthias

Werbung
Typverträglichkeit bei Feldern mit Klassentyp als Basistyp
zur Erinnerung:
short [] aShort={1,2,3};
int [] aInt;
//aInt = aSort; // Typfehler
Aber B Subtyp von A , dann B[] Subtyp von A[]
Problematisch:
Account[] a = new Account[10];
Checking[] c = new Checking [5];
a=c;
a[0]= c[0];
a[0] = new Account(4999);
bedeutet?
Exception in thread "main" java.lang.ArrayStoreException:
hs / fub - alp2-08 43
Sichtbarkeit, Verdecken und Ersetzen
Sichtbarkeit: definiert durch Modifikatoren und Vererbung
Sichtbarkeitsmodifikatoren (Klassen):
keiner
Klasse ist nur aus demselben package erreichbar.
public
Klasse ist von überall erreichbar.
final
Klasse ist final, d.h. kann nicht vererbt werden.
Es können keine Unterklassen abgeleitet werden.
(Eigentlich kein Sichtbarkeitsmodifikator:
public final überall sichtbar und nicht
erweiterbar)
hs / fub - alp2-08 44
Sichtbarkeitsmodifikatoren für Attribute und Methoden:
keiner
Variable ist nur innerhalb der eigenen Klasse und des
package erreichbar, zu dem sie gehört.
public
Variable ist überall dort erreichbar, wo auch die Klasse
erreichbar ist, zu der sie gehört.
private
Variable ist nur innerhalb der eigenen Klasse
erreichbar.
protected Variable ist nur innerhalb der eigenen Klasse und des
package erreichbar, zu dem sie gehört, ferner in
Unterklassen.
hs / fub - alp2-08 45
Sichtbarkeit verdeckender oder überschreibender Namen
darf nicht gegenüber den verdeckten / ersetzten
verringert werden.
Deshalb nur folgende Änderungen erlaubt:
protected
leer
→ public
→ public, protected
… aber
hs / fub - alp2-08 46
… eine gewisse Vorsicht ist angebracht:
class C1 {
private int foo() {return
int bar(){
return foo();
}
}
0;}
überschreibt private foo()
class D1 extends C1 {
int foo(){return 1;}
public static void main(String[] args) {
D1 c = new D1();
System.out.println(c.bar());
wird geerbt und bezieht
}
}
auf private foo(),
… und ohne private? s.u.
sich
was nicht direkt verwendet
werden darf!
hs / fub - alp2-08 47
Verdecken (hiding) und Ersetzen (Überschreiben, overriding)
Betrachten hier nur vertikale Kollision in der Vererbungshierarchie
• Attribute:
Verdecken wie in Blockstruktur (hiding)
(aber gleiche Namen/Typ erlaubt.)
• Methoden:
verschiedene Signatur:
gleiche Signatur,
beide statisch
gleiche Signatur
beide nichtstatisch
sonst
Überladen (overloading)
Verdecken
Ersetzen (overriding)
Fehler
(*) Implementieren von mehr als einer Schnittstelle kann auch zu Namenskollision führen.
hs / fub - alp2-08 48
Verdecken von Attributen (1)
class B extends A {
int bool=1;
...
}
class A {
boolean bool=true;
...
}
B b = new B();
A a = b;
a.bool=false;
System.out.println(a.bool + ((B)a).bool);
> false
> 1
b
bool: false
a
statischer Typ von a ist A,
dynamischer B
⇒ Statischer Typ bestimmt Attribut!
hs / fub - alp2-08 49
Verdecken von Attributen (2)
Auch statische Attribute werden verdeckt:
class C {
boolean bool=false;
static int i=10;
class D extends C {
static int bool; // hides boolean
boolean i; // hides static int i
static void op(){
System.out.println
("op() in C: i="+i);
//...
}}
static void op(){
// i=1; //can only use static
//members! but i is now dynamic
System.out.println("op() in D:
bool=:"+bool);
}}
D dd = new D();
C c = dd;
// c.bool= 1; error: static type of c.bool is boolean
c.bool = true;
dd.bool = 1;
((D)c).bool = 22;
c.i = 11;
hs / fub - alp2-08 50
Statischer Typ bestimmt Attribut!
d
D d = new D();
C c = d ;
// c.bool= 1; error
c.bool = true;
d .bool = 1;
((D)c).bool = 22;
c.i = 11;
d.i = true;
D e = new D();
c
bool
i
false
true
true
C
D static fields
10
11
i
bool
e
bool
221
false
i
hs / fub - alp2-08 51
Verdeckung statischer Methoden
… wie bei Attributen: der statische Typ bestimmt die
auszuführende Methode.
D dd = new D();
C c = dd;
c.op();
((D)c).op();
dd.op();
Ausgabe:
> op() in C: i= 11
> op() in D: bool=22
> op() in D: bool=22
class C {
boolean bool=false
int i=11;
static void op(){
System.out.println
("op() in C: i="+i);
…}
class D extends C {
static int bool = 22;
static void op(){
System.out.println
("op() in D:
bool="+bool);
}
hs / fub - alp2-08 52
Polymorphie: Methoden gemäß dynamischem Typ ausführen
Class Saving extends Account{
…
void compInterest(){
… //for saving accounts
}
Class Checking extends Account{
…
void compInterest(){
… //for checking accounts!
}
Account a = new Saving(..);
a.compInterest();
a = new Checking(..);
a.compInterest();
Zur Laufzeit (dynamisch) wird die Methode gewählt, die das
Objekt besitzt, auf die a verweist, nicht die durch den
statischen Typ (hier Account) von a bestimmte.
hs / fub - alp2-08 53
Po·ly·mor'phie, die; -, keine Mehrzahl
1.Vielgestaltigkeit, Verschiedengestaltigkeit 2. […]
(*)
Diese Art der Polymorphie ist nur im Zusammenhang mit
Vererbung definiert.
- Vererbung von Klassen,
- Vererbung von Schnittstellen,
- Implementierung von Schnittstellen durch Klassen.
-Sammelbegriff: Inklusions- (Einschluss-) Polymorphie
(inclusion polymorphism)
Andere Arten von Polymorphie??
(*) Langenscheidt Fremdwörterbuch (digitale Ausgabe)
hs / fub - alp2-08 54
Polymorphie in Java
Zugriffsregel:
• für nichtstatische Methoden ist der Typ des Objekts
entscheidend
• für Attribute und statische Methoden der Typ des
der Verweisvariablen (bzw. Parameter)
Grund dafür:
Effizienter Attributzugriff
- schon beim Übersetzen steht die
Speicheradresse fest
- Adressen der Methoden werden sowieso
Nicht in allen
dynamisch ermittelt
OO Sprachen so.
Regeln können explizit umgangen werden
Regeln beachten!
z,B, durch Typanpassung.
hs / fub - alp2-08 55
Dynamischer Methodenaufruf
c
Rechteck
a
Felder
a,b,..
b
Felder
a,b,..
flaeche()
static
farbe()
...
f
2DGeoO
Referenzen
Objekte (nur Werte!)
Klasse
d
Felder
r,..
e
Genaugenommen: KlassenDeskriptoren, die die Adressen
der Methoden enthalten
Das ist die Kreisfläche!
also: völlig anderer Code
g
Kreis
Code für diese
flaeche()
Felder
r,..
flaeche()
farbe()
...
Code
farbe()
Code für jene
flaeche()
Zur Übersetzungszeit ist nicht bekannt, ob f bzw. g auf ein Rechteck oder einen Kreis
zeigen. Stattdessen wird g.flaeche() so ausgeführt:
(1) Klassendeskriptor lesen (2) dort Adresse a von „richtiger flaeche()“ finden
hs / fub - alp2-08 56
Generizität (*)
Unterschied zu Inklusionspolymorphie?
Vergleiche Generizität in Haskell!
Generizität = parametrische Polymorphie
Typparameter ermöglichen das Schreiben von Programmen
ohne auf einen Typ oder die Vererbungsbeziehung von Typen
festgelegt zu sein.
Vor Ausführung des Programms: Typparameter durch
konkreten Typ ersetzen.
(*) hier nur extrem knapp behandelt. Details ALP3 bzw. Literatur
hs / fub - alp2-08 57
Zwei Beispiele:
a) Für Algorithmus ist der konkrete Typ belanglos
append :: [a]-> [a] -> [a]
append [] xListe = xListe
append (y:yListe) xListe = x:(append yListe xListe)
b) Konkrete Typen müssen zueinander passen, welche
das sind spielt keine Rolle.
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xList) = (f y): map f xList
Objektorientierte Sprachen?
hs / fub - alp2-08 58
Generizität
.. gibt es in Eiffel, C++ ("Template-Mechanismus"),
C# (seit .NET 2.0) und Java (seit 1.5)
Generische verkettete Listen in Java:
public class LListGeneric <G>{
private ListNodeGen <G> head, tail, current;
private ListNodeGen <G> sentinel = new ListNodeGen<G>(null);
…
public void add(G o){
// insert at front
head = new ListNodeGen <G>(o,sentinel.next);
sentinel.next=head;
size++;
typarametrisierte Methode
} … }
hs / fub - alp2-08 59
Verwendung von generischen Listen
map (2*) [1..10]
Typparameter a, b durch integer
ersetzen.
Java:
public static void main(String[] args) {
LListGeneric<Integer> ll;
int maxElem = 17;
ll= new LListGeneric<Integer>();
for (int i=1;i<=maxElem;i++)
ll.add(new Integer(i));
}
hs / fub - alp2-08 60
Problematisch…
… ist die Interferenz mit Vererbung.
Zum Beispiel:
Aus B verträglich mit A folgt nicht List<B> verträglich
mit List<A>
List<A> a =
List<B> b =
a.head = new
a.head = new
new List<A>();
new List<B>();
A();
B(); // vgl. Felder
Komplexität des Typsystems erhöht sich deutlich.
hs / fub - alp2-08 61
Übersicht Polymorphie
Polymorphie
Überladen
ad hoc
Typwandlung
(coercion)
Universelle Polymorphie
Generizität
Inklusionspolymorphie
hs / fub - alp2-08 62
Ergänzung (*)
Innere Klassen
Manchmal nützlich, Klassen Inside nicht auf dem "Toplevel"
zu definieren, sondern innerhalb einer anderen Klasse Outside.
1. statische innere Klassen
class A{
static class B{...
}
}
Kein Problem:
B ist Attribut von A
mit Zugriff auf alle
statischen Eigenschaften
von A
(aber nicht die dynamischen)
(*) in der Literatur nachlesen
hs / fub - alp2-08 63
2. Elementklassen
class A{
class B{...
}
B b = new B();
}
A a = new A();
B b = a.new B();
B ist Attribut von A
das erzeugt werden muss und
Zugriff auf die nichtstatischen
Eigenschaften von A hat.
Von "außen" kann ein B-Objekt
nur erzeugt werden, wenn ein
zugehöriges A-Objekt a existiert.
hs / fub - alp2-08 64
2. Lokale und anonyme innere Klassen
class A{
public static void main( String args[] )
{ Point p = new Point( 10, 12 )
{ public String toString()
{ return "(" + x + "," + y + ")"; }
};
System.out.println( p ); // (10,12)
} }
Hier wird ein einziges Objekt erzeugt, das über p
verwendet werden kann.
new A {<anonyme Klasse>}: anonyme ist Unterklasse von class A
- im Beispiel: {…} überschreibt toString() –
Wenn interface A (Schnittstelle), wird sie von {...} implementiert.
Variante: benannte lokale Klasse: {..class B{...}new B;
hs / fub - alp2-08 65
}
Herunterladen