Skip to content

Commit 4d4e5e1

Browse files
committed
generics2: improve material, add further remarks
1 parent 992680a commit 4d4e5e1

1 file changed

Lines changed: 77 additions & 24 deletions

File tree

lecture/java-classic/generics2-bounds-wildcards.md

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ title: "Generics2: Bounds & Wildcards"
44
---
55

66
::: tldr
7-
Typ-Variablen können weiter eingeschränkt werden, in dem man einen verpflichtenden
8-
Ober- oder Untertyp angibt mit `extends` bzw. `super`. Damit muss der später bei der
9-
Instantiierung verwendete Typ-Parameter entweder die Oberklasse selbst sein oder
10-
davon ableiten (bei `extends`) bzw. der Typ-Parameter muss eine Oberklasse der
11-
angegebenen Schranke sein (`super`).
12-
13-
Durch die Einschränkung mit `extends` können in der Klasse/Methode auf der
14-
Typ-Variablen alle Methoden des angegebenen Obertyps verwendet werden.
15-
16-
Ein Wildcard (`?`) als Typ-Parameter steht für einen beliebigen Typ, wobei die
17-
Typ-Variable keinen Namen bekommt und damit innerhalb der Klasse/Methode nicht
18-
zugreifbar ist.
7+
Typ-Parameter können durch **Bounds** eingeschränkt werden: `<T extends ...>`
8+
bedeutet, dass der Typ-Parameter `T` nach oben eingeschränkt wird ("upper bound").
9+
Durch `extends`-Bounds kann in einer Klasse bzw. Methode der Typ-Parameter so
10+
eingeschränkt werden, dass alle Methoden des Obertyps verwendet werden können.
11+
12+
Ein **Wildcard** (`?`) steht für einen unbestimmten Typ. Ein Wildcard-Typ hat keinen
13+
Namen / ist nicht benennbar und ist innerhalb der Klasse/Methode nicht direkt
14+
zugreifbar. Wildcards können mit `? extends ...` nach oben ("upper bound") oder
15+
`? super ...` nach unten ("lower bound") eingeschränkt werden.
16+
17+
Bei `? extends Bound` muss der konkrete Typ die Schranke selbst oder ein Subtyp
18+
davon sein. Bei `? super Bound` muss der konkrete Typ ein Supertyp (Obertyp) der
19+
angegebenen Schranke sein.
1920
:::
2021

2122
::: youtube
@@ -40,20 +41,29 @@ Cps<String> c; // Fehler!!!
4041

4142
- Schlüsselwort `extends` gilt hier auch für Interfaces
4243

43-
- Mehrere Interfaces: nach `extends` Klasse oder Interface, danach mit "`&`"
44-
getrennt die restlichen Interfaces:
44+
- Mehrere Interfaces: nach `extends` **eine** Klasse oder **ein** Interface,
45+
danach mit "`&`" getrennt die restlichen Interfaces:
4546

4647
``` java
4748
class Cps<E extends KlasseOderInterface & I1 & I2 & I3> {}
4849
```
4950

