Sie sind auf Seite 1von 30

Klassenmethoden

Ingenieurmäßiges Vorgehen in der SW-Erstellung:


• Ein großes Problem wird in Teilprobleme zerlegt.
• Wiederverwendung: Bestimmte (bekannte) Aufgaben lassen sich durch
vorgefertigte "Standardbausteine" erledigen.
Klassenmethoden
• zur Erledigung von Teilaufgaben.
• "abstrakte Befehle" der "Fabrik" (Klasse)
• Wiederverwendung (➔ eigene Bibliothek möglich).
• Lesbarkeit/Wartbarkeit.
Klassenvariablen
• zur Beschreibung der "Fabrik".
• Daten der Fabrik.
Für Anwender: Das WAS ist im Vordergrund. Das WIE ist unwichtig.
Für Entwickler: Beide Punkte sind wichtig.
Schlüsselwort: static
Tran / Hettel GDI 2 1
Klassenmethoden

Beispiel
public class Test
{
private static int sCounter = 0;
public static double f(double x, int n)
{
sCounter++;
double tmp = Math.pow(x,n);
return tmp;
}
}

Aufruf vom außerhalb der Klasse:


Test.f(5, 3); // Klassenname.Methodenname(Parameter)

Tran / Hettel GDI 2 2


Klassenmethoden

Daten der Fabrik


(private/public/protected/-)
static

von "außen" nur


Methoden der Fabrik
public static-Methoden
(private/public/protected/-)
sichtbar static

Tran / Hettel GDI 2 3


Klassenmethoden

Methoden
formale Parameter (Platzhalter)
tatsächliche Parameter

Wert parameter
double tmp;
tmp = a + b; Rückgabe
usw..
parameter
Wert

Parameterübergabe
lokale Variablen existieren nur
während der Methodenausführung

Tran / Hettel GDI 2 4


Klassenmethoden

Aufrufe

Methode f Methode g
{ {

f() g()

} }

Tran / Hettel GDI 2 5


Klassenmethode

Beispiel
public class Test
{
Parameter
public static long fakultaet(int n)
{
long result = 1; Lokale Variablen
for (int i = 2; i <= n; ++i) result *= i;
return result;
}
}

Aufruf vom außerhalb:


long a = Test.fakultaet(3); // OK
int b = Test.fakultaet(2); // Fehler
long c = Test.fakultaet(2.0); // Fehler
byte d = (byte) Test.fakultaet((byte) 2.3); // OK

Tran / Hettel GDI 2 6


Klassenmethode

Beispiel
Um einen int-Wert einzulesen schreibt man oft etwa

Scanner in = new Scanner(System.in);


int a;
System.out.println("Geben Sie bitte eine ganze Zahl ein");
a = in.nextInt();
in.close();

Was ist dabei schlecht?


• Man muss jedes Mal ein Scanner-Objekt erzeugen und es dann ,,zerstören’’
(teuer). Ein ,,globales‘‘ Objekt ist doch für eine Anwendung ausreichend.
• Es gibt keine Fehlerbehandlung. Was passiert, wenn der Benutzer falsch
eingibt?

Lösung: eigene Hilfsmethode.

Tran / Hettel GDI 2 7


Klassenmethode

Man legt eine Klasse an mit einem ,,globalen‘‘ Scanner-Objekt

public class ReadUtil


