Verbund (Java Klasse)

Motivation

  • Viele einzelne Variablen sind verwirrend und schwer zu handhaben
  • Häufig gehören Daten zusammen und sollen gemeinsam verarbeitet werden, z. B.
    • Daten eines Studierenden (Name, Matrikelnummer etc.)
    • Technische Daten eines Autos (PS, Höchstgeschwindigkeit etc.)
  • Man möchte diese Daten zu einer einzigen Variable zusammenfassen

Verbund/Struktur

  • Ein Verbund (record) bzw. Struktur (struct) erlaubt verschiedene Daten zu einer Variable zusammenfassen
  • er besteht aus Elementen mit unterschiedlichen Datentypen, den Attributen (attributes)
Verbund

In der Programmierung benötigt man Strukturen, um Daten unterschiedlichen Typs sinnvoll zusammenzufassen, weil primitive Datentypen oder einfache Variablen keine strukturierte Darstellung komplexer Objekte erlauben. Wenn beispielsweise mehrere zusammengehörige Informationen, wie Name (String), Alter (int) und Gehalt (double), gemeinsam verarbeitet werden sollen, ist es unpraktisch, sie einzeln zu verwalten.

Strukturen ermöglichen es, diese verschiedenen Datenfelder in einer logisch zusammengehörigen Einheit zu kapseln. Dadurch wird der Code übersichtlicher, besser wartbar und leichter erweiterbar. Außerdem lassen sich in der objektorientierten Programmierung noch Methoden hinzufügen, mit denen man auch Verhalten definieren kann, das zu den Daten gehört, was zu einer klaren Trennung von Daten und Funktionalität führt.

Klasse (class)

  • in Java wird eine Struktur mithilfe einer Klasse realisiert
  • eine Klasse setzt sich aus primitiven Datentypen oder anderen Klassen zusammen
  • Syntax: class NAME { Variablen-Deklaration }
class Kfz {
    /** Leistung in PS */
    int leistung;

    /** Hoechstgeschwindigkeit in km/h */
    int vmax;

    /** Leergewicht in Tonnen */
    double gewicht;
}

UML-Darstellung einer Klasse


UML-Darstellung der Klasse Kfz

Speicherung einer Klasse

  • In Java müssen Klassen in einer eigenen Datei abgelegt werden
  • Datei muss so heißen, wie die Klasse mit der Endung .java
    Kfz.java
  • Eclipse beachtet diese Regel automatisch

Verwenden einer Klasse

  • Jede Klasse führt einen neuen Datentyp ein
  • Kann als Typ einer Variable benutzt werden
    Syntax: NAME variable;
  • Elemente einer Klasse nennt man Attribute (attributes)
  • Anders als bei primitiven Typen handelt es sich um Referenztypen
Kfz bmw;
Kfz porsche;
Kfz ferrari;

Referenzdatentypen

Java unterscheidet zwischen

  • primitiven Datentypen – Variable repräsentiert Speicherstelle, in der die Daten stehen
    • byte, short, int, long, boolean, char, double, float
  • Referenzdatentypen – Variable repräsentiert Speicherstelle, in der die Adresse der Speicherstelle steht, in der die Daten zu finden sind (Indirektion)
    • alle anderen (höheren) Datentypen (Klassen, Verbund)
    • insbesondere Strings und Arrays
  • Variable, die auf einen Referenzdatentyp zeigt nennt man Referenzvariable
Vergleich primitiver Datentyp mit Referenztyp

Definition von Referenzdatentypen

Definition besteht aus zwei Schritten

  1. Anlegen der Variable (Referenzvariable), die die Referenz speichert
    Syntax: DATENTYP variable;
  2. Speicher für die eigentlichen Daten beschaffen
    Syntax: new DATENTYP()

Häufig werden beide Operationen kombiniert
DATENTYP variable = new DATENTYP();


Kfz auto = new Kfz();
Kfz porsche = new Kfz();
Kfz ferrari = new Kfz();

Referenzdatentypen

Kfz auto = new Kfz();
Speicherablage eines Verbundes

Besonderer Wert: null

Der spezielle Wert null wird in Java (und vielen anderen Programmiersprachen) benötigt, um auszudrücken, dass eine Variable noch auf kein Objekt verweist. Er dient also als Platzhalter oder Kennzeichnung dafür, dass kein gültiger Wert vorhanden ist.

  • null: Wert, der andeutet, dass Referenzvariable auf nichts verweisen
  • nur zwei mögliche Zustände einer Referenzvariable
    • zeigt auf eine Speicherstelle mit Daten oder
    • hat den Wert null
  • man kann eine Variable mit null vergleichen, um zu sehen, ob sie auf Daten zeigt
Kfz auto = null; // zeigt auf nichts
auto = new Kfz(); // zeigt auf das neue KFZ

System.out.println(auto == null); // -> false

Ohne null gäbe es keine einfache Möglichkeit, zwischen einem vorhandenen Objekt und dem Fehlen eines Objekts zu unterscheiden.

Ein typisches Beispiel: Wenn eine Methode ein Objekt sucht (z. B. einen Benutzer in einer Datenbank) und nichts findet, kann sie null zurückgeben. Der aufrufende Code erkennt dann: Es gibt kein Ergebnis, die Suche war erfolglos.

Klasse und Objekt

In Java bezeichnet

  • Klasse den Datentyp, der neu definiert wird (Vorlage für Objekte)
    • es gibt immer nur eine Klasse
    • Kfz im Beispiel
  • Objekt Instanzen der Klasse, in der Daten gespeichert werden können
    • es gibt beliebig viele Objekte von einer Klasse
    • Instanz, auf welche die Referenzen golf und opel im Beispiel zeigen
