5. Inhalt von Objekten   Inhaltsverzeichnis 7. Beispiel: Warteschlange

6. Referenzieren von Objekten

Objekte werden von (Referenz-) Variablen referenziert. Diese können entweder lokale oder globale Referenzen in einem Modul oder einer Klasse sein. In den ersten beiden Fällen werden sie im Objektdiagramm „nackt“ (in den Speicherbereichen Modul bzw. Stapel) dargestellt; im dritten Fall befinden sie sich in (typischerweise anderen[1]) Objekten auf der Halde.

Referenzen zeigen (zumindest in Scala und Java) nie auf Variablen[2], nur auf Objekte – daher immer auf die Halde. Referenzen zeigen (zumindest in Scala und Java) nie in ein Objekt hinein, nur auf ein Objekt.

Objekte können nirgendwo hinzeigen – sie enthalten nur Variablen. Nur eine Referenz (statisch, lokal oder global) kann auf ein Objekt zeigen.

Manchmal ist es sinnvoll, die (unveränderbare) Referenz this zu zeichnen, die in jeder (Klassen-) Methode auf das aktuelle Objekt zeigt. Diese kann im Stapel dargestellt werden.

Es kommt häufig vor, dass ein Objekt von mehreren Stellen referenziert wird – insbesondere nach Zuweisungen. Wenn ref1 auf ein Objekt zeigt, dann zeigen nach der Zuweisung

val ref2 = ref1 // [3]

beide Referenzen auf dasselbe Objekt:

Abbildung12: Zuweisung

Hierbei befinden sich die Referenzen auf dem Stapel, auf der Halde oder im Modulbereich.

Solche Zuweisungen befinden sich häufig verborgen innerhalb einer Methode, deren Programmtext nicht vorliegt. Ein typisches Beispiel hierfür sind set-Methoden. Beispielsweise bewirkt der Programmabschnitt

val f = new java.awt.Frame

val mb = new java.awt.MenuBar

f.setMenuBar(mb)

dass eine (unbekannte, in der Klasse Frame vereinbarte) Referenz auf das MenuBar-Objekt zeigt:

Abbildung 13: setMenuBar

Eine solche implizite Zuweisung kann im Objektdiagramm mit dem Namen der bewirkenden Methode (oben rot) am Pfeil dargestellt werden.

Dasselbe Effekt ist meistens auch bei parametrisierten Konstruktoren zu vermuten, deren Aufgabe typischerweise ist, die Objektvariablen mit den Parameterwerten zu initialisieren:

val br = new java.io.BufferedReader(new java.io.InputStreamReader
   (java.lang.System.in)) //
[4]

Abbildung 14: Reader

In diesem Objektdiagramm haben wir mit einem punktierten (rotem) Pfeil dargestellt, dass der Konstruktor den Wert aus der Klassenvariable System.in (nämlich die Adresse des InputStream-Objekts, das die Konsole repräsentiert) in eine Variable des (im obigen Programmstück) neu erzeugten InputStreamReader-Objekts hineinkopiert hat. Deren Namen kennen wir nicht, dazu müsste der Programmtext von InputStreamReader studiert werden; er spielt aber keine Rolle, um zu verstehen, wie Reader-Objekte miteinander verknüpft werden, um die Leistung von Filterklassen (hier z.B. mit einem anschließenden br.readLine-Aufruf) nutzen zu können.

Als ein weiteres Beispiel für die Entstehung einer Objektstruktur können wir die Behälterhiearchie in Swing betrachten:

class Knopf extends javax.swing.JApplet {

   override def init = {

     val knopf = new javax.swing.JButton("OK")

     val c = super.getContentPane() // java.awt.Container[5]

     c.add(knopf) } }

Hier wird die von JApplet geerbte init-Methode überschrieben: Darin ein JButton-Objekt (mit Hilfe eines String-parametrisierten Konstruktors) erzeugt und dessen Adresse in die lokale Variable knopf abgelegt. Damit das Objekt nach der Beendigung der init-Methode nicht (zusammen mit der knopf-Variable auf dem Stapel) verloren geht, wird es dem Content Pane (ein Container-Objekt) des JApplet-Objekts mit add hinzugefügt. Die Adresse des Container-Objekts wird mit Hilfe der (von JApplet geerbten) getContentPane-Methode besorgt und in die lokale Variable c abgelegt:

Abbildung 15: swing

Um das Objektdiagramm einfach und übersichtlich zu halten, haben wir hier die Tatsache nicht dargestellt, dass dem Content Pane nicht nur ein Component-Objekt (wie JButton), sondern mehrere[6] hinzugefügt werden können. Eine ähnliche Vereinfachung ist, dass wir die Zeichenkette OK einfach in das JButton-Objekt hineingeschrieben haben. Korrekter wäre ein zusätzliches String-Objekt (referenziert aus einer Variable im JButton-Objekt) zu zeichnen, was aber zur Verständlichkeit des Sachverhalts wenig beitragen und die Komplexität der Zeichnung überflüssig erhöhen würde.

Das Objektdiagramm stellt dar, dass add() die Adresse des JButton-Objekts aus der Variable knopf in eine (unbekannte) Variable des Container-Objekts hineinkopiert. Die Adresse dieses Container-Objekts wird aus einer (unbekannten) Variable des Knopf-Objekts von der Methode getContentPane() geholt. Das Knopf-Objekt ist gleichzeitig auch ein JApplet-Objekt, zumal in der Klasse Knopf keine zusätzlichen Objektvariablen vereinbart wurden.

5. Inhalt von Objekten   Inhaltsverzeichnis 7. Beispiel: Warteschlange

[1] Es ist vorstellbar (wenn auch nur selten sinnvoll), dass ein Objekt eine Referenz enthält, die auf sich selbst zeigt.

[2] in C/C++ ist dies möglich

[3] durch Inferenz ermittelt der Compiler den Typ von ref1, so wird ref2 vom selben Typ

[4] in Scala wird diese aus früheren Java-Programmen bekannte Programmzeile meistens nicht benötig, da Console alle nötigen Methoden enthält – sie stellt aber die Verkettung von Filterstrom-Objekten einleuchtend dar.

[5] der Typ wird vom Compiler durch Inferenz ermittelt

[6] d.h. add die Adresse von JButton nicht in eine Variable, sondern in eine verkettete Liste schreibt


Version: 5. Dezember 2010

© Prof. Solymosi, 2010, Beuth-Hochschule für Technik Berlin