{
/**
* sIn wird verwendet, um von der Konsole einzulesen
*/
public static Scanner sIn = new Scanner(System.in);

Und schreibt eine Klassenmethode für das Einlesen eines int-Werts


public static int nextInt(String meldung)
{
// siehe nächste Seite
}

Der Anwender braucht dann nur noch zu schreiben:

int a = ReadUtil.nextInt("Geben Sie bitte eine ganze Zahl ein");

Tran / Hettel GDI 2 8


Klassenmethode

public static int nextInt(String meldung)


{
while (true) // solange kein vernünftiger Wert eingelesen wurde
{
try
{
System.out.println(meldung); // gibt die Meldung aus
var s = sIn.next(); // liest die Zahl als Zeichenkette ein
return Integer.parseInt(s); // und wandelt sie in int um
} catch (Exception ex)
{ // Falls Fehler vorkommt, gibt einen Hinweis aus und das Ganze
// wird wiederholt
System.out.println("Geben Sie bitte nur eine ganze Zahl zwischen "
+ Integer.MIN_VALUE + " und " + Integer.MAX_VALUE + " ein");
}
}
}
Vorteile:
• Wir müssen nicht mehr wissen, wie ein Scanner-Objekt angelegt und verwendet
wird.
• Jede Verbesserung der Methode führt dazu, dass alle Codes, die sie verwenden,
werden automatisch verbessert.
Tran / Hettel GDI 2 9
Klassenmethoden

Überladen von Methoden


Mehrere Methoden können den gleichen Namen haben, wenn ihre Parameterliste
unterscheidbar sind. D.h. wenn
• die Anzahlen der Parameter verschieden sind oder
• die Parameter unterschiedliche Typen haben.
Konzept von Signatur
Methodenname + Anzahl der Parameter + Typen der Parameter
Der Rückgabetyp wird zur Unterscheidung nicht verwendet.
Beispiel public static void doIt(int i) { ... }
public static void doIt(double d){ ... }
public static void doIt(double d, int i) { ... }

Der Compiler muss wissen, welche Methode auszuwählen ist.


Vermeiden Sie Methodenüberladung, wenn die Parameter kompatibel sind.

Tran / Hettel GDI 2 10


Klassenmethoden

Beispiel einer Überladung der Methode nextInt


Eine Hilfsmethode, um einen int-Wert aus einem Zahlenbereich einzulesen:
public static int nextInt(String meldung, int von, int bis)
{
while (true)
{
try
{
System.out.println(meldung);
var s = sIn.next();
var erg = Integer.parseInt(s);
if (erg >= von && erg <= bis)
return erg;
else
throw new Exception();
} catch (Exception ex)
{
System.out.println("Geben Sie bitte nur eine ganze Zahl zwischen "
+ von + " und " + bis + " ein");
}
}
}

Tran / Hettel GDI 2 11


Klassenmethoden

Parameterübergabe In Java können wir nur das Objekt weitergeben, indem


In Java "Wertübergabe". wir verraten, wo es liegt
Bei elementaren Datentypen werden die Werte kopiert.
Bei Objekten werden die "Adressen" der Objekte kopiert.
Wichtig Implizite Umwandlung wird ggf. durchgeführt.
Beispiel
public static void doIt(int i) { ... }
public static void doIt(float f){ ... }
public static void doIt(double d, int i) { ... }
...
byte b = 123; doIt(b) // OK byte -> int
long c = 3; doIt(c); // OK long -> float
doIt(2.0); // Fehler
doIt(1, 2L); // Fehler
doIt(2F); // OK

Tran / Hettel GDI 2 12


Klassenmethoden

Beispiel
Falsche Implementierung zum Tauschen zweier int-Werten
public static void swap(int a, int b)
{
var temp = a;
a = b;
b = temp;
}

Mögliche Lösung Über Objekt (hier über Array)


public static void swap(int[] a)
{
var temp = a[0];
a[0] = a[1];
a[1] = temp;
}

Tran / Hettel GDI 2 13


Klassenmethoden

In Java kann man die übergebenen Objekte nicht schützen.


public static void f(final int[] a) // a wird geschützt
{
...
a = new int[3]; // Fehler, a ist final!!
...
a[0] = 123; // Erlaubt
...
}

Man muss also ggf. mit einer Kopie oder mit einem Vermittler arbeiten.

Tran / Hettel GDI 2 14


Klassenmethoden

Rückgabewert
Es kann nur ein Wert bzw. ein Objekt mit der return-Anweisung
zurückgegeben werden. Um mehrere Objekte/Werte zurückzugeben, benutzt
man das Konzept der Parameter als Behälter.
Methode ohne Rückgabe muss void als Rückgabetyp deklarieren.
Beispiel
public static void printUsage()
{
out.println("Usage: java CTest Name");
}
public static int squareRoot(int i)
{
return (int) (Math.sqrt(i));
}

Tran / Hettel GDI 2 15


Klassenmethoden – Einige Syntaxfehler

Syntaktische Fehler beim Schreiben von Methoden


1) Partielle Methoden
Eine Methode muss, wenn sie einen Rückgabewert verspricht, auf jeden Fall einen
Wert zurückliefern.
Beispiel (fehlerhafte Implementierung)

