Advanced   Java   Services Methoden Back Next Up Home

Einleitung

Methoden oder Funktionen sind Unterprogramme, die Teilaufgaben eines Programms erledigen. Durch diese wird die Modularisierung von Programmen unterstützt und die Wiederverwendbarkeit von Programmcode ermöglicht. Eine Funktion ist unabhängiges Unterprogramm, das für sich alleine existiert. Eine Methode ist ein abhängiges Unterprogramm, das nur im Zusammenhang mit einer Klasse existiert. Aus diesem Grund nannte man eine Methode früher auch memberfunction, weil sie eben Teil einer Klasse ist. Wir haben bereits eine Reihe von Methoden aus der Klasse Stdin und der Klasse Math verwendet (siehe Erster Kontakt mit Klassen) und wissen, wie man statische Methoden aufruft, nämlich mit dem dem Namen der Klasse, aus der sie stammen.


Formale Darstellung eines Unterprogrammaufrufs

Die nachfolgende Graphik zeigt, wie man sich einen Unterprogrammaufruf vorzustellen hat. Bei einem Statement, das einen Unterprogrammaufruf darstellt, verzweigt das Programm zu einem neuen Speicherblock, dessen Code dann abgearbeitet wird. Damit hat jedes Unterprogramm seinen eigenen Speicherbereich und seine eigenen lokalen Variablen. Am Ende eines Unterprogramms gibt es einen Rücksprung zum jeweils aufrufenden Programm. Dieses return-Statement wird vom Compiler automatisch ergänzt wenn man eine Funktion oder Methode schreibt. Mit diesem return-Statement kann das Unterprogramm auch einen Wert an das aufrufende Programm zurückgegeben. In diesem Fall muß der Programmierer selbst ein passenden return-Statement einfügen. Auch in main() selbst gibt es ein implizites return-Statement. Dieses hat dann das Ende des Programms zur Folge. Der prinzipielle Vorgang ist für Funktionen und Methoden derselbe. Natürlich kann in einem Unterprogramm ein weiterer Unterprogrammaufruf sein. Beim jedem Aufruf eines Unterprogramms muß das Hauptprogramm sich eine Rücksprungadresse merken, damit nach dem Ende des Unterprogramms das aufrufende Programm weiter abgearbeitet werden kann. Diese Rücksprungadressen werden in einem eigenen Speicherbereich verwaltet, dem sogenannten Stack, der in der Graphik nicht dargestellt wird. bei sehr vielen geschachtelten Unterprogrammaufrufen kann dieser Stack eventuell zu klein werden. Ein dann auftretender stack overflow führt unweigerlich zu einem Programmabsturz.
unterprogrammaufruf.jpg


Parameterliste und Returntyp

Jetzt wollen wir eigene Methoden schreiben. Dazu müssen wir folgende Schritte beachten:

Am besten schaut man sich das an einem Beispiel an. Im folgenden werden außer main noch vier weitere Methoden definiert.

public class MethodenDemo
{
   public static void main(String args[])
   {
      System.out.println("main-Methode");
   }

   static void kriegtNixGibtNix()      // Methode 1
   {
      System.out.println("kriegtNixGibtNix-Methode");
   }

   static void kriegtWasGibtNix(int a)    // Methode 2
   {
      System.out.println("kriegtWasGibtNix-Methode : "+a);
   }

   static char kriegtNixGibtWas()      // Methode 3
   {
      System.out.println("kriegtNixGibtWas-Methode");

      return 'x' ;
   }

   static double kriegtWasGibtWas(int a)     // Methode 4
   {
      System.out.println("kriegtWasGibtWas-Methode : "+a);

      return a*a ;
   }

   static double mimmZweiGibEins(double a, double b)     // Methode 5
   {
      System.out.println("mimmZweiGibEins-Methode");

      return a*b ;
   }

}

Im obigen Beispiel sind die grundsätzlichen Möglichkeiten durchgespielt. Nach der main-Methode folgen fünf weitere selbstentworfene Methoden. Allen Methoden haben eine Kopfzeile, die den Namen und die Parameterliste festlegt, und einen Rumpf, der mindestens aus den geschweiften Klammern bestehen muß. Die erste Zeile mit dem Namen nennt man auch gerne die Signatur der Methode, diese taucht für gewöhnlich in der Dokumentation zu der Methode bzw. Klasse auf (siehe die Doku zur Klasse Stdin).


Aufruf, Parameterübergabe und Returnwert

