wiki:Skript/2. Java/ 5. Methoden

Version 9 (modified by tr, 8 years ago) (diff)

--

Methoden

Eine Methode ist ein geschlossenes Stück Programmcode, das wiederkehrende Aufgaben mit demselben Algorithmus löst. Durch die Verwendung von Methoden lässt sich Redundanz vermeiden.

Eine Methode besteht aus einem Methodenkopf und einem Methodenrumpf. Alle Methoden, die nicht den Rückgabetyp void haben, müssen mittels return einen wert vom Rückgabetyp zurückliefern. Tatsächlich ist void kein in Java existierender Datentyp sondern nur eine Kennzeichnung für "nichts".

Allgemeine Form
sichtbarkeit [static] [final] rueckgabetyp methodenname(Parameterliste) {
  Anweisungsblock
}

Bedeutung der einzelnen Elemente:

  • Sichtbarkeitsattribut: gibt an, wo die Methode verwendet werden kann. Möglich sind die vier Werte public, protected, private sowie ohne Angabe. Details siehe Objektorientierte Programmierung
  • static, optional: Die Methode ist eine Klassenmethode und kann keine Attribute von Objekten verändern.
  • final, optional: Die Methode ist final und kann nicht überschrieben werden. Details siehe Objektorientierte Programmierung
  • Rückgabetyp: jeder beliebige Typ oder void. Falls etwas anderes als void angegeben wird, muss die Methode einen Wert des angegebenen Typs mittels return zurückliefern.
  • Parameterliste: besteht aus kommagetrennten Paaren aus Typ und Name, z. B.: int xm, int ym, int radius. Die Parameter sind Variable, die der Methode vom aufrufenden Programmteil übergeben werden, damit die Methode ihre Aufgabe erfüllen kann. Die entsprechenden Werte sind in der Methode unter den in der Parameterliste aufgeführten Namen verfügbar. Zuweisungen an Parameter innerhalb der Methode haben keinen Einfluss auf Variable im aufrufenden Programmteil, sofern es sich um primitive Datentypen handelt.

Signatur

Die Signatur ist ein Teil des Methodenkopfes und besteht aus dem Methodennamen und der Parameterliste. Der Rückgabetyp ist kein Bestandteil der Signatur.

In ein und derselben Klasse darf es nicht mehrere Methoden mit derselben Signatur geben, da der Compiler sonst Methodenaufrufe nicht eindeutig zuordnen könnte.

Externe Sicht und interne Sicht

Bei der Entwicklung von Software gibt es zwei Sichten auf Methoden. Die externe Sicht auf eine Methode spiegelt deren Verwendung wider: Entwickler wissen nicht zwingend, wie die Methode intern aufgebaut ist, kennen aber deren Signatur und eine Funktionsbeschreibung. Beispiel dafür sind die Methoden der Java API. In der externen Sicht kann eine Methode als Black-Box aufgefasst werden, deren Eingabedaten, Ausgabedaten und Zweck bekannt, deren konkrete Implementierung jedoch unbekannt ist.

Beispiel
// Verwendung der Methode sqrt aus der Klasse java.lang.Math
// Externe Sicht: wir wissen nicht, wie sqrt implementiert ist
double r = Math.sqrt(42);

// Verwendung der Methode fakultaet, nicht aus java.lang.Math sondern aus dieser
// Klasse, in der wir sie verwenden (s. u.)
// wir wissen zwar, wie fakultaet implementiert ist (s. u.), nehmen an dieser
// Stelle aber die externe Sicht ein, da wir die Methode verwenden.
int x = fakultaet(4);

Die interne Sicht auf eine Methode spiegelt deren Implementierung wider: Entwickler haben ein konkretes fachliches Problem, für dessen Lösung sich eine Methode anbietet. Es wird definiert,

  • welche Daten für die Lösung notwendig sind (daraus entsteht die Parameterliste),
  • von welchem Typ der Rückgabewert ist,
  • wie die Methode heißen soll (spiegelt üblicherweise das fachliche Problem wider).
Beispiel
// Methode zur Berechnung der Fakultät einer Ganzzahl n
public static int fakultaet(int n) {
  // Zwischenergebnis
  int f = 1;

  for (int i = 1; i <= n; i++) {
    f = f * i;
  }

  // Rückgabe des Ergebnisses an den Aufrufer
  return f;
}

Bei der Entwicklung von Programmen findet häufig eine Vermischung von interner und externer Sicht statt: man programmiert eine Methode, die man in einem anderen Programmteil dann verwendet.

Beispiel
import java.util.Scanner;

public class Beispiel {

  // Methode zur Berechnung der Fakultät einer Ganzzahl n
  public static int fakultaet(int n) {
    // Zwischenergebnis
    int f = 1;

    for (int i = 1; i <= n; i++) {
      f = f * i;
    }

    // Rückgabe des Ergebnisses an den Aufrufer
    return f;
  }

  public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);

    System.out.print("Geben Sie eine Zahl ein: ");
    int x = scan.nextInt();

    System.out println(x + "! = " + fakultaet(x));
  }
}

Im obigen Beispiel sieht man bei der Ausgabe mit println auch, dass Methoden in Ausdrücken überall dort verwendet werden können, wo ein Wert stehen darf, der vom Rückgabetyp der Methode ist. Es ist also nicht erforderlich, dass der Rückgabewert immer einer Variablen zugewiesen wird, sondern der Rückgabewert kann auch implizit in einem Ausdruck verwendet werden.

