Luisengymnasium

Referenzen im Speicher

Lernziele

Nach diesem Kapitel kannst du:

  • die Grundidee der Von-Neumann-Architektur erklären,
  • Speicher als Modell aus Adresse und Daten beschreiben,
  • Speicherabbilder für Objekte und Referenzen zeichnen und lesen,
  • Setter und Getter für Referenz-Attribute implementieren,
  • analysieren, ob eine Methode das übergebene Objekt verändert oder nur die lokale Referenz umbiegt,
  • begründen, warum getPilot() Zugriff auf das Original-Objekt gibt, nicht auf eine Kopie.

Leitfrage: Wie sieht eine Referenz im Speicher tatsächlich aus — und was passiert, wenn du sie an eine Methode weitergibst?

Voraussetzungen

Hinweis

Dieses Kapitel baut direkt auf Kapitel 01 (Referenzen verstehen) auf. Du solltest Aliasing, null und den Unterschied == vs. .equals() sicher beherrschen.

Übergang aus dem letzten Kapitel

Im letzten Kapitel hast du gelernt: Eine Referenz ist wie ein Pfeil auf ein Objekt. Dieses Bild erklärt Aliasing gut, aber es ist noch ungenau.

Jetzt wird der Pfeil entzaubert: Im Speicher ist eine Referenz eine Adresse. Die Frage lautet nicht mehr nur „Worauf zeigt die Variable?", sondern: Welche Adresse steht in der Variable und welches Objekt liegt an dieser Adresse?


Phase 1: Einstieg — Was IST eine Referenz im Speicher?

Hinweis

Retrieval-Check (ohne nachschauen):

  1. Was kopiert rs2 = rs1 — das Objekt oder den Pfeil?
  2. Was ist der Unterschied zwischen einfachen und komplexen Datentypen im Speicher?
  3. Was passiert bei rs.setGroesse(200), wenn rs auf null zeigt?

Aufgabe: Vorhersage

Lies den folgenden Code. Was erwartest du — true oder false bei den Vergleichen?

Raumschiff rs1 = new Raumschiff();
Raumschiff rs2 = rs1;
 
System.out.println(rs1 == rs2);
 
rs2 = new Raumschiff();
System.out.println(rs1 == rs2);
Tipp

Schreibe deine Vermutung auf, bevor du den Code ausführst.

Textabgabe

IDE lädt…


Phase 2: Konzeptaufbau — Vom Speicher zur Praxis

2.1 Von-Neumann-Architektur

Die zentrale Idee: Programme und Daten liegen im selben Speicher (RAM). Die CPU holt Befehle und Daten, verarbeitet sie und schreibt Ergebnisse zurück.

KomponenteAufgabe
SteuerwerkFührt Befehle in der richtigen Reihenfolge aus
ALURechnet und vergleicht Werte
Speicher (RAM)Speichert Programme und Daten während der Ausführung
Ein-/AusgabeAustausch mit Tastatur, Bildschirm, Dateien

2.2 Speicher als Adress-/Daten-Tabelle

Der RAM ist eine große Folge von Speicherzellen. Jede Zelle hat eine Adresse und speichert Bytes:

AdresseDatenInterpretation
0x1000x3A8Referenz rs1 → zeigt auf Adresse 0x3A8
0x1080x3A8Referenz rs2 → zeigt auf dieselbe Adresse!
.........
0x3A8200.0Attribut groesse des Raumschiff-Objekts
Hinweis

Kernaussage: Eine Referenz speichert eine Adresse — eine Zahl, die sagt, WO das Objekt im RAM liegt. rs2 = rs1 kopiert diese Adresse, nicht das Objekt.

Achtung

Dieselben Bytes im Speicher können je nach Kontext eine Zahl, ein Zeichen oder eine Adresse bedeuten. Die Interpretation ergibt sich erst durch den Datentyp im Programm.

Reflexionsfrage: Warum speichert Java nicht einfach das ganze Objekt in der Variablen, statt nur eine Adresse?

2.3 Objekte miteinander verbinden — Referenz-Attribute

Bisher hatten wir Referenzen in der Hauptklasse (WeltraumSim → Raumschiff). Aber was, wenn das Raumschiff selbst wissen soll, wer es fliegt?

Dafür bekommt Raumschiff ein Referenz-Attribut:

Mermaid-Diagramm
Mermaid-Diagramm wird geladen…

Implementierung:

public class Raumschiff
{
    private String typ;
    private Pilot pil;       // Referenz-Attribut
 
    public void setPilot(Pilot pp)
    {
        pil = pp;            // Referenz wird gespeichert — nicht das Objekt kopiert!
    }
 