public static int squareRoot(int i)


{
if (i >= 0)
{
return (int) (Math.sqrt(i));
}
}

Was passiert, wenn i negativ ist?

Tran / Hettel GDI 2 16


Klassenmethoden

Verschiedene Abhilfen bei falscher Übergabe von Parametern


1) Terminieren bei einer falschen Eingabe
public static int squareRoot(int i)
{
if (i < 0)
{
System.exit(1); // 1 ist der Fehlercode
}
return (int) (Math.sqrt(i));
}

=> Unschön: Nicht jeder Fehler darf zum Programmabbruch führen!

Tran / Hettel GDI 2 17


Klassenmethoden

2) Rückgabe von Dummy-Werten


public static int squareRoot(int i)
{
if (i < 0)
{
return –1;
}
return (int) (Math.sqrt(i));
}

➔ Woher sollen die anderen Programmierer wissen, dass -1 illegal ist. -1 ist auch
ein int-Wert wie alle anderen!

Tran / Hettel GDI 2 18


Klassenmethoden

3) Ausnahmen werfen
public static int squareRoot(int i)
{
if (i < 0)
{
throw new IllegalArgumentException("wrong param " + i);
}
return (int) (Math.sqrt(i));
}

➔ Programmabsturz mit einer genauen Angabe vom Grund. Der Programmierer


kann seinen Benutzungsfehler korrigieren.

Tran / Hettel GDI 2 19


Klassenmethoden

4) „assert" (Zusicherung) einbauen (ab Java 1.4)

public static int squareRoot(int i)


{
assert (i >= 0) : "squareRoot mit einem negativen Wert";
return (int) (Math.sqrt(i));
}

Design by contract.

Syntax:
assert Bedingung [: Meldung]
Beim Ausführen muss man assert aktivieren (enable assert) : java -ea

Tran / Hettel GDI 2 20


Klassenmethoden – Syntaktische Fehler

2) Unerreichbare Codes
public static int f(int i) {
if (i < 0) {
throw new IllegalArgumentException("wrong param " + i);
return 0; // Fehler !!!! unerreichbar
}
return 1;
}

3) Nicht initialisierte lokale Variablen


Initialisieren Sie stets
public static int f(int i) { alle lokalen Variablen !
int r;
if (i < 0) {
r = 1; // .. weiter Befehle
}
return r; // Kompilierfehler weil r evtl. nicht
} // initialisiert ist.

Tran / Hettel GDI 2 21


Klassenvariablen und -objekte

• zur Beschreibung und zum Merken der Fabrikdaten.


• werden wie lokale Variablen/Objekte deklariert (mit der static-Angabe).
• können Modifizierer wie public/private haben.
• dürfen überall in der Klasse (außerhalb der Methoden) deklariert werden.
• können von allen Methoden in der Klasse zugegriffen werden.
• existieren bis zum Programmende (die Fabrik wird beim Laden der Klasse
gebaut).
• Werte bzw. Objekte der Klassenvariablen bleiben über Methodenaufrufe
hinweg erhalten.
• Man kann Klassenvariablen als Variablen für Übergabewerte missbrauchen. Es
ist aber abzuraten (fehlerträchtig).

Tran / Hettel GDI 2 22


Klassenvariablen und -objekte

Klassenvariablen können lokal verdeckt werden (auch Quellen von Fehlern).


