Home > Informatik > Einführung in die OOP > 2. Klasse Waage > 2.1 Die Klasse Waage

2.1 Die Klasse Waage

In der vorhergehenden Einheit haben Sie erste eigene Klassen und Methoden in Java entwickelt. Nun setzen wir diese Grundlagen fort – allerdings nicht mit grafischer Benutzeroberfläche, sondern mit sogenannten Konsolenprogrammen. So können wir uns auf die zentralen Sprachkonzepte von Java konzentrieren.

Im Rahmen einer Hochschul-Ausbildung liegt der Schwerpunkt zunächst auf solider Modellierung und methodischem Vorgehen. An Hochschulen wird anfangs meist ohne Oberflächen gearbeitet, da die Konzepte von Klassen, Objekten, Attributen und Methoden im Vordergrund stehen.

Inhalt dieser Seite

2.1.1 Die erste Version der Klasse Waage

Schritt 1: Anlegen des neuen Projekts

⇒ Legen Sie ein neues BlueJ-Projekt mit dem Namen "Waage-1"an.

Schritt 2: Erstellung der Klasse Waage

⇒ Erzeugen Sie in diesem Projekt dann eine neue Klasse Waage.

Hinweis: Eine saubere Ordnerstruktur erleichtert langfristig die Wiederverwendung und das Refactoring von Code. Verwenden Sie klare Projekt- und Versionsnamen.

Hinweis zur Versionsverwaltung

Führen Sie bei größeren Änderungen des Projekts stets eine Sicherung mit Sichern unter... durch. So können Sie jederzeit auf eine funktionierende Zwischenversion zurückgreifen.

Im professionellen Umfeld gibt es natürlich richtige Projektverwaltungssysteme, die alle Veränderungen protokollieren, so dass man jederzeit zu einer älteren Version zurückkehren kann. Mit solchen professionellen Anwendungen werden Sie sich in den höheren Semestern beschäftigen. Für Einsteiger(innen) sind solche Systeme allerdings zu kompliziert, sie lenken von der eigentlichen Programmierarbeit zu stark ab.

Schritt 3: Erstellung der Klasse Waage

⇒ Öffnen Sie die Klasse Waage im Editor und ersetzen Sie den automatisch generierten Quelltext durch diesen Minimal-Quelltext:

Beschreibung siehe folgenden Text

Der Minimal-Quelltext der Klasse Waage
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Der Minimal-Quelltext besteht aus der Klasse mit einem Konstruktor.

Für Fortgeschrittene: Wenn der Konstruktor so wie in diesem Beispiel nichts weiter macht, kann er auch komplett weggelassen werden. Der Compiler setzt dann bei der Übersetzung einen Standard-Konstruktor ein.

Schritt 4: Die erste Instanzvariable

⇒ Fügen Sie nun die Instanzvariable double gewicht hinzu.

Die Instanzvariable gewicht repräsentiert das Attribut Gewicht in der Java-Klasse. Der Datentyp double erlaubt die Speicherung von Gleitkommazahlen. Für ein realistisches Modell einer Personenwaage ist dies erforderlich, damit man auch Gewichte wie 78.3 kg verwalten kann.

⇒ Erzeugen Sie ein Objekt dieser Klasse und überprüfen Sie es mit dem Objektinspektor.

Schritt 5: Die erste Setter-Methode

In der Folge 1.4 hatten wir uns bereits mit Setter- und Getter-Methoden beschäftigt. Für die Klasse Waage benötigen wir nun eine Setter-Methode zur Gewichtserfassung.

⇒ Fügen Sie der Klasse die Methode setGewicht(double gewicht) hinzu.

public void setGewicht(double gewicht)
{
   this.gewicht = gewicht;
}

Hier sehen Sie, dass der Parameter gewicht denselben Namen trägt wie die Instanzvariable gewicht. Um Missverständnisse zu vermeiden, wird bei der Zuweisung das Schlüsselwort this verwendet. Damit ist eindeutig klar: Gemeint ist die Instanzvariable des aktuellen Objekts.

Vielleicht wundern Sie sich, warum der Parameter hier nicht pGewicht heißt. In den Abituraufgaben des Landes NRW ist es üblich, alle Parameter mit dem Präfix 'p' zu versehen (z. B. pGewicht). Auf diese Weise soll sofort erkennbar sein, ob es sich bei einem Namen um einen Parameter handelt. Konsequent durchgeführt wird dieses Verfahren im NRW-Abitur allerdings nicht, denn nach dieser Logik müssten alle lokalen Variablen mit einem 'l' beginnen und alle Instanzvariablen mit einem 'i'.

