1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
|
<html>
<head>
<title>
Handbuch der Java-Programmierung, 5. Auflage
</title>
</head>
<body>
<a name="startofbody"></a>
<script language="JavaScript" src="hjp4lib.js">
</script>
<script language="JavaScript">
installKbdHandler("97,#startofbody;101,#endofbody;116,cover.html;122,k100003.html;115,search.html;105,index.html;100,JDKDOCS;112,APIDOCS;104,k100046.html;106,k100046.html;107,k100048.html;108,k100051.html");
</script>
<table border=0 cellpadding=0 cellspacing=1 width="100%">
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html"> Titel </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html"> Inhalt </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html"> Suchen </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html"> Index </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()"> DOC </a>
<td align="right">Handbuch der Java-Programmierung, 5. Auflage
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100046.html"> << </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100046.html"> < </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100048.html"> > </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100051.html"> >> </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()"> API </a>
<td align="right">Kapitel 7 - OOP I: Grundlagen
</table>
<hr>
<!-- Section -->
<a name="sectlevel2id007001"></a>
<h2>7.1 Konzepte objektorientierter Programmiersprachen </h2>
<hr>
<ul>
<li><a href="k100047.html#sectlevel2id007001">7.1 Konzepte objektorientierter Programmiersprachen</a>
<ul>
<li><a href="k100047.html#sectlevel3id007001001">7.1.1 Einführung</a>
<li><a href="k100047.html#sectlevel3id007001002">7.1.2 Abstraktion</a>
<li><a href="k100047.html#kapselung">7.1.3 Kapselung</a>
<li><a href="k100047.html#sectlevel3id007001004">7.1.4 Wiederverwendung</a>
<li><a href="k100047.html#sectlevel3id007001005">7.1.5 Beziehungen</a>
<ul>
<li><a href="k100047.html#sectlevel4id007001005001">Generalisierung und Spezialisierung</a>
<li><a href="k100047.html#sectlevel4id007001005002">Aggregation und Komposition</a>
<li><a href="k100047.html#sectlevel4id007001005003">Verwendungs- und Aufrufbeziehungen</a>
</ul>
<li><a href="k100047.html#polymorphismus">7.1.6 Polymorphismus</a>
<li><a href="k100047.html#sectlevel3id007001007">7.1.7 Fazit</a>
</ul>
</ul>
<hr>
<!-- Section -->
<a name="sectlevel3id007001001"></a>
<h3>7.1.1 Einführung </h3>
<p>
<a name="ixa100437">Objektorientierte Programmierung</a> (kurz <a name="ixa100438"><i>OOP</i></a>)
ist <i>das</i> Programmierparadigma der 90er Jahre. Viele der heute
verwendeten Programmiersprachen sind entweder von Grund auf objektorientiert
(Java, Eiffel, SmallTalk) oder wurden im Laufe der Zeit mit objektorientierten
Erweiterungen versehen (Basic, Pascal, ADA). Selbst manche Scriptsprachen
erlauben den Zugriff auf (mitunter vordefinierte) Objekte oder besitzen
objektorientierte Eigenschaften (JavaScript, Python). Die objektorientierte
Programmierung war eine der »Silver Bullets«, die die Software-Industrie
aus ihrer Krise führen und zu robusteren, fehlerärmeren
und besser wartbaren Programmen führen sollte.
<p>
Was sind nun die Geheimnisse der objektorientierten Programmierung?
Was verbirgt sich hinter dem Begriff, und welches sind seine wichtigsten
Konzepte? Wir wollen uns zunächst mit den Grundideen objektorientierter
Programmierung auseinandersetzen und dann in diesem und den nächsten
Kapiteln Schritt für Schritt erläutern, wie sie in Java
umgesetzt wurden.
<!-- Section -->
<a name="sectlevel3id007001002"></a>
<h3>7.1.2 Abstraktion </h3>
<p>
Eine der wichtigsten Ideen der objektorientierten Programmierung ist
die Trennung zwischen <i>Konzept</i> und <i>Umsetzung</i>, etwa zwischen
einem <i>Bauteil</i> und seinem <i>Bauplan</i>, einer <i>Speise</i>
und dem für die Zubereitung erforderlichen <i>Rezept</i> oder
einem <i>technischen Handbuch</i> und der <i>konkreten Apparatur</i>,
die dadurch beschrieben wird. Diese Art von Unterscheidung ist in
der wirklichen Welt sehr bedeutsam. Wer weiß, wie man <i>einen
einzigen</i> Lichtschalter bedient, kann andere, gleichartige Schalter
ebenfalls bedienen. Wer ein Rezept für eine Sachertorte besitzt,
ist in der Lage, diese zu backen, selbst wenn er ansonsten über
keine Koch- oder Backkünste verfügt. Wer einen Führerschein
gemacht hat, kann ein Auto fahren, ohne im Detail über das komplizierte
Innenleben desselben unterrichtet zu sein.
<p>
In der objektorientierten Programmierung manifestiert sich diese Unterscheidung
in den Begriffen <i>Objekt</i> und <i>Klasse</i>. Ein Objekt ist ein
tatsächlich existierendes »Ding« aus der Anwendungswelt
des Programms. Es spielt dabei keine Rolle, ob es sich um die programmierte
Umsetzung eines konkret existierenden Gegenstandes handelt, oder ob
»nur« ein abstraktes Konzept modelliert wird. Eine »Klasse«
ist dagegen die Beschreibung eines oder mehrerer ähnlicher Objekte.
»Ähnlich« bedeutet dabei, dass eine Klasse nur Objekte
eines bestimmten Typs beschreibt. Diese müssen sich zwar nicht
in allen Details gleichen, aber doch in so vielen von ihnen übereinstimmen,
dass eine gemeinsame Beschreibung angebracht ist. Eine Klasse beschreibt
mindestens drei wichtige Dinge:
<ul>
<li>Wie ist das Objekt zu bedienen?
<li>Welche Eigenschaften hat das Objekt und wie verhält es sich?
<li>Wie wird das Objekt hergestellt?
</ul>
<p>
Ähnlich wie ein Rezept zur Herstellung von Hunderten von Sachertorten
verwendet werden kann, ermöglicht eine Klasse das Erzeugen einer
prinzipiell beliebigen Anzahl von Objekten. Jedes hat dabei seine
eigene Identität und mag sich in gewissen Details von allen anderen
unterscheiden. Letzlich ist das Objekt aber immer eine <i>Instanz</i>
der Klasse, nach der es modelliert wurde. In einem Haus kann es beispielsweise
fünfzig Lichtschalter-Objekte geben. Sie alle sind Instanzen
der Klasse »Lichtschalter«, lassen sich in vergleichbarer
Weise bedienen und sind identisch konstruiert. Dennoch unterscheiden
wir sehr wohl zwischen dem Lichschalter-Objekt, das die Flurbeleuchtung
bedient, und jenem, das den Keller erhellt. Und beide widerum unterscheiden
sich eindeutig von allen anderen Lichschalterinstanzen im Haus.
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
Es ist übrigens kein Zufall, dass wir die Begriffe »Instanz«
und »Objekt« synonym verwenden. In der objektorientierten
Programmierung ist das sehr verbreitet (auch wenn Puristen zwischen
beiden Begriffen noch Unterschiede sehen), und wir wollen uns diesem
Wortgebrauch anschließen.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
<tr>
<td><font color="#FFFFFF"> Hinweis </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
</tr>
</table>
<p>
Diese Unterscheidung zwischen Objekten und Klassen kann als <a name="ixa100439"><i>Abstraktion</i></a>
angesehen werden. Sie bildet die erste wichtige Eigenschaft objektorientierter
Sprachen. Abstraktion hilft, Details zu ignorieren, und reduziert
damit die Komplexität des Problems. Die Fähigkeit zur Abstraktion
ist eine der wichtigsten Voraussetzungen zur Beherrschung komplexer
Apparate und Techniken und kann in seiner Bedeutung nicht hoch genug
eingeschätzt werden.
<!-- Section -->
<a name="kapselung"></a>
<h3>7.1.3 Kapselung </h3>
<p>
In objektorientierten Programmiersprachen wird eine Klasse durch die
Zusammenfassung einer Menge von Daten und darauf operierender Funktionen
(die nun <a name="ixa100440"><i>Methoden</i></a> genannt werden) definiert.
Die Daten werden durch einen Satz Variablen repräsentiert, der
für jedes instanziierte Objekt neu angelegt wird (diese werden
als <a name="ixa100441"><i>Attribute</i></a>, <a name="ixa100442"><i>Membervariablen</i></a>,
<a name="ixa100443"><i>Instanzvariablen</i></a> oder <a name="ixa100444"><i>Instanzmerkmale</i></a>
bezeichnet). Die Methoden sind im ausführbaren Programmcode nur
einmal vorhanden, operieren aber bei jedem Aufruf auf den Daten eines
ganz bestimmten Objekts (das Laufzeitsystem übergibt bei jedem
Aufruf einer Methode einen Verweis auf den Satz Instanzvariablen,
mit dem die Methode gerade arbeiten soll).
<p>
Die Instanzvariablen repräsentieren den <i>Zustand</i> eines
Objekts. Sie können bei jeder Instanz einer Klasse unterschiedlich
sein und sich während seiner Lebensdauer verändern. Die
Methoden repräsentieren das <i>Verhalten</i> des Objekts. Sie
sind - von gewollten Ausnahmen abgesehen, bei denen Variablen bewußt
von außen zugänglich gemacht werden - die einzige Möglichkeit,
mit dem Objekt zu kommunizieren und so Informationen über seinen
Zustand zu gewinnen oder diesen zu verändern. Das Verhalten der
Objekte einer Klasse wird in seinen Methodendefinitionen festgelegt
und ist von dem darin enthaltenen Programmcode und dem aktuellen Zustand
des Objekts abhängig.
<p>
Diese Zusammenfassung von Methoden und Variablen zu Klassen bezeichnet
man als <a name="ixa100445"><i>Kapselung</i></a>. Sie stellt die zweite
wichtige Eigenschaft objektorientierter Programmiersprachen dar. Kapselung
hilft vor allem, die Komplexität der Bedienung eines Objekts
zu reduzieren. Um eine Lampe anzuschalten, muss man nicht viel über
den inneren Aufbau des Lichtschalters wissen. Sie vermindert aber
auch die Komplexität der Implementierung, denn undefinierte Interaktionen
mit anderen Bestandteilen des Programms werden verhindert oder reduziert.
<!-- Section -->
<a name="sectlevel3id007001004"></a>
<h3>7.1.4 Wiederverwendung </h3>
<p>
Durch die Abstraktion und Kapselung wird die <a name="ixa100446"><i>Wiederverwendung</i></a>
von Programmelementen gefördert, die dritte wichtige Eigenschaft
objektorientierter Programmiersprachen. Ein einfaches Beispiel dafür
sind <i>Collections</i>, also Objekte, die Sammlungen anderer Objekte
aufnehmen und auf eine bestimmte Art und Weise verarbeiten können.
Collections sind oft sehr kompliziert aufgebaut (typischerweise zur
Geschwindigkeitssteigerung oder Reduzierung des Speicherbedarfs),
besitzen aber in aller Regel eine einfache Schnittstelle. Werden sie
als Klasse implementiert und werden durch die Kapselung der Code-
und Datenstrukturen die komplexen Details »wegabstrahiert«,
können sie sehr einfach wiederverwendet werden. Immer, wenn im
Programm eine entsprechende Collection benötigt wird, muss lediglich
ein Objekt der passenden Klasse instanziert werden, und das Programm
kann über die einfach zu bedienende Schnittstelle darauf zugreifen.
Wiederverwendung ist ein wichtiger Schlüssel zur Erhöhung
der Effizienz und Fehlerfreiheit beim Programmieren.
<!-- Section -->
<a name="sectlevel3id007001005"></a>
<h3>7.1.5 Beziehungen </h3>
<p>
Objekte und Klassen existieren für gewöhnlich nicht völlig
alleine, sondern stehen in Beziehungen zueinander. So ähnelt
ein Fahrrad beispielsweise einem Motorrad, hat aber auch mit einem
Auto Gemeinsamkeiten. Ein Auto ähnelt dagegen einem Lastwagen.
Dieser kann einen Anhänger haben, auf dem ein Motorrad steht.
Ein Fährschiff ist ebenfalls ein Transportmittel und kann viele
Autos oder Lastwagen aufnehmen, genauso wie ein langer Güterzug.
Dieser wird von einer Lokomotive gezogen. Ein Lastwagen kann auch
einen Anhänger ziehen, muss es aber nicht. Bei einem Fährschiff
ist keine Zugmaschine erforderlich, und es kann nicht nur Transportmittel
befördern, sondern auch Menschen, Tiere oder Lebensmittel.
<p>
Wir wollen ein wenig Licht in diese Beziehungen bringen und zeigen,
wie sie sich in objektorientierten Programmiersprachen auf wenige
Grundtypen reduzieren lassen:
<ul>
<li>»is-a«-Beziehungen (Generalisierung, Spezialisierung)
<li>»part-of«-Beziehungen (Aggregation, Komposition)
<li>Verwendungs- oder Aufrufbeziehungen
</ul>
<!-- Section -->
<a name="sectlevel4id007001005001"></a>
<h4>Generalisierung und Spezialisierung </h4>
<p>
Zuerst wollen wir die »is-a«-Beziehung betrachten. »is-a«
bedeutet »ist ein« und meint die Beziehung zwischen »ähnlichen«
Klassen. Ein Fahrrad ist kein Motorrad, aber beide sind Zweiräder.
Ein Zweirad, und damit sowohl das Fahrrad als auch das Motorrad, ist
ein Straßenfahrzeug, ebenso wie das Auto und der Lastwagen.
All diese Klassen repräsentieren Transportmittel, zu denen aber
auch die Schiffe und Güterzüge zählen.
<p>
Die »is-a«-Beziehung zwischen zwei Klassen <i>A</i> und
<i>B</i> sagt aus, dass »<i>B</i> ein <i>A</i> ist«, also
alle Eigenschaften von <i>A</i> besitzt, und vermutlich noch ein paar
mehr. <i>B</i> ist demnach eine Spezialisierung von <i>A</i>. Andersherum
betrachtet, ist <i>A</i> eine Generalisierung (Verallgemeinerung)
von <i>B</i>.
<p>
»is-a«-Beziehungen werden in objektorientierten Programmiersprachen
durch <a name="ixa100447"><i>Vererbung</i></a> ausgedrückt. Eine
Klasse wird dabei nicht komplett neu definiert, sondern von einer
anderen Klasse <i>abgeleitet</i>. In diesem Fall erbt sie alle Eigenschaften
dieser Klasse und kann nach Belieben eigene hinzufügen. In unserem
Fall wäre also <i>B</i> von <i>A</i> abgeleitet. <i>A</i> wird
als <a name="ixa100448"><i>Basisklasse</i></a> (manchmal auch als
<a name="ixa100449"><i>Vaterklasse</i></a>), <i>B</i> als <a name="ixa100450"><i>abgeleitete
Klasse</i></a> bezeichnet.
<p>
Vererbungen können mehrstufig sein, d.h. eine abgeleitete Klasse
kann Basisklasse für weitere Klassen sein. Auf diese Weise können
vielstufige <i>Vererbungshierarchien</i> entstehen, die in natürlicher
Weise die Taxonomie (also die gegliederte Begriffsstruktur) der zu
modellierenden Anwendungswelt repräsentieren. Vererbungshierarchien
werden wegen ihrer Baumstruktur auch als <a name="ixa100451"><i>Ableitungsbäume</i></a>
bezeichnet. Sie werden meist durch Graphen dargestellt, in denen die
abgeleiteten Klassen durch Pfeile mit den Basisklassen verbunden sind
und die Basisklassen oberhalb der abgeleiteten Klassen stehen. Für
unsere Fahrzeugwelt ergäbe sich beispielsweise folgender Ableitungsbaum:
<p>
<a name="transportmittel"></a>
<img src="images/VererbTransp.gif">
<p>
<p><i>
Abbildung 7.1: Vererbungshierarchie für Transportmittel</i></p>
<p>
Als Eigenschaften der Basisklasse <i>Transportmittel</i> könnten
etwa dessen Anschaffungskosten, seine Lebensdauer oder die Transportgeschwindigkeit
angesehen werden. Sie gelten für alle abgeleiteten Klassen. In
der zweiten Ableitungsebene unterscheiden wir nach der Art der Fortbewegung
(wir hätten allerdings ebensogut nach der Farbe, dem Verwendungszweck
oder einem beliebigen anderen Merkmal unterscheiden können).
In der Klasse <i>Wasserfahrzeug</i> könnten nun Eigenschaften
wie Verdrängung, Hochseetauglichkeit und erforderliche Besatzung
festgehalten werden. Das Fährschiff schließlich fügt
seine Transportkapazitäten für Autos, Lastwagen und Personen
hinzu, gibt die Anzahl der Kabinen der unterschiedlichen Kategorien
an und definiert, ob es im RORO-Verfahren be- und entladen werden
kann oder nicht.
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
In manchen objektorientierten Programmiersprachen kann eine abgeleitete
Klasse mehr als eine Basisklasse besitzen (z.B. in C++ oder Eiffel).
In diesem Fall spricht man von <a name="ixa100452"><i>Mehrfachvererbung</i></a>.
Die Vererbungshierarchie ist dann nicht mehr zwangsläufig ein
Baum, sondern muss zu einem gerichteten Graph verallgemeinert werden.
In Java gibt es allerdings keine Mehrfachvererbung, und wir wollen
daher nicht weiter auf die Besonderheiten dieser Technik eingehen.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
<tr>
<td><font color="#FFFFFF"> Hinweis </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
</tr>
</table>
<!-- Section -->
<a name="sectlevel4id007001005002"></a>
<h4>Aggregation und Komposition </h4>
<p>
Der zweite Beziehungstyp, die »part-of«-Beziehungen, beschreibt
die <i>Zusammensetzung</i> eines Objekts aus anderen Objekten (dies
wird auch als <a name="ixa100453"><i>Komposition</i></a> bezeichnet).
So besteht beispielsweise der Güterzug aus einer (oder manchmal
zwei) Lokomotiven und einer großen Anzahl Güterzuganhänger.
Der Lastwagen besteht aus der LKW-Zugmaschine und eventuell einem
Anhänger. Ein Fahrrad besteht aus vielen Einzelteilen. Objektorientierte
Sprachen implementieren »part-of«-Beziehungen durch Instanzvariablen,
die Objekte aufnehmen können. Der Güterzug könnte also
eine (oder zwei) Instanzvariablen vom Typ <i>Lokomotive</i> und ein
Array von Instanzvariablen vom Typ <i>Güterzuganhänger</i>
besitzen.
<p>
»part-of«-Beziehungen müssen nicht zwangsläufig
beschreiben, <i>woraus</i> ein Objekt zusammengesetzt ist. Vielmehr
können sie auch den allgemeineren Fall des <i>einfachen Aufnehmens</i>
anderer Objekte beschreiben (was auch als <a name="ixa100454"><i>Aggregation</i></a>
bezeichnet wird). Zwischen dem Motorrad, das auf dem Lastwagenanhänger
steht, oder den Straßenfahrzeugen, die auf einem Fährschiff
untergebracht sind, besteht zwar eine »part-of«-Beziehung,
sie ist aber nicht <i>essentiell</i> für die Existenz des aufnehmenden
Objekts. Der Anhänger existiert auch wenn kein Motorrad darauf
platziert ist. Und das Fährschiff kann auch leer von Kiel nach
Oslo fahren.
<p>
Während bei der objektorientierten Modellierung sorgsam zwischen
beiden Fällen unterschieden wird (Komposition bezeichnet die
strenge Form der Aggregation auf Grund einer existentiellen Abhängigkeit),
behandeln objektorientierte Programmiersprachen sie prinzipiell gleich.
In beiden Fällen gibt es Instanzvariablen, die Objekte aufnehmen
können. Ist ein optionales Objekt nicht vorhanden, wird dies
durch die Zuweisung eines speziellen <a name="ixa100455"><i>null-Objekts</i></a>
ausgedrückt. Für die semantischen Eigenschaften der Beziehung
ist die Klasse selbst verantwortlich.
<!-- Section -->
<a name="sectlevel4id007001005003"></a>
<h4>Verwendungs- und Aufrufbeziehungen </h4>
<p>
Die dritte Art von Beziehungen zwischen Objekten oder Klassen hat
den allgemeinsten Charakter. Benutzt beispielsweise eine Methode während
ihrer Ausführung ein temporäres Objekt, so besteht zwischen
beiden eine Verwendungsbeziehung: Objekt <i>x</i> verwendet eine Instanz
der Klasse <i>Y</i>, um bestimmte Operationen auszuführen. Taucht
in der Argumentliste einer Methode eine Objektvariable der Klasse
<i>T</i> auf, so entsteht eine ähnliche Beziehung zu <i>T</i>.
Zwar ist dies keine »part-of«-Beziehung, und auch die Ableitungsbeziehung
zwischen beiden Klassen spielt keine Rolle. Wenigstens muss aber die
Methode die Argumentklasse kennen und in der Lage sein, Methoden darauf
aufzurufen oder das Objekt an Dritte weiterzugeben.
<p>
Allgemeine Verwendungs- oder Aufrufbeziehungen finden in objektorientierten
Programmiersprachen ihren Niederschlag darin, dass Objekte als lokale
Variablen oder Methodenargumente verwendet werden. Sie werden auch
mit dem Begriff <a name="ixa100456"><i>Assoziationen</i></a> bezeichnet.
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
In den vorangegangenen Abschnitten wurden mehrfach die Begriffe <i>Membervariable</i>,
<i>Instanzvariable</i> und <i>Objektvariable</i> verwendet. Als <a name="ixa100457"><i>Objektvariable</i></a>
bezeichnen wir stets eine Variable, die ein Objekt aufnehmen kann,
also vom Typ einer Klasse ist. Das Gegenteil einer Objektvariable
ist eine primitive Variable <a name="ixa100458"></a>. Die Begriffe
<i>Membervariable</i> und <i>Instanzvariable</i> werden synonym verwendet.
Sie bezeichnen eine Variable, die innerhalb einer Klasse definiert
wurde und mit jeder Instanz neu angelegt wird.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
<tr>
<td><font color="#FFFFFF"> Hinweis </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
</tr>
</table>
<!-- Section -->
<a name="polymorphismus"></a>
<h3>7.1.6 Polymorphismus </h3>
<p>
Als letztes wichtiges Konzept objektorientierter Programmiersprachen
wollen wir uns mit dem <a name="ixa100459"><i>Polymorphismus</i></a>
beschäftigen. Polymorphismus bedeutet direkt übersetzt etwa
»Vielgestaltigkeit« und bezeichnet zunächst einmal
die Fähigkeit von Objektvariablen, Objekte unterschiedlicher
Klassen aufzunehmen. Das geschieht allerdings nicht unkontrolliert,
sondern beschränkt sich für eine Objektvariable des Typs
<i>X</i> auf alle Objekte der Klasse <i>X</i> oder einer daraus abgeleiteten
Klasse.
<p>
Eine Objektvariable vom Typ <i>Straßenfahrzeug</i> kann also
nicht nur Objekte der Klasse <i>Straßenfahrzeug</i> aufnehmen,
sondern auch Objekte der Klassen <i>Zweirad</i>, <i>Vierrad</i>, <i>Anhänger</i>,
<i>Motorrad</i>, <i>Fahrrad</i>, <i>Auto</i> und <i>Lastwagen</i>.
Diese auf den ersten Blick erstaunliche Lässigkeit entspricht
allerdings genau dem gewohnten Umgang mit Vererbungsbeziehungen. Ein
<i>Zweirad</i> ist nunmal ein <i>Straßenfahrzeug</i>, hat alle
Eigenschaften eines Straßenfahrzeugs und kann daher durch eine
Variable repräsentiert werden, die auf ein Straßenfahrzeug
verweist. Daß es möglicherweise ein paar zusätzliche
Eigenschaften besitzt, stört den Compiler nicht. Er hat nur sicherzustellen,
dass die Eigenschaften eines Straßenfahrzeugs vollständig
vorhanden sind, denn mehr stellt er dem Programm beim Zugriff auf
eine Variable dieses Typs nicht zur Verfügung. Davon kann er
aber aufgrund der Vererbungshierarchie ausgehen.
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
Anders herum funktioniert Polymorphismus nicht. Wäre es beispielsweise
möglich, einer Variable des Typs <i>Motorrad</i> ein Objekt des
Typs <i>Zweirad</i> zuzuzweisen, könnte das Laufzeitsystem in
Schwierigkeiten geraten. Immer wenn auf der <i>Motorrad</i>-Variablen
eine Eigenschaft benutzt würde, die in der Basisklasse <i>Zweirad</i>
noch nicht vorhanden ist, wäre das Verhalten des Programms undefiniert,
wenn zum Ausführungszeitpunkt nicht ein <i>Motorrad</i>, sondern
ein Objekt aus der Basisklasse darin gespeichert wäre.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
<tr>
<td><font color="#FFFFFF"> Hinweis </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
</tr>
</table>
<p>
Interessant wird Polymorphismus, wenn die Programmiersprache zusätzlich
das Konzept des <a name="ixa100460"><i>Late Binding</i></a> implementiert.
Im Unterschied zum »Early Binding« wird dabei nicht bereits
zur Compilezeit entschieden, welche Ausprägung einer bestimmten
Methode aufgerufen werden soll, sondern erst zur Laufzeit. Wenn beispielsweise
auf einem Objekt der Klasse <i>X</i> eine Methode mit dem Namen <i>f</i>
aufgerufen werden soll, ist zwar prinzipiell bereits zur Compilezeit
klar, wie der Name lautet. Objektorientierte Programmiersprachen erlauben
aber das <a name="ixa100461"><i>Überlagern</i></a> von Methoden
in abgeleiteten Klassen, und da - wie zuvor erwähnt - eine Objektvariable
des Typs <i>X</i> auch Objekte aus allen von <i>X</i> abgeleiteten
Klassen aufnehmen kann, könnte <i>f</i> in einer dieser nachgelagerten
Klassen überlagert worden sein. Welche konkrete Methode also
aufgerufen werden muss, kann damit erst zur Laufzeit entschieden werden.
Wir werden in <a href="k100055.html#abstraktpolymorph">Abschnitt 8.4</a>
ein ausführliches Anwendungsbeispiel vorstellen.
<p>
Nun ist dieses Verhalten keinesfalls hinderlich oder unerwünscht,
sondern kann sehr elegant dazu genutzt werden, automatische typbasierte
Fallunterscheidungen vorzunehmen. Betrachten wir dazu noch einmal
unsere Hierarchie von Transportmitteln. Angenommen, unser Unternehmen
verfügt über einen breit gefächerten Fuhrpark von Transportmitteln
aus allen Teilen des Ableitungsbaums. Als Unternehmer interessieren
uns natürlich die Kosten jedes Transportmittels pro Monat, und
wir würden dazu eine Methode <i>getMonatsKosten</i> in der Basisklasse
<i>Transportmittel</i> definieren. Ganz offensichtlich läßt
sich diese dort aber nicht <i>implementieren</i>, denn beispielsweise
die Berechnung der monatlichen Kosten unseres Fährschiffes gestaltet
sich ungleich schwieriger als die der drei Fahrräder, die auch
im Fahrzeugfundus sind.
<p>
Anstatt nun in aufwändigen Fallunterscheidungen für jedes
Objekt zu prüfen, von welchem Typ es ist, muss lediglich diese
Methode in jeder abgeleiteten Klasse implementiert werden. Besitzt
das Programm etwa ein Array von <i>Transportmittel</i>-Objekten, kann
dieses einfach durchlaufen und für jedes Element <i>getMonatsKosten</i>
aufgerufen werden. Das Laufzeitsystem kennt den jeweiligen konkreten
Typ und kann die korrekte Methode aufrufen (und das ist die aus der
eigenen Klasse, nicht die in <i>Transportmittel</i> definierte).
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
Falls es vorkommt, dass die Implementierung in einer bestimmten Klasse
mit der seiner Basisklasse übereinstimmt, braucht die Methode
nicht noch einmal überlagert zu werden. Das Laufzeitsystem verwendet
in diesem Fall die Implementierung aus der Vaterklasse, die der eigenen
Klasse am nächsten liegt.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
<tr>
<td><font color="#FFFFFF"> Hinweis </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
</tr>
</table>
<!-- Section -->
<a name="sectlevel3id007001007"></a>
<h3>7.1.7 Fazit </h3>
<p>
Objektorientierte Programmierung erlaubt eine natürliche Modellierung
vieler Problemstellungen. Sie vermindert die Komplexität eines
Programms durch Abstraktion, Kapselung, definierte Schnittstellen
und Reduzierung von Querzugriffen. Sie stellt Hilfsmittel zur Darstellung
von Beziehungen zwischen Klassen und Objekten dar, und sie erhöht
die Effizienz des Entwicklers durch Förderung der Wiederverwendung
von Programmcode. Wir werden in den nächsten Abschnitten zeigen,
wie die objektorientierte Programmierung sich in Java gestaltet.
<hr>
<table border=0 cellpadding=0 cellspacing=1 width="100%">
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html"> Titel </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html"> Inhalt </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html"> Suchen </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html"> Index </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()"> DOC </a>
<td align="right">Handbuch der Java-Programmierung, 5. Auflage, Addison
Wesley, Version 5.0.1
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100046.html"> << </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100046.html"> < </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100048.html"> > </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100051.html"> >> </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()"> API </a>
<td align="right">© 1998, 2007 Guido Krüger & Thomas
Stark, <a href="http://www.javabuch.de">http://www.javabuch.de</a>
</table>
<a name="endofbody"></a>
</body>
</html>
|