    public Pilot getPilot()
    {
        return pil;          // Gibt die Referenz zurück — Zugriff auf das Original
    }
}
Hinweis

Rollenverteilung: WeltraumSim erzeugt alle Objekte (new). Raumschiff erzeugt den Piloten nicht selbst — es bekommt nur die Referenz zugewiesen. So kann der Pilot gewechselt werden.

Reflexionsfrage: Warum erzeugt das Raumschiff den Piloten nicht selbst im Konstruktor (z.B. pil = new Pilot();)? Wann wäre das sinnvoll, wann nicht?

Was passiert bei setPilot(p1) im Speicher?

  1. p1 enthält die Adresse des Pilot-Objekts (z.B. 0x500).
  2. setPilot(p1) übergibt diese Adresse an den Parameter pp.
  3. pil = pp kopiert die Adresse nach pil.
  4. Ergebnis: p1 (in WeltraumSim) und pil (in Raumschiff) speichern beide 0x500 — dasselbe Objekt.
Mermaid-Diagramm
Mermaid-Diagramm wird geladen…
Tipp

Erkläre, bevor du weiterliest: Was genau passiert im Speicher, wenn setPilot(p1) aufgerufen wird? Wird der Pilot kopiert? Schreibe 2–3 Sätze auf.

Probiere es selbst aus:

IDE lädt…

Sicherheit: null-Check vor dem Zugriff

getPilot() kann null zurückgeben — wenn noch kein Pilot zugewiesen wurde.

Pilot p = rs1.getPilot();
if (p != null)
{
    System.out.println(p.getName());
}
Wichtig

Ohne null-Check: rs1.getPilot().getName() → NullPointerException, wenn kein Pilot gesetzt ist.

Ruhige Sicherung: Referenz, Adresse, Objekt

Tipp

Ordne die drei Ebenen sauber:

EbeneFrageBeispiel
VariableWo steht die Referenz?rs1
ReferenzwertWelche Adresse wird gespeichert?0x1A4F
ObjektWas liegt an dieser Adresse?Raumschiff(groesse=100)

Der häufigste Denkfehler ist, Variable und Objekt gleichzusetzen. Die Variable ist nicht das Objekt. Sie enthält nur die Adresse, über die das Objekt gefunden wird.

Code-Patterns zum Nachschlagen

Referenz-Attribute: Patterns
// Referenz setzen
obj.setRef(anderesObj);
 
// Referenz sicher auslesen
Typ x = obj.getRef();
if (x != null) { x.methode(); }
 
// Optional-Check als boolean-Methode
public boolean hatRef() { return ref != null; }

Fading: Übe schrittweise


Phase 3: Üben — Parameterübergabe und Praxis

Hinweis

Retrieval-Check:

  1. Wie viele Pilot-Objekte existieren nach rs1.setPilot(p1); Pilot p = rs1.getPilot();?
  2. Was gibt rs1.getGroesse() aus nach Raumschiff rs2 = rs1; rs2.setGroesse(500);? (Rückbezug Kap. 01)

3.1 Parameterübergabe: Objekt verändern vs. Referenz umbiegen

Sage für beide Methoden vorher: Ändert sich das Original?

IDE lädt…

3.2 Abgabe-Aufgaben

A1: Speicherabbild zeichnen (Pflicht)

Zeichne ein Speicherabbild (Tabelle mit Adresse | Daten | Interpretation) für den folgenden Code. Verwende fiktive Adressen (z.B. 0x100, 0x200, ...).

Pilot p1 = new Pilot("Kirk");
Raumschiff rs1 = new Raumschiff();
rs1.setPilot(p1);
Pilot p = rs1.getPilot();

Wie viele Objekte existieren? Wie viele Referenzen zeigen auf das Pilot-Objekt?

Textabgabe

A2: Klasse Kunde implementieren (Pflicht)

Implementiere die Klasse Kunde mit:

  • Attribut name (String), kto (Konto), dep (Depot — optional)
  • Konstruktor, der den Namen setzt
  • Getter/Setter für kto und dep
  • Methode hatDepot(), die true zurückgibt, wenn dep gesetzt ist

IDE lädt…

A3: Debugging — null-Check fehlt (Pflicht)

Der folgende Code stürzt ab. Finde den Fehler und behebe ihn.

IDE lädt…

A4: Parameter-Analyse (Vertiefung)

Gegeben:

void wechslePilot(Raumschiff rs) { rs.setPilot(new Pilot("Neu")); }
void resetSchiff(Raumschiff rs) { rs = new Raumschiff(); }

a) Ändert wechslePilot(meins) den Piloten im Original-Raumschiff meins? Begründe.

b) Ändert resetSchiff(meins) das Original-Raumschiff? Begründe.