Im professionellen Umfeld wird oft eine andere Konvention bevorzugt: Parameter dürfen denselben Namen tragen wie die zugehörigen Instanzvariablen. Wichtig ist nur, dass Sie in der Methode dann konsequent das Schlüsselwort this verwenden, wenn auf die Instanzvariable zugegriffen wird.

Schritt 6: Die zweite Setter-Methode

⇒ Ergänzen Sie das Attribut double groesse und eine entsprechende Setter-Methode.

Zusammenfassung der Schritte 1 bis 6

Beschreibung siehe folgenden Text

Zusammenfassung der Schritte 1 bis 6
Autor: Ulrich Helmich 2025, Lizenz: Public domain

⇒ Testen Sie mithilfe des Objektinspektors, ob die beiden Setter-Methoden korrekt funktionieren.

2.1.2 Exkurs: Datenkapseln und Information Hiding

Beschreibung siehe folgenden Text

Das Schlüsselwort private

Was bedeutet eigentlich das Schlüsselwort private bei der Deklaration der Instanzvariablen gewicht und groesse?

Beschreibung siehe folgenden Text

Eine Datenkapsel als Black Box
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Dieses Bild soll das Prinzip der Datenkapselung oder des Information Hiding verdeutlichen

Durch das "Verstecken" der Instanzvariablen gewicht und groesse mit Hilfe des Zugriffsmodifizierers private kann von außerhalb der Klasse bzw. der Objekte dieser Klasse nicht auf die Instanzvariablen zugegriffen werden. Das ist so, als ob sie in einem schwarzen Kasten versteckt wären (Black Box - Prinzip oder Information Hiding).

Nur mit Hilfe bestimmter Getter- und Setter-Methoden ist ein Zugriff auf diese Instanzvariablen möglich. Getter-Methoden liefern Informationen über die Werte dieser Variablen, und Setter-Methoden können diese Werte ändern.

Zwei Setter-Methoden für die Klasse Waage haben Sie eben ja bereits geschrieben (Schritte 5 und 6).

2.1.3 Exkurs: Der Ausgabe-Befehl println()

Bevor wir mit der Klasse Waage weitermachen, wollen wir uns einen der wichtigsten Befehle für die Konsolen-Ausgabe anschauen, den Befehl println() der Java-Klasse System.

Beschreibung siehe folgenden Text

Der println()-Befehl

Dieses Bild zeigt verschiedene Anwendungen des Befehls System.out.println().

  1. In dem ersten Beispiel wir ein einfacher String ausgegeben: "Hallo Welt!".
  2. Das zweite Beispiel zeigt, wie man eine einfache Zahl ausgibt.
  3. Der dritte Beispiel demonstriert, wie man eine Meldung wie "Sinn des Universums ist 42" ausgibt, also einen String, gefolgt von einer Zahl.
  4. Das vierte Beispiel schließlich könnte für die Erweiterung der Klasse Waage interessant sein, wenn Sie Meldungen wie "Ihr Gewicht beträgt 78.3 kg" ausgeben wollen.
Schritt 7: Ausgabe der Attribute

⇒ Ergänzen Sie die Klasse Waage um eine Ausgabe-Methode, in der das Gewicht und die Körpergröße auf der Konsole angezeigt werden.

Beschreibung siehe folgenden Text

Ausgabe der beiden Instanzvariablen

Schritt 8: Formatierte Ausgabe der Attribute

⇒ Ersetzen Sie die normale Ausgabe aus Schritt 7 durch eine formatierte Ausgabe, wie sie im folgenden Bild gezeigt wird.

Beschreibung siehe folgenden Text

Der printf()-Befehl
Autor: Ulrich Helmich 09/2025, Lizenz: Public domain

Wenn Sie alles richtig gemacht haben, müsste die Ausgabe der Zahlen rechtsbündig sein mit max. 3 Vorkommastellen, einem Dezimalpunkt und 2 Nachkommastellen.

Die Formatierungsanweisung %6.2 besagt genau das: Insgesamt 6 Stellen, davon zwei Nachkommastellen.

