Luisengymnasium

Referenzen verstehen

Lernziele

Nach diesem Kapitel kannst du:

  • Code mit Referenzzuweisungen tracen und die Ausgabe korrekt vorhersagen,
  • erklären, warum ein Methodenaufruf auf null zur NullPointerException führt,
  • Referenzfehler (NullPointerException, unbeabsichtigtes Aliasing) debuggen und beheben,
  • Objektdiagramme zu gegebenem Code zeichnen und den Speicherzustand erklären,
  • begründen, warum == und .equals() unterschiedliche Ergebnisse liefern,
  • einschätzen, ob ein Objekt vom Garbage Collector entfernt werden kann.

Leitfrage: Wenn rs2 = rs1 nicht das Objekt kopiert — was kopiert es dann?

Voraussetzungen

Hinweis

Bevor du startest, prüfe mit dem Selbsttest unten, ob du die Grundlagen beherrschst. Falls du unsicher bist: Nutze die Auffrischungen oder den KI-Wiederholungsprompt.

Selbsttest

Tipp

Falls du mehr als eine Aufgabe nicht lösen konntest, nutze die Auffrischungen unten.

Kurzwiederholungen

Lernweg

Arbeite dieses Kapitel in vier Schritten:

  1. Ausprobieren: Was passiert bei rs2 = rs1? Vermute, teste, staune.
  2. Verstehen: Wie funktionieren Referenzen — null, new, Aliasing?
  3. Üben: Tracing, Debugging, == vs. equals().
  4. Übertragen: Eigene Klassen mit Referenzen entwerfen.
Dramaturgischer Auftakt

Bisher konntest du Variablen meistens wie kleine Behälter behandeln: In int a = 5 steckt der Wert 5. Dieses Bild funktioniert für einfache Werte gut.

In diesem Kapitel bricht dieses Bild absichtlich. Bei Objekten enthält die Variable nicht das Objekt selbst, sondern nur einen Weg dorthin. Genau deshalb kann eine Änderung über rs2 plötzlich bei rs1 sichtbar werden.

Die zentrale Spannung lautet: Wenn = nicht das Objekt kopiert, was wird dann wirklich kopiert?


Phase 1: Einstieg — Was kopiert = wirklich?

Hinweis

Bevor du weiterliest — beantworte ohne nachzuschauen:

Aufgabe: Vorhersage

Lies den folgenden Code. Schreibe deine Vermutung auf, BEVOR du den Code ausführst.

Raumschiff rs1 = new Raumschiff();
rs1.setGroesse(100);
Raumschiff rs2 = rs1;
rs2.setGroesse(200);
System.out.println(rs1.getGroesse());

Was wird ausgegeben? Notiere deine Antwort.

Textabgabe
Tipp

Versuche es wirklich selbst — auch eine falsche Vermutung hilft dir beim Lernen.

Jetzt teste deine Vorhersage:

IDE lädt…


Phase 2: Konzeptaufbau — Referenzen Schritt für Schritt

Hinweis

Retrieval-Check: Wie viele Objekte existieren nach rs2 = rs1? Wie viele Referenzen?

2.1 Einfache vs. komplexe Datentypen

Hinweis

Einfache Datentypen (int, double, boolean, char) speichern einen Wert direkt. Ein Attribut mit einem Klassen-Typ (z.B. Raumschiff rs) heißt Referenz — es speichert nicht das Objekt, sondern einen Verweis darauf.

Im Code sieht man den Unterschied sofort:

private int anzahl;       // einfacher Datentyp → speichert direkt einen Wert
private Raumschiff rs;    // komplexer Datentyp → speichert eine Referenz

2.2 null — Referenz ohne Objekt

Wenn ein Objekt der Klasse WeltraumSim erzeugt wird:

  • anzahl wird auf 0 gesetzt (einfaches Attribut).
  • rs zeigt auf nichts — der Wert ist null.
public static void main(String[] args)
{
    anzahl = 1;             // funktioniert
    rs.setGroesse(200.0);   // ABSTURZ!
}
Wichtig