Ausgabe vs. Rückgabe

Im Zusammenhang mit Methoden ist zwischen den Begriffen Ausgabe und Rückgabe zu unterscheiden:

  • Ausgabe: Eine Ausgabe ist eine Information, die dem Benutzer bereitgestellt wird. Beispiele dafür sind Ausgaben auf der Konsole mittels System.out.print... oder die Anzeige von Daten in einer grafischen Benutzeroberfläche.
  • Rückgabe: Ein Rückgabewert ist eine Information, die zwischen zwei Programmteilen ausgetauscht wird. Üblicherweise ist dies für den Benutzer nicht erkennbar. Konkret handelt es sich bei der Rückgabe von Werten um die Übermittlung des Ergebnisses einer Operation (z. B. Berechnung) an einen Programmteil, der diese Operation initiiert (eine Methode aufgerufen) hat. Methoden geben Rückgabewerte mit Hilfe des Schlüsselwortes return zurück.

lokaler Scope

Variable gelten in Java nur in dem Block, in dem sie deklariert wurden. Dies gilt ebenso für Methoden. In Methoden gibt es zwei verschiedene Arten von lokalen Variablen: Parameter und lokal definierte Variable:

// Methode zur Berechnung der Fakultät einer Ganzzahl n
// n ist der formale Parameter der Methode. Er wird innerhalb der Methode wie eine normale Veriable verwendet.
public static int fakultaet(int n) {
  // Zwischenergebnis
  // f ist eine normale Variable, die nur innerhalb der Methode existiert.
  int f = 1;

  for (int i = 1; i <= n; i++) {
    f = f * i;
  }

  // Rückgabe des Ergebnisses an den Aufrufer
  return f;
}

Methoden können die Werte von Parametern verändern, indem sie ihnen Werte zuweisen. Sofern es sich um primitive Typen handelt, hat dies keinen Einfluss auf Variable außerhalb der Methode. Eine Methode kann Variable von primitiven Typen, die außerhalb der Methode deklariert wurden, nicht verändern. Man spricht dabei von call-by-value: Beim Aufruf der Methode wird vom außerhalb der Methode befindlichen Wert eine Kopie angelegt und der Methode zur Verfügung gestellt. Die Methode hat ausschließlich Zugriff auf diese Kopie. Deswegen haben die Namen von Parametern nur lokale Bedeutung: Ein konkreter Parameter kann denselben Namen wie oder einen anderen Namen als ein formaler Parameter tragen: Es wird keine Verbindung zwischen den Werten innerhalb und außerhalb der Methode hergestellt.

Unabhängig davon ist es schlechter Stil, wenn man Parameter von primitiven Typen innerhalb einer Methode ändert. Man sollte statt dessen eine zusätzliche Hilfsvariable verwenden.

Beispiel für formale und konkrete Parameter
// Methode zur Berechnung der Fakultät einer Ganzzahl n
// n ist der formale Parameter der Methode. Er wird innerhalb der Methode wie eine normale Veriable verwendet.
public static int fakultaet(int n) {
  // Zwischenergebnis
  // f ist eine normale Variable, die nur innerhalb der Methode existiert.
  int f = 1;

  for (int i = 1; i <= n; i++) {
    f = f * i;
  }

  // Rückgabe des Ergebnisses an den Aufrufer
  return f;
}

public static void main(String[] args) {
  // n ist lokal in der Methode main
  int n = 4;
  // n wird zum konkreten Parameter beim Aufruf von fakultaet
  // innerhalb der Methode fakultaet wird ein zweites n durch Kopie dieses n erzeugt
  // es existieren also zwei Variable mit dem Namen n: eines in main, eines in fakultaet
  int x = fakultaet(n);

  // m ist lokal in der Methode main
  int m = 5;
  // m wird zum konkreten Parameter beim Aufruf von fakultaet
  // innerhalb der Methode fakultaet wird n durch Kopie von m erzeugt
  // es existieren also zwei Variable: m in main, n in fakultaet
  int y = fakultaet(m);
}

Falls es sich bei den Parametern nicht um primitve Typen sondern um Objekte handelt, verhält sich die Veränderbarkeit von außerhalb der Methode befindlichen Variablen anders (Details siehe dort). In diesem Fall spricht man von call-by-reference (Aufruf mit einer Referenz oder Zeiger, Adresse).

Beispiele

Beispiele
public static void main (String[] args) {...}
SichtbarkeitZuordnungRückgabetypNameParameterlisteMethodenrumpf
public static int fakultaet(int n){
  int f = 1;
  for (int i = 1; i <= n; i++) {
    f = f * i;
  }
  return f;
}
public class f {

// Methoden mit dem gleichen Namen, aber
// unterschiedlichem Rückgabewert und Parameterliste

  public static int f;

  public static void f() {
    f = 42;
  }

  public static int f(int n) {
    int f = 1;
    for (int i = 1; i <= n; i++) {
      f = f * i;
    }
    return f;
  }

  public static int f(int a, int b) {
    return tuWas(a,b);
  }
  public static void main(String[] args) {
    f = 5;
    int f = 7;
    f = f(f);
    f = f( f,f );
    f = f(f(f,f) , f(f(f),f));
  }
}

Java Insel

Methoden einer Klasse