Die Formatierungsanweisung ist auch gleichzeitig ein Platzhalter. An die Stelle der Formatierungsanweisung wird bei der Konsolen-Ausgabe dann die eigentliche Zahl eingesetzt, die am Ende des Ausgabestrings durch ein Komma abgetrennt steht.

Die zweite Formatierungsanweisung %n bewirkt einen Zeilenumbruch. Im Gegensatz zum println()-Befehl erzeugt der printf()-Befehl nämlich keinen automatischen Zeilenumbruch.

2.1.4 Die zweite Version der Klasse Waage

Bisher haben wir die Methoden der Klasse Waage mit der linken Maustaste aufgerufen, wenn wir auf das erzeugte Objekt der Klasse geklickt haben. Auf die Dauer ist das aber recht lästig, und es gibt mehrere Wege, wie man das vereinfachen kann.

Alternative a) Methodenaufrufe im Konstruktor

Beschreibung siehe folgenden Text

Die Methoden werden hier im Konstruktor aufgerufen (Version 8a)
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Dieses Bild zeigt die einfachste Möglichkeit, sich das ständige Mausklicken zu ersparen. Die drei Methoden, die wir bisher implementiert haben, werden einfach von dem Konstruktor aufgerufen. Wenn wir also mit der Maus in BlueJ ein neues Objekt der Klasse anlegen, wird der Konstruktor ausgeführt, und dieser ruft dann die drei Methoden für uns auf.

Methodenaufrufe im Konstruktor erleichtern zwar die Arbeit mit BlueJ, sind aber nicht sehr professionell.
Der Konstruktor sollte nur die Instanzvariablen initialisieren oder Methoden aufrufen, die Initialisierungs- oder Start-Aufgaben übernehmen.

Alternative b) Eine eigene run()-Methode

Beschreibung siehe folgenden Text

Die Methoden werden hier von einer run()-Methode aufgerufen (Version 8b)
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Diese Möglichkeit entlastet den Konstruktor. Instanzvariablen werden hier zwar nicht initialisiert, aber er ruft die run()-Methode auf. Diese wiederum ruft die drei zu testenden Methoden auf. Diese Alternative ist schon viel besser und professioneller als die Alternative a) - aber es geht noch besser.

Alternative c) Eine eigene Test-Klasse

Beschreibung siehe folgenden Text

Die Methoden der Waage werden von einer Testklasse überprüft (Version 8c)
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Hier sehen wir eine noch bessere Möglichkeit, die Methoden der Klasse Waage zu testen. Wir schreiben uns eine eigene Testklasse, die ein Objekt der Klasse Waage anlegt und dann die Methoden aufruft.

Alternative d) Eine Test-Klasse mit einer main()-Methode

Beschreibung siehe folgenden Text

Die Methoden der Waage werden von einer Testklasse überprüft (Version 8d)
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Das hier ist sicherlich die professionellste Methode, eine Klasse zu testen - abgesehen von speziellen Test-Units, aber das ist wieder ein anderes Kapitel.

Alle "richtigen" Java-Apps werden über eine main()-Methode gestartet. Diese regelt dann den Aufruf der Objekte und deren Methoden. Wenn Sie eine solche Klasse mit BlueJ kompilieren, dürfen Sie nicht den new-Operator wählen (erster Eintrag in dem Kontext-Menü), sondern müssen die main()-Methode auswählen.

Man kann der main()-Methode eine ganze Reihe von Parametern übergeben, die alle vom Datentyp String sein müssen. Darauf gehen wir jetzt aber noch nicht ein.

Schritt 9: main()-Methode ergänzen

⇒ Ergänzen Sie das Java-Projekt durch eine Testklasse mit einer main()-Methode, in der die Methoden der Klasse Waage getestet werden.

2.1.5 Exkurs Dialogboxen in Java

Dieser Exkurs ist für die fortgeschrittenen Kursteilnehmer gedacht. Die Leute, denen dieses Thema zu komplex ist, können diesen Abschnitt gern überspringen und gleich mit 2.1.6 weitermachen. Klausurrelevant sind Dialogboxen nicht!

Betrachten Sie folgenden Quelltext:

Beschreibung siehe folgenden Text

Die Daten werden über Dialogboxen eingegeben

Wir binden in unsere Testklasse ein Objekt der Klasse JOptionPane ein, damit wir die Methode showInputDialog() dieser Klasse verwenden können.