rs zeigt auf null — es gibt kein Objekt! Der Methodenaufruf führt zur NullPointerException. Dieser Fehler ist einer der häufigsten in Java — und der Compiler erkennt ihn nicht.

Teste es selbst — sage vorher, was passiert:

IDE lädt…

2.3 Der new-Operator

Die Lösung: Im Konstruktor wird das Objekt mit new erzeugt.

public WeltraumSim()
{
    rs = new Raumschiff();   // Jetzt zeigt rs auf ein echtes Objekt
}
Mermaid-Diagramm
Mermaid-Diagramm wird geladen…
Hinweis

Immer in dieser Reihenfolge denken:

  1. Referenz deklarieren
  2. Objekt mit new erzeugen
  3. Methoden am Objekt aufrufen

2.4 Mehrere Referenzen und Aliasing

Was, wenn wir mehrere Raumschiffe verwalten wollen?

public class WeltraumSim
{
    private Raumschiff rs1, rs2;
    private Raumschiff aktuell;
    ...
}

Schritt für Schritt:

Hinweis

Merkregel: Eine Referenz ist ein Pfeil, kein Ding. rs2 = rs1 kopiert den Pfeil — nicht das, worauf er zeigt.

Reflexionsfrage: Was wäre der Nachteil, wenn Java bei rs2 = rs1 automatisch eine Kopie des Objekts machen würde?

Ruhige Sicherung: Was sich wirklich geändert hat

Tipp

Halte kurz an. Das ist der wichtigste Modellwechsel des Kapitels:

  1. Eine Objektvariable enthält nicht das Objekt, sondern eine Referenz.
  2. Eine Zuweisung wie rs2 = rs1 kopiert diese Referenz.
  3. Danach können zwei Variablen auf dasselbe Objekt zeigen.

Wenn du diese drei Sätze sicher erklären kannst, ist der schwierigste Teil dieses Kapitels geschafft.

Fading: Übe schrittweise

Code-Patterns zum Nachschlagen

Referenz-Patterns
// Erzeugung: Referenz + Objekt
Typ ref = new Typ();
 
// Aliasing: Zwei Pfeile, ein Objekt
Typ ref2 = ref1;
 
// Null-Check: Absturz vermeiden
if (ref != null) { ref.methode(); }

Phase 3: Üben — Tracing, Debugging, Vergleiche

Hinweis

Retrieval-Check:

  1. Was gibt aus: Raumschiff a = new Raumschiff(); Raumschiff b = a; a = null; System.out.println(b.getGroesse());?
  2. Wird das Raumschiff-Objekt jetzt vom Garbage Collector entfernt?

3.1 == vs. equals() — Identität vs. Gleichheit

Was passiert, wenn man zwei Referenzen mit == vergleicht?

String strA = new String("Heute");
String strB = new String("Heute");
Mermaid-Diagramm
Mermaid-Diagramm wird geladen…

Die Objekte haben den gleichen Inhalt, sind aber verschiedene Objekte.

VergleichPrüft was?Ergebnis
strA == strBIdentität (gleiches Objekt?)false
strA.equals(strB)Inhalt (gleicher Text?)true
Achtung

== prüft, ob zwei Referenzen auf dasselbe Objekt zeigen. Für Inhaltsvergleich verwende .equals().

Sage für jeden Ausdruck die Ausgabe vorher, dann teste:

IDE lädt…

3.2 Übungsaufgaben

A1: Tracing (Pflicht)

Gegeben ist folgender Code:

String s1, s2, s3, s4;
s1 = new String("ABC");
s1 = new String("XYZ");
s2 = new String("ABC");
s3 = s1;
s4 = new String("XYZ");

a) Zeichne alle Objekte und Referenzen am Ende des Codes.

b) Fülle die Tabelle aus:

AusdruckErgebnis
s1 == s2
s1 == s3
s1 == s4
s1.equals(s2)
s1.equals(s3)
s1.equals(s4)
Textabgabe

A2: Debugging (Pflicht)

Das folgende Programm enthält zwei Fehler. Finde und behebe sie. Erkläre jeweils, warum der Fehler entsteht.