50-
::: notes
51+
:::: notes
52+
Falls eine Klasse einem gemeinsamen Obertyp folgen soll, können mehrere Bound-Typen
53+
durch `&` verbunden werden. Der erste Bound kann eine Klasse (z.B. `Number`) sein;
54+
alle weiteren Bound-Typen müssen Interfaces sein. Wenn kein Klassen-Bound existiert,
55+
können alle Bound-Typen Interfaces sein.
56+
57+
::: tip
5158
*Anmerkung*: Der Typ-Parameter ist analog auch mit `super` (nach unten)
52-
einschränkbar
59+
einschränkbar. Das schauen wir uns im Zusammenhang mit Vererbungsbeziehungen und
60+
Polymorphie im dritten Teil ["Generics3: Generics und
61+
Polymorphie"](generics3-polymorphism.md) noch genauer an.
62+
:::
5363

5464
[Beispiel bounds.Cps]{.ex
5565
href="https://github.com/Programmiermethoden-CampusMinden/Prog2-Lecture/blob/master/lecture/java-classic/src/bounds/Cps.java"}
56-
:::
66+
::::
5767

5868
# Wildcards: Dieser Typ ist mir nicht so wichtig
5969

@@ -80,17 +90,58 @@ public class Wuppie {
8090
nutzbar ...
8191

8292
::: notes
93+
Die Wildcard `?` steht für einen unbekannten Typ. `List<?>` erlaubt `List`-Objekte
94+
jedes Typs, aber innerhalb der Methode kann man nicht sicher auf spezifische
95+
Eigenschaften des konkreten Typs zugreifen. `List<?>` ist also **nicht** eine "Liste
96+
von `Object`", sondern "Liste von unbekanntem Typ".
97+
98+
- Typvariable: "ich benenne den Typ und kann ihn mehrfach verwenden"
99+
- Wildcard: "ich akzeptiere etwas Unbekanntes, kann es aber nicht benennen"
100+
101+
Mit `List<? extends A>` erlaubt man Listen von Elementen, die `A` oder eine
102+
Unterklasse von `A` sind (*kovariant*, siehe auch Diskussion in ["Generics3:
103+
Generics und Polymorphie"](generics3-polymorphism.md)); man kann Elemente als `A`
104+
lesen/nutzen, aber nicht sicher als `A` hinzufügen (weil der echte Typ wg. des
105+
Wildcards unbekannt ist - es könnte ein beliebiger Untertyp von `A` sein).
106+
83107
Weitere Eigenschaften:
84108

85109
- Durch Wildcard kein Zugriff auf den Typ
86110
- Wildcard kann durch upper bound eingeschränkt werden
87-
- Geht nicht bei Klassen-/Interface-Definitionen
111+
- Geht nicht bei Klassen-/Interface-Definitionen, hier wird eine Typ-Variable
112+
benötigt
113+
114+
Weitere Beispiele:
115+
116+
- `List<?>` - Typ der Listenelemente unbekannt, nur Methoden von `Object` nutzbar
117+
- `List<? extends T>` - Typ der Listenelemente ist `T` oder eine Unterklasse von
118+
`T`; Zugriff lesend mit den Methoden von `T` (außer `null`), Schreiben nur
119+
eingeschränkt möglich (konkreter Typ unklar wg. `?` - es könnte eine Unterklasse
120+
von `T` sein, und Schreiben von Elementen vom Typ `T` würde (wenn es erlaubt
121+
wäre) dann zur Laufzeit schief gehen - Java fängt das aber zur Compilezeit ab)
122+
- `List<? super T>` - Typ der Listenelemente ist `T` oder eine Oberklasse von `T`;
123+
Zugriff schreibend möglich mit Werten vom Typ `T` und Untertypen, Lesen nur mit
124+
`Object` (der konkrete Typ samt Schnittstelle ist unklar: es könnte eine
125+
beliebige Oberklasse von `T` sein, die eine völlig unterschiedliche
126+
Schnittstelle als `T` hat)
127+
128+
=\> Das soll uns als erste Einführung von Bounds und Wildcards reichen. Wir werden
129+
überwiegend die `extends`-Bounds verwenden. Für eine genauere Diskussion von "Type
130+
Erasure" (TE) und "Producer extends, Consumer super" (PECS-Regel) sowie die
131+
Varianz-Diskussion siehe Lektion ["Generics3: Generics und
132+
Polymorphie"](generics3-polymorphism.md).
88133
:::
89134

90135
\bigskip
91136
\bigskip
92137

93-
@Bloch2018: Nur für Parameter und nicht für Rückgabewerte nutzen!
138+
@Bloch2018: Wildcards **meist** für Parameter; Rückgabewerte **möglichst** konkret
139+
typisieren.
140+
141+
::: notes
142+
Generische Typen in Rückgabewerten sollten möglichst konkrete Typen oder Bounds
143+
verwenden, um Typ-Sicherheit zu wahren.
144+
:::
94145

95146
# Hands-On: Ausgabe für generische Listen
96147

@@ -115,9 +166,11 @@ public class X {
115166
}
116167
```
117168

118-
[**Hinweis**: Dieses Beispiel beinhaltet auch Polymorphie bei/mit generischen
119-
Datentypen, bitte vorher auch das Video zum vierten Teil "Generics und Polymorphie"
120-
anschauen]{.notes}
169+
::: notes
170+
**Hinweis**: Dieses Beispiel berührt auch Polymorphie bei/mit generischen
171+
Datentypen, vgl. dritter Teil ["Generics und
172+
Polymorphie"](generics3-polymorphism.md) anschauen.
173+
:::
121174

122175
::: notes
123176
## Erster Versuch (*A* und *B* und *main()* wie oben)
@@ -130,7 +183,7 @@ public class X {
130183
}
131184
```
132185

133-
=\> **So gehts nicht!** Eine `List<B>` ist **keine** `List<A>` (auch wenn ein `B`
186+
=\> **So geht's nicht!** Eine `List<B>` ist **keine** `List<A>` (auch wenn ein `B`
134187
ein `A` ist, vgl. spätere Sitzung zu Generics und Vererbung ...)!
135188

136189
[Beispiel wildcards.v1.X]{.ex
@@ -168,7 +221,7 @@ public class X {
168221
Das ist die Lösung. Man erlaubt als Argument nur `List`-Objekte und fordert, dass
169222
sie mit `A` oder einer Unterklasse von `A` parametrisiert sind. D.h. in der Schleife
170223
kann man sich auf den gemeinsamen Obertyp `A` abstützen und hat dann auch wieder die
171-
`printInfo`-Methode zur Verfügung ...
224+
`printInfo`-Methode (von `A`) zur Verfügung ...
172225
:::
173226

174227
[Konsole wildcards.v3.X]{.ex

0 commit comments

Comments
 (0)