ChatGPT zu JOptionPane:

Die Klasse JOptionPane gehört zum Paket javax.swing und dient in Java zur einfachen Ein- und Ausgabe über Dialogfenster. Sie ist Teil des Swing-Frameworks, das für die Erstellung grafischer Benutzeroberflächen (GUIs) verwendet wird.

Die Hauptaufgabe von JOptionPane besteht darin, Standarddialoge bereitzustellen, die ohne großen Programmieraufwand verwendet werden können. Dabei handelt es sich um Fenster, die vom Betriebssystem unabhängig funktionieren und plattformübergreifend ein einheitliches Verhalten zeigen.

Wen Sie Lust haben, können Sie ja selbst mal recherchieren, welche Möglichkeiten diese Klasse bietet. Wir benötigen für unser Projekt Waage nur die eine Methode showInputDialog().

String showInputDialog(String message)

Das ist die Syntax dieser Methode. An die Methode wird ein String übergeben, der in der Dialogbox erscheint, also beispielsweise "Bitte Gewicht in kg eingeben: ". Die Methode liefert dann einen String zurück, nämlich das, was der Benutzer des Programm in die Dialogbox eingetippt hat, die in BlueJ so aussieht:

Beschreibung siehe folgenden Text

So sieht ein showInputDialog in BlueJ aus

Unsere Setter-Methoden setGewicht() und setGroesse() können mit einem String natürlich nichts anfangen, sie erwarten als Parameter eine double-Zahl. Wir müssen den String, den die Dialogbox liefert, also erst in eine double-Zahl umwandeln. Dies geschieht mit der Methode parseDouble() der Klasse Double.

Die Klasse Double gehört zu den sogenannten Wrapper-Klassen. Primitive Datentypen wie double stellen bekanntlich keine Methoden zur Verfügung. Die Wrapper-Klasse Double ist sozusagen ein "Mantel" oder eine "Hülle" für den Datentyp double, und dieser Mantel stellt jetzt zusätzliche Methoden für den Umgang mit double-Variablen zur Verfügung.

       double gewicht = Double.parseDouble(gText);
       double groesse = Double.parseDouble(hText);

       waage.setGewicht(gewicht);
       waage.setGroesse(groesse);

Die beiden ersten Zeilen dieses Quelltext-Ausschnitts zeigen die Umwandlung der String-Variablen gText und hText in double-Variablen gewicht und groesse. Diese double-Variablen können dann als Parameter in die beiden Setter-Methoden eingesetzt werden.

Achtung: Die beiden lokalen Variablen heißen hier genau so wie die beiden Instanzvariablen der Klasse Waage. Das macht durchaus Sinn, ist aber nicht zwingend. Man hätte die Variablen auch durchaus anders bezeichnen können, was aber vielleicht auch für Verwirrung gesorgt hätte.

Schritt 10: Dialogboxen einbauen

⇒ Bauen Sie diese Dialogboxen in Ihre Testklasse ein.

Anmerkung zu den Dialogboxen:

Dialogboxen sind eine nette Sache, wenn der Benutzer oder die Benutzerin zur Laufzeit des Programms tatsächlich Daten eingeben soll. Die Aufgabe des Testprogramms bzw. der Testklasse ist allerdings eine andere. Sie soll die Methoden der Klasse Waage testen. Und dafür ist es vielleicht komfortabler für die Benutzer, wenn sie nicht ständig Daten in die aufpoppenden Dialogboxen eintippen müssen. Das heißt, Sie können zum Testen der Klasse gern wieder die vorherige Version der Testklasse verwenden, bei der die Methoden der Waage direkt mit Parametern aufgerufen werden, ohne die Dialogboxen. Die Dialogboxen hatten wir nur eingeführt, um mal das Prinzip kennenzulernen. Wenn Sie also meinen, dass Sie mal eine Eingabebox brauchen, schauen Sie hier noch einmal nach, wie das geht.

2.1.6 Die dritte Version der Klasse Waage

Schritt 11: Drei Getter-Methoden

⇒ Ergänzen Sie die Waage um diese drei Getter-Methoden:

Drei Getter-Methoden
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Dieses Bild zeigt drei Getter-Methoden der Klasse Waage. Zwei dieser Getter-Methoden liefern direkt den Wert der entsprechenden Instanzvariable zurück, man könnte diese Getter-Methoden auch als "direkte Getter-Methoden" bezeichnen; üblicher ist aber der Begriff "echte Getter-Methoden".