IDE lädt…

A3: Modifizierung (Pflicht)

Das folgende Programm hat eine aktuell-Referenz, die auf verschiedene Raumschiffe zeigen soll. Ergänze die fehlenden Zuweisungen, sodass nacheinander alle drei Raumschiffe gesteuert werden.

IDE lädt…

A4: Identität vs. Gleichheit (Vertiefung)

Ein Mitschüler behauptet: „Wenn == bei zwei Raumschiff-Variablen true ergibt, dann sind die Raumschiffe gleich groß."

Hat er recht? Formuliere eine präzisere Aussage und belege sie mit einem Code-Beispiel, das zeigt, wann == true ergibt, obwohl die Größen unterschiedlich sein könnten — und umgekehrt.

Textabgabe

A5: Garbage Collection analysieren (Vertiefung)

Gegeben:

Raumschiff rs1 = new Raumschiff();
Raumschiff rs2 = rs1;
rs1 = null;

a) Wird das Raumschiff-Objekt vom Garbage Collector entfernt? Begründe mit einem Objektdiagramm.

b) Ändere den Code so, dass das Objekt tatsächlich entfernt werden kann. Erkläre, was sich ändert.

Textabgabe

Phase 4: Transfer und Vernetzung

Transferaufgabe

Online-Shop: Produkt und Kunde

Durchgängiges Projekt: Online-Shop

Ab jetzt baust du Schritt für Schritt einen Online-Shop auf. In jedem Kapitel kommt ein neues Feature dazu. Am Ende des Kurses Lineare Datenstrukturen 1 hast du ein komplettes System mit Produkten, Kunden, Bestellungen und Bewertungen.

Projektstand Online-Shop

Der Shop bekommt jetzt seine erste Beziehung: Ein Kunde kann auf ein Produkt zeigen. Das klingt klein, ist aber der Grundbaustein für alles Weitere. Ab jetzt besteht der Shop nicht mehr nur aus einzelnen Objekten, sondern aus Objekten, die andere Objekte kennen.

Entwirf zwei Klassen: Produkt (mit Attributen name und preis) und Kunde (mit Attribut lieblingsProdukt vom Typ Produkt).

a) Zeichne ein Klassendiagramm.

b) Schreibe den Konstruktor für Kunde, der einen Namen entgegennimmt (das Lieblingsprodukt ist anfangs null).

c) Schreibe setLieblingsProdukt(Produkt p) und getLieblingsProdukt().

d) Beantworte: Wenn jemand über kunde.getLieblingsProdukt().setPreis(0.01) den Preis ändert — ändert sich dann auch der Preis des Produkts IM Shop? Warum?

IDE lädt…

Vernetzung

Heute gelöst: Du weißt jetzt, warum rs2 = rs1 nicht zwei Raumschiffe erzeugt. Es entsteht nur ein zweiter Zugriff auf dasselbe Objekt. Das erklärt Aliasing, null und viele scheinbar merkwürdige Ausgaben.

Noch offen: Das Pfeilbild hilft, aber es bleibt noch eine Metapher. Im Rechner gibt es keine gezeichneten Pfeile. Dort gibt es Speicherstellen, Werte und Adressen.

Nächster Schritt: Im nächsten Kapitel wird der Pfeil technisch konkret: Eine Referenz ist eine Adresse im Speicher. Dann klären wir auch, was bei Methodenaufrufen wirklich übergeben wird.

Reflexion

Hinweis

Beantworte die Leitfrage in eigenen Worten: Wenn rs2 = rs1 nicht das Objekt kopiert — was kopiert es dann? Nutze die Begriffe „Referenz", „Objekt" und „Pfeil".

Textabgabe

Selbstdiagnose

  • Ich kann erklären, was bei rs2 = rs1 passiert (Pfeil kopiert, nicht Objekt).
  • Ich kann eine NullPointerException erkennen und beheben.
  • Ich kann den Unterschied zwischen == und .equals() an einem Beispiel erklären.
  • Ich kann ein Objektdiagramm zu Code mit Referenzen zeichnen.