Klassenvariablen können qualifiziert (mit dem Klassennamen) angegeben
werden:
public class ShadowingDemo1 {
private static int a = 1;
public static void main(String[] args) {
out.println(a); // Ausgabe 1
int a = 2;
out.println(a); // Ausgabe 2
}
}
public class ShadowingDemo2 {
private static int a = 1;
public static void main(String[] args) {
out.println(a); // nichtqualifizierter Name Ausgabe 1
var a = 2;
out.println(a); // Ausgabe 2
out.println(ShadowingDemo2.a); // Qualifizierte Angabe
// Ausgabe 1
}
}

Tran / Hettel GDI 2 23


Klassenvariablen und -objekte

static –Initialisierung wird benötigt, um komplexe Klassenobjekte zu


initialisieren:
public class StaticInitDemo {
private static final int MAX_SIZE = 100;
private static int[] sQuadratTable;
static {
sQuadratTable = new int[MAX_SIZE];
for (var i = 0; i < MAX_SIZE; ++i)
sQuadratTable[i] = i*i;
}
public static int get(int i) {
if (i < MAX_SIZE) return sQuadratTable[i];
else return i*i;
}
}

- Mehrere static -Blöcke sind möglich (wird von Compiler zu einem großen
zusammengefasst).
- Reihenfolgen der Blöcke sind relevant.
Tran / Hettel GDI 2 24
Klassenvariablen und -objekte

Andere Möglichkeit: Missbrauch von Exception (wird auch in der Praxis


angewendet) – Muster: Lazy Initialization

public class VersionMitException {


private static final int MAX_SIZE = 100;
private static int[] sQuadratTable;
public static int get(int i) {
if (i < MAX_SIZE)
{
try { return sQuadratTable[i];}
catch (Exception ex)
{
sQuadratTable = new int[MAX_SIZE];
for (var idx = 0; idx < MAX_SIZE; ++idx)
sQuadratTable[idx] = idx*idx;
return sQuadratTable[i];
}
}
else return i*i;
}
}

Tran / Hettel GDI 2 25


Rekursive Methoden

Eine Methode, die sich selbst (direkt oder indirekt) aufruft, ist rekursiv.
Die Natur der Rekursion
Charakteristiken:
Ein oder mehrere einfache Fälle existieren, für die eine (nicht rekursive) Lösung
bekannt ist.
Das Problem lässt sich lösen, wenn ein "kleineres" (reduziertes) Problem gelöst
wurde.
Häufige Struktur
if (Spezialfälle eingetreten)
Löse das Problem
else
Löse reduzierte Probleme und verwende die Ergebnisse, um
das Problem zu lösen

Tran / Hettel GDI 2 26


Rekursive Methoden

Beispiel: Fakultät.
Aus der Mathematik:

public static long fakultaet(int n)


{
assert (n >= 0);
if (n == 0 || n == 1)
{
return 1;
}
else
{
return n*fakultaet(n-1);
}
}

Tran / Hettel GDI 2 27


Rekursive Methoden

Beispiel: Fibonacci-Zahlen.
Aus der Mathematik:

public static long fibo(int n)


{
assert (n >= 1);
if (n == 1 || n == 2)
{
return 1;
}
else
{
return fibo(n-1) + fibo(n-2);
}
}

Tran / Hettel GDI 2 28


Rekursive Methoden

Beispiel - Turm von Hanoi

public static void move(int n, int from, int to, int help)
{
if (n == 1)
{
System.out.println("move from " + from + " to " + to);
}
else
{
move(n-1, from , help, to);
System.out.println("move from " + from + " to " + to);
move(n-1, help, to, from);
}
}

Tran / Hettel GDI 2 29


Rekursive Methoden

Rekursive oder iterative Lösung?


Jedes rekursive Problem lässt sich auch iterativ lösen.
Iterative Lösung oft schneller, der Code dafür aber meist länger und schwerer zu
verstehen.
Häufige Anwendung von rekursiven Methoden: Dynamische Datenstrukturen
(siehe ALDS-Vorlesungen).

Tran / Hettel GDI 2 30