Die Getter-Methode getIdealgewicht() dagegen liefert nicht den Wert einer Instanzvariablen zurück, sondern berechnet daraus einen anderen Rückgabewert, in diesem Fall das Idealgewicht der Person. Solche Getter-Methoden könnte man als "indirekte Getter-Methoden" bezeichnen, in der Fachliteratur spricht man aber meistens von "berechnenden Getter-Methoden".

Rückblick auf das Shapes-Projekt

Die Klasse Circle aus dem Shapes-Projekt kann um einige selbst geschriebene Getter-Methoden ergänzt werden:

  • getDiameter() liefert den Durchmesser eines Kreis-Objektes als int-Wert zurück. Es handelt sich hierbei um eine echte Getter-Methode, die den Wert der Instanzvariable diameter zurückliefert.
  • getColor() liefert die Farbe des Kreis-Objektes als String zurück. Auch dies ist eine echte Getter-Methode.
  • getArea() liefert den Flächeninhalt eines Kreis-Objektes als double-Wert zurück. Dies ist eine berechnende Getter-Methode, da es keine Instanzvariable für den Flächeninhalt gibt. Dieser muss aus der Instanzvariable diameter berechnet werden.

2.1.7 Exkurs: Instanzvariablen und Attribute

Noch eine kleine aber wichtige Ergänzung zu Instanzvariablen und Getter-Methoden. In der Fachliteratur wird oft nicht zwischen Instanzvariablen und Attributen unterschieden. Manchmal werden beide Begriffe gleichgesetzt, manchmal wird hier differenziert.

Auf meiner Homepage und in meinen Präsentationen unterschiede ich zwischen diesen beiden Begriffen, und das möchte ich Ihnen an dem Beispiel des bisher besprochenen Quelltextes einmal klar machen.

Attribute sind die Eigenschaften eines Objektes. Das Objekt Waage hat in der bisherigen Version drei solcher Eigenschaften: Gewicht, Körpergröße und Idealgewicht. Das sind die Attribute der Klasse Waage bzw. der Objekte dieser Klasse.

Realisiert werden diese drei Attribute durch zwei Instanzvariablen: gewicht und groesse.

Das Attribut Gewicht wird durch die Instanzvariablegewicht realisiert, das Attribut Körpergröße durch die Instanzvariable groesse, und das Attribut Idealgewicht durch eine mathematische Berechnung aus der Instanzvariable groesse ermittelt.

Beschreibung siehe folgenden Text

Instanzvariablen und Attribute
Autor: Ulrich Helmich 2025, Lizenz: Public domain

2.1.8 Exkurs: Der printf()-Befehl, Fortsetzung

Im nächsten Bild sehen wir eine neue Formatierungsanweisung: %-13s. Diese Anweisung bewirkt, dass der String in dem printf()-Befehl mit 13 Stellen ausgegeben wird. Sollte der String weniger Stellen haben als 13, dann wird er mit Leerzeichen aufgefüllt.

Beschreibung siehe folgenden Text

Der printf()-Befehl
Autor: Ulrich Helmich 2025, Lizenz: Public domain

Schritt 12

⇒ Passen Sie die ausgeben()-Methode der Klasse Waage entsprechend an.

Schritt 13

⇒ Ergänzen Sie die Klasse Waage um eine Methode getDifferenz(), welche die Differenz zwischen dem tatsächlichen Gewicht und dem Idealgewicht zurückgibt: Gewicht - Idealgewicht.

⇒ Ergänzen Sie die ausgeben()-Methode der Klasse Waage, so dass auch diese Differenz angezeigt wird.

Schritt 14

⇒ Ergänzen Sie die Klasse Waage um eine Methode getBMI(), welche den Bodymass-Index als double-Zahl zurückliefert. Lassen Sie den BMI in der ausgeben()-Methode mit anzeigen.

Der BMI berechnet sich aus dem Gewicht der Person in kg geteilt durch das Quadrat der Körpergröße in Metern.

Beispiel

Gewicht = 80 kg, Größe = 180 cm. BMI = 80 / 1.82 = 24,69 kg/m2.

Seitenanfang
Weiter mit der if-else-Anweisung ...