c) Erkläre den Unterschied mit dem Satz: „Java übergibt eine Kopie der ___."

Teste deine Vermutung:

IDE lädt…

Textabgabe

A5: Sichere Getter (Vertiefung)

getPilot() gibt eine Referenz auf das Original-Pilot-Objekt zurück. Das bedeutet: Jeder, der getPilot() aufruft, kann den Piloten im Raumschiff verändern — auch unbeabsichtigt.

a) Ist das gefährlich? Nenne ein Szenario, in dem das zum Problem wird.

b) Schreibe eine „sichere" Version getPilotKopie(), die eine Kopie des Piloten zurückgibt. Tipp: Du brauchst new Pilot(pil.getName()).

c) Wann lohnt sich der Aufwand einer Kopie, wann nicht?

Textabgabe

Phase 4: Transfer und Vernetzung

Transferaufgabe

Durchgängiges Projekt: Online-Shop

Diese Aufgabe ist Teil des Online-Shop-Projekts, das sich durch den Kurs Lineare Datenstrukturen 1 zieht. In Kapitel 01 hast du Produkt und Kunde kennengelernt. Jetzt kommt der Warenkorb dazu.

Projektstand Online-Shop

Der Shop kann jetzt Beziehungen speichern: Ein Warenkorb, ein Kunde oder ein Produkt kann eine Referenz auf ein anderes Objekt halten. Damit wird aus einzelnen Klassen ein kleines Objektsystem.

Die Grenze ist aber noch sichtbar: Für viele Produkte reicht eine einzelne Referenz nicht mehr aus.

Online-Shop: Warenkorb

Entwirf eine Klasse Warenkorb mit einer Referenz aktuellesProdukt auf ein Produkt.

a) Zeichne ein Klassendiagramm.

b) Implementiere setAktuellesProdukt(Produkt p) und getAktuellesProdukt().

c) Schreibe eine Methode wechsleProdukt(Produkt neues). Was passiert mit dem alten Produkt-Objekt — wird es gelöscht?

IDE lädt…

Projekt: Bank-Software

Projekt: Bank-Software (umfangreich)

Entwirf und implementiere eine vereinfachte Bank-Software mit 4 Klassen:

Mermaid-Diagramm
Mermaid-Diagramm wird geladen…

Aufgaben:

a) Implementiere die Klassen Konto, Depot und Kunde.

b) Implementiere anfangsWerte() in Bank: Erzeuge 2 Kunden, 2 Konten, 1 Depot. Weise jedem Kunden ein Konto zu. Nur Kunde 1 bekommt ein Depot.

c) Implementiere kontoBearbeiten(Kunde pk): Zeige den Kontostand an, lass einzahlen oder abheben.

d) Implementiere depotBearbeiten(Kunde pk): Prüfe zuerst mit hatDepot(), ob der Kunde ein Depot hat. Wenn ja: Aktie anzeigen, kaufen/verkaufen. Wenn nein: Meldung ausgeben.

e) Reflexionsfrage: Was passiert, wenn zwei Kunden dasselbe Konto-Objekt zugewiesen bekommen? Erkläre mit Aliasing.

IDE lädt…

Vernetzung

Heute gelöst: Der Pfeil aus Kapitel 01 ist jetzt kein bloßes Bild mehr. Du weißt: Eine Referenz ist ein Adresswert. Bei einer Übergabe an eine Methode wird diese Adresse kopiert. Das Originalobjekt kann dadurch verändert werden, aber die ursprüngliche Variable wird nicht einfach umgebogen.

Noch offen: Bisher haben wir einzelne Referenzen betrachtet: ein Raumschiff kennt einen Piloten, ein Kunde kennt ein Lieblingsprodukt. Reale Systeme brauchen aber nicht nur einen Pfeil, sondern viele Pfeile nebeneinander.

Nächster Schritt: Im nächsten Kapitel entstehen Arrays von Referenzen. Die neue Falle: Viele Plätze bedeuten noch nicht viele Objekte.

Reflexion

Hinweis

Beantworte die Leitfrage: Wie sieht eine Referenz im Speicher aus? Was passiert, wenn du sie an eine Methode weitergibst? Nutze die Begriffe „Adresse", „Kopie der Referenz" und „Original-Objekt".

Textabgabe

Selbstdiagnose

  • Ich kann erklären, was eine Referenz im Speicher ist (eine Adresse).
  • Ich kann ein Speicherabbild zu gegebenem Code zeichnen (Adresse | Daten | Interpretation).
  • Ich kann Setter/Getter für Referenz-Attribute schreiben.
  • Ich weiß, wann ich einen null-Check brauche.
  • Ich kann erklären, ob eine Methode das Original-Objekt verändert oder nicht.