Kfz golf = new Kfz();
Kfz opel = new Kfz();

In der objektorientierten Programmierung beschreibt eine Klasse den Bauplan für Objekte. Sie legt fest, welche Eigenschaften (Attribute) und welches Verhalten (Methoden) ein Objekt haben kann. Eine Klasse ist also eine abstrakte Definition, die selbst noch kein konkretes „Ding“ im Speicher darstellt. Erst wenn eine Klasse instanziiert wird, entsteht ein Objekt, eine konkrete Ausprägung dieser Klasse.

Ein Objekt ist somit eine tatsächliche Instanz, die im Speicher angelegt wird und mit der man arbeiten kann. Es besitzt individuelle Werte für die in der Klasse definierten Attribute und kann die vorgesehenen Methoden ausführen. Während die Klasse also nur beschreibt, wie etwas aussehen und sich verhalten soll, ist das Objekt die greifbare Umsetzung dieses Bauplans.

Ein einfaches Beispiel wäre die Klasse Kfz, die beschreibt, dass jedes Auto eine Farbe hat und fahren kann. Erst wenn man sagt Kfz golf = new Kfz();, wird ein Objekt erzeugt, also ein konkretes Kfz. Dieses Objekt kann dann verwendet werden, etwa um es fahren zu lassen oder Eigenschaften auszulesen.

Zugriff auf Elemente

  • Punkt-Operator (.) erlaubt Zugriff auf die Attribute des Verbundes
  • Syntax: variable.ATTRIBUTNAME
  • wichtig: Variable darf nicht null sein
Kfz porsche = new Kfz();
porsche.leistung = 350;
porsche.vmax = 289;
porsche.gewicht = 1.455;

Kfz m6 = new Kfz();
m6.leistung = 507;
m6.vmax = 305;
m6.gewicht = 1.785;

Standardwerte

Werden Variablen (Attribute) eines Objektes nicht initialisiert, erhalten sie Standardwerte

  • Ganzzahlen: 0
  • Fließkommazahlen: 0.0
  • Wahrheitswerte: false
  • Referenzvariablen: null
Kfz auto = new Kfz();

System.out.println(auto.vmax); // -> 0
System.out.println(auto.gewicht); // -> 0.0

In Java erhalten Attribute (Instanzvariablen und Klassenvariablen), die nicht explizit initialisiert werden, automatisch sogenannte Standardwerte. Diese werden vom Java gesetzt, um sicherzustellen, dass alle Attribute vor der Verwendung einen definierten Zustand haben.

Die Standardwerte hängen vom Datentyp des Attributs ab:

Datentyp Standardwert
int, short, byte, long 0
float, double 0.0
char '\u0000' (Null-Zeichen)
boolean false
Objektreferenzen (z. B. String, eigene Klassen) null

Wichtig: Diese automatische Initialisierung gilt nur für Attribute, nicht für lokale Variablen in Methoden, diese müssen explizit initialisiert werden, bevor sie verwendet werden dürfen.

Verschachtelte Definitionen

Klassen können Attribute von Klassen sein

class Fuhrpark {
    Kfz porsche = new Kfz();
    Kfz m6 = new Kfz();
}

In der Klasse Fuhrpark wird gezeigt, dass Klassen in Java auch Attribute vom Typ anderer Klassen enthalten können. Das bedeutet, man kann innerhalb einer Klasse Objekte anderer Klassen als Attribute deklarieren und instanziieren.

  • porsche und m6 sind Attribute der Klasse Fuhrpark, genauer gesagt: Sie sind beides Referenzen auf Objekte vom Typ der Klasse Kfz.
  • Beim Anlegen eines Objekts vom Typ Fuhrpark werden automatisch zwei neue Kfz-Objekte erzeugt: eins für porsche und eins für m6. Dies geschieht nicht durch die Deklaration Kfz porsche bzw. Kfz m6, sondern durch das new Kfz() in der Zuweisung.
  • Da in der Klasse Kfz die Attribute (leistung, vmax, gewicht) nicht explizit initialisiert wurden, erhalten sie die Standardwerte:
  • leistung: 0 (int)
  • vmax: 0 (int)
  • gewicht: 0.0 (double)

Man sieht, dass Objekte komplex zusammengesetzt sein können: Eine Klasse (z. B. Fuhrpark) kann aus Objekten anderer Klassen (z. B. Kfz) bestehen, man spricht auch von einer Hat-ein-Beziehung (Komposition).

Fuhrpark fuhrpark = new Fuhrpark();

fuhrpark.porsche.leistung = 350;
fuhrpark.porsche.vmax = 289;
fuhrpark.porsche.gewicht = 1.455;

fuhrpark.m6.leistung = 507;
fuhrpark.m6.vmax = 305;
fuhrpark.m6.gewicht = 1.785;

Da die Objekte porsche und m6 jeweils mit ihren Standardwerten initialiisert wurden, muss man (so man sinnvolle Werte speichern will) nach dem Anlegen eines Objektes vom Typ Furhpark die Attribute setzen.

Die hier dargestellte Lösung ist relativ unelegant und wir werden später sehen, wie man durch Konstruktoren ein deutlich sauberes Programm realisieren kann. Außerdem kann man durch die Verwendung von Arrays dafür sorgen, dass die Anzahl der Autos im Fuhrpark variable sein kann.

Die Abbildung zeigt, wie sich die Daten im Speicher verteilen. Durch die Tatsache, dass fuhrpark, porsche und m6 Referenzvariabeln sind, weil sie von einem Referenzdatentyp sind, gibt es die entsprechenden Referenzen, welche durch die Pfeile angedeutet werden.


Copyright © 2025 Thomas Smits