Die oben geschriebenen Methoden werden noch nirgends verwendet. Damit eine Methode abgearbeitet wird, muß sie aufgerufen werden. Erst dann kann sie etwas bewirken. Meist wird eine Methode aus einer anderen Methode heraus aufgerufen. Standardbeispiel: Innerhalb der main-Methode wird System.out.println() aufgerufen. Ein Methodenaufruf kann aber auch in einer Vereinbarung stehen und dort eine Variable initialisieren. In den folgenden zwei Beispielen demonstrieren wir Aufrufe der vier oben eingeführten Methoden.

public class Aufruf1
{
   public static void main(String args[])
   {
      System.out.println("main-Methode");

      Aufruf1.kriegtNixGibtNix() ;                 // Methode 1 wird aufgerufen

      Aufruf1.kriegtWasGibtNix(17) ;               // Methode 2 wird aufgerufen

      char erg = Aufruf1.kriegtNixGibtWas() ;      // Methode 3 wird aufgerufen

      int a = 34; double ret;
      ret = Aufruf1.kriegtWasGibtWas(a) ;          // Methode 4 wird aufgerufen

      kriegtNixGibtNix() ;                         // Methode 1 wird nochmal aufgerufen

      double erg =  Aufruf1.mimmZweiGibEins(a, ret)  // Methode 5 wird aufgerufen
   }

   static void kriegtNixGibtNix()      // Methode 1
   {
      System.out.println("kriegtNixGibtNix-Methode");
   }

   static void kriegtWasGibtNix(int a)    // Methode 2
   {
      System.out.println("kriegtWasGibtNix-Methode : "+a);
   }

   static char kriegtNixGibtWas()      // Methode 3
   {
      System.out.println("kriegtNixGibtWas-Methode");

      return 'x' ;
   }

   static double kriegtWasGibtWas(int a)     // Methode 4
   {
      System.out.println("kriegtWasGibtWas-Methode : "+a);

      return a*a ;
   }

   static double mimmZweiGibEins(double a, double b)     // Methode 5
   {
      System.out.println("mimmZweiGibEins-Methode");

      return a*b ;
   }

}

Im obigen Beispiel werden alle Methoden aus main heraus aufgerufen. Beachten Sie die Art der Parameterübergabe und die Zuweisung des Returnwertes. Eine Methode kann also Daten aus einem laufenden Programm entgegennehmen (Parameterübergabe) und ein Datum an die aufrufende Methode zurückgeben (Zuweisung des Returnwertes).


statisch oder nicht statisch

Es fällt auf, daß im obigen Beispiel alle Methoden statisch sind. Dies hat zwei Gründe. Zum einen wurde bisher nur ein statischer Methodenaufruf behandelt. Zum anderen wollen wir unsere Beispielsmethoden aus main heraus aufrufen. Nun ist aber main selbst auch statisch und für statische Methoden gibt eine wichtige Einschränkung:

Bezüglich Parameterlisten und Returnwert bestehen jedoch zwischen statischen und nichtstatischen Methoden keine Unterschiede.


Überladen von Methoden

In objektorientierten Sprachen ist es möglich, denselben Namen für mehrere Methoden zu vergeben. Sprachen, die noch aus der vorobjektorientierten Zeit stammen, wie etwa C können dies nicht. Bei gleichen Namen erfolgt die Unterscheidung von Methoden über die Parameterliste. Der Returntyp und sonstige Modifier wie public oder static werden nicht zur Namensunterscheidung herangezogen. In der Parameterliste werden die Parameter nach Anzahl, Typ und Reihenfolge unterschieden. Im folgenden finden Sie einige Beispielsignaturen mit gleichem Namen, die der Compiler an Hand der Parameterliste unterscheiden kann.

In diesem Beispiel ist jede Methode zu jeder anderen unterscheidbar. Etwa : 1. von 2. wegen unterschiedlicher Parameteranzahl, 2. von 3. wegen unterschiedlicher Parametertypen, 3. von 4. wegen unterschiedlicher Parameteranzahl, 4. von 5. wegen unterschiedlicher Reihenfolgen der Typen. Sie können im obigen Beispiel irgendzwei der fünf Methoden betrachten und feststellen, daß die Signaturen unterscheidbar sind.

Das Überladen von Methoden (engl. method overloading) sollte nur dann angewandt werden, wenn die Methoden ähnliche oder verwandte Aufgaben erledigen, die Methoden der Klasse Sort sind ein gutes Beispiel.

Vorsicht ist allerdings beim Aufruf von überladenen Methoden geboten. Hier kann es schnell zu nicht auflösbaren Mehrdeutigkeiten kommen. Wir betrachten die letzten beiden Signaturen (4. und 5.) unseres obigen Beispiels und den folgenden Aufruf:

  int r=2, s=3 ;
  xx.beispiel(r, s) ;


Für diesen Aufruf findet der Compiler keine Signatur, die exakt paßt (exact match), also versucht er eine Typanpassung. Eine Typanpassung von int nach double ist kein Problem, die Frage ist nur, bei welchem Parameter sie vorgenommen werden soll, beim ersten oder beim zweiten. Da beide Varianten gleichberechtigt sind, kann der Compiler hier keine Entscheidung treffen.


call by value und call by reference

Bei der Übergabe von Parametern an Methoden wird grundsätzlich mit Kopien gearbeitet. Die Methode erhält nicht das Original des aktuellen Parameters, sondern eine Kopie desselben. Die Methode speichert diese Kopie in einem eigenen Speicherbereich. Etwaige Änderungen dieser Kopie können sich also nicht auf das Original auswirken. Diese Art der Übergabe beim Aufruf einer Methode nennt man "call by value" , Wertübergabe. Insofern könnte man sagen, daß es in Java eigentlich nur "call by value" gibt. Es macht jedoch einen qualitativen Unterschied, ob man die Kopie einer Variablen übergibt oder die Kopie einer Referenz auf eine Variable, deswegen spricht man bei der Übergabe einer Kopie einer Referenz auch gerne von "call by reference".

call by value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
callByValue

Beim Aufruf von method() wird der Wert des aktuellen Parameters x der lokalen Variablen a von method() zugewiesen. Änderungen der Kopie a können sich nicht auf das Original x auswirken.

call by reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
callByreference

Hier wird die Übergabe einer Feldreferenz dargestellt. Beim Aufruf der Methode method() wird eine Kopie der Feldreferenz arr in die lokale Referenz brr abgelegt. Damit zeigen sowohl arr als auch brr auf das in main() angelegte Feld. Die Methode kann deshalb auf das Feld zugreifen und dort beliebige Änderungen vornehmen, die die Datensituation in der aufrufenden Methode ( hier main() ) beeinflußen. Eine Änderung der Referenz brr innerhalb der Methode method() hat dagegen keinen Einfluß auf main() .


Übergabe einer Feldreferenz

Die folgende Methode arbeitet mit zwei Parametern. Der erste Parameter ist eine Feldreferenz, der zweite Parameter eine int-Variable. Mit dem zweiten Parameter kann man z.B. den Mittelwert nur der ersten Hälfte des Arrays ermiteln, so wie es hier geschieht.

public class Aufruf2
{
   public static void main(String args[])
   {

      int brr[] = { 2, 4, 6, 20, 18, 16, 7, 12, 12, 17 } ;

      double mittel = Aufruf2.mittelWert(brr, brr.length/2) ;

      System.out.println("Mittelwert der ersten Hälfte " + mittel);
   }

   static double mittelWert(int arr[], int len)
   {
      double mittel=0;

      for(int i=0; i<len; i++)
         mittel += arr[i] ;

      return mittel/len ;
   }

} // end main class

Feldreferenz als Returntyp

Dieses Beispiel zeigt, daß auch der Returntyp einer Methode ein Referenztyp sein kann. Es wird eine Feldreferenz übergeben. In der Methode wird ein zweites Feld angelegt. Dieses Feld enthält Kopien der Elemente des Ausgangsfeldes, nur in umgekehrter Reihenfolge. Das Ausgangsarray wird also nicht verändert.

public class Aufruf3
{
   public static void main(String args[])
   {

      int brr[] = { 2, 4, 6, 20, 18, 16, 7, 12, 12, 17 } ;

      int rev[] = Aufruf3.reverse(brr) ;

      for(int i=0; i<rev.length; i++)
         System.out.println("rev["+i+"] = " + rev[i]);
   }

   static int[] reverse(int arr[])
   {
      int feld[] = new int[arr.length] ;

      for(int i=0; i<arr.length; i++)
         feld[i] = arr[ (arr.length-1) - i] ;

      return feld ;
   }

} // end main class

Namenskonvention

Wahrscheinlich ist Ihnen aufgefallen, daß alle bezeichner für Methoden mit kleinem Buchstaben beginnen. Dies ist kein Zufall, sondern eine sehr nützliche Konvention, die es uns erleichtert, uns in eigenen und fremden Programmen zurecht zu finden. Es hat sich auch eingebürgert, jedes neue Wort im Bezeichner mit großen Buchstaben beginnen zu lassen. Hier einige Beispiele aus der Klassenbibliothek:

Und noch etwas sieht man an den obigen Namen: Bezeichner sollen nicht kurz sein, sondern selbsterklärend. Das spart Erklärungen in Kommentaren.


Übungen

Einfache Methoden

Kalenderberechnungen

Finanzmathematische Methoden

Mathematische Methoden

Valid XHTML 1.0 Strict top Back Next Up Home