Literatur

Aufruf von Methoden

Da wir nun den Aufbau und die Deklaration von Methoden kennen, wollen wir uns nun anschauen, wie wir die Methoden aufrufen. Damit wir auf eine Methode einer Klasse zugreifen können, müssen wir zuerst ein Objekt von dieser Klasse erstellen (Ausnahme: mit static deklarierte Klassenmethoden). Anschließend kann über die Punktnotation auf die Methode zugegriffen werden. Hierzu erstellen wir uns erstmal eine Startklasse und erzeugen uns in dieser ein Objekt unserer Klasse Punkt aus dem vorausgegangenen Beispiel. Anschließend rufen wir die Methode set_x_Koordinate auf.

class MethodenBeispiel
{
        // main-Methode
        public static void main(String[ ] args)
       {
               // Hier erzeugen wir ein Objekt der Klasse Punkt
               Punkt punkt_eins = new Punkt();
               /* Hier rufen wir die Methode set_x_Koordinate für unser
               Punkt-Objekt auf  */
               punkt_eins.set_x_Koordinate(5);
        }
 }

Erweitern wir nun unsere Klasse Punkt um die Methode get_x_Koordinate.

class Punkt            // Deklaration des neuen Klassennamens Punkt
{
 
    int x_koordinate;    // x-Position unseres Punktes
    int y_koordinate;    // y-Position unseres Punktes
 
    public void set_x_Koordinate (int zusetzendeX_Koordinate)
    {
        this.x_koordinate = zusetzendeX_Koordinate;
    }
 
    // Methodenkopf mit dem Zugriffsmodifikator public (überall sichtbar).
    // Der Rückgabedatentyp ist int
    // Der Methodenname get_x_Koordinate
    // Übergabeparameter gibt es nicht
    public int get_x_Koordinate ()
    {
        /* Hier wird der Wert des Attributes x_koordinate eines Objektes an den Aufrufer zurückgegeben. */
        return this.x_koordinate;
    }
}

Wie Sie an diesem Beispiel wieder sehen, wählt man die Methodennamen aussagekräftig. Die eine dient zum Setzen (set) und die andere zum Auslesen (get) eines Attributes (in diesem Fall x_koordinate). Diese Methoden werden auch getter- bzw. setter-Methoden genannt. Eine Methode, bei der ein Rückgabedatentyp angegeben ist, muss zwingend  einen Wert diesen Typs  über das Schlüsselwort return zurückgeben. Für die Methode get_x_Koordinate bedeutet das, dass sie eine Variable (in dem Fall das Attribut x_koordinate) vom Datentyp int zurückgeben muss.

Wir wollen nun die Klasse MethodenBeispiel um einen Aufruf der setter- und getter-Methode erweitern, um den Wert der Koordinate zu setzen und anschließend auszulesen.

Beispiel:

class MethodenBeispiel
{
        // main-Methode
        public static void main(String[ ] args)
       {
           // Hier erzeugen wir ein Objekt der Klasse Punkt
           Punkt punkt_eins = new Punkt();
 
           /* Hier rufen wir die Methode set_x_Koordinate für unser
           Punkt Objekt auf. */
           punkt_eins.set_x_Koordinate(5);
 
           /* Hier rufen wir die Methode get_x_Koordinate für unser
           Punkt Objekt auf und speichern den zurückgegebenen Wert
           in die Variable zurueck_gegebener_Wert */
           int zurueck_gegebener_Wert = punkt_eins.get_x_Koordinate();
 
           // Ausgabe des zurück gegebenen Wertes
           System.out.println("Zurück gegebener Wert ist: "+ zurueck_gegebener_Wert);
       }
}


Der Aufruf von Methoden erfolgt in Java durch einen sogenannten „call-by-value“.  Das bedeutet, dass der Wert (Inhalt) der übergebenen Parameter an die aufgerufene Methode übergeben wird. Diese werden dort in lokale Variablen kopiert. Veränderungen an den Parametern innerhalb der Methode wirken sich somit nicht außerhalb aus. Die beim Aufruf der Methode übergebenen Parameter bleiben also unverändert.

Für komplexe Datentypen schauen wir uns hierzu einmal folgendes Beispiel an:

// Unsere Klasse, mit der wir spielen wollen.
class RefTyp
{    
    // Attribut x
    int x;
}
 
class CallByReferenceBeispiel
{
    // methode1 mit Übergabeparameter vom Datentyp int
    static void methode1(int par)
    {    
          // par wird hier auf 2 verändert
          par=2;
    }
 
    // methode2
    static void methode2(RefTyp refParam)
    {    
         // Hier wird das Attribut x des Objekts refParam verändert
         refParam.x=2;
    }
 
    // main-Methode
    public static void main (String[ ] args)
    {
        // Variable var mit dem Wert 1
        int var=1;
 
        // Erzeugung eines Objektes der Klasse RefTyp
        RefTyp ref = new RefTyp();
 
        // Setzen des Attributes x unseres Objektes ref auf den Wert 1
        ref.x=1;
 
        // Ausgabe von var
        System.out.println("aktueller Wert vor methode1 für var :"+var);
 
        // Aufruf der Methode methode1 mit unserer Variablen var
        methode1(var);
 
        // Ausgabe von var nach Aufruf der Methode methode1
        System.out.println("aktueller Wert nach methode1 für var : "+var);
 
        // Ausgabe von dem Attribut x unseres Objektes ref
        System.out.println("aktueller Wert vor methode2 für ref.x :"+ref.x);
 
        // Aufruf der Methode methode2 mit unserem Objekt ref
        methode2(ref);
 
        /* Ausgabe von dem Attribut x unseres Objektes ref nach dem Aufruf der
        Methode methode2 */
        System.out.println("aktueller Wert nach methode2 für ref.x : "+ref.x);
    }
}


Was wird hier jetzt ausgegeben?



In der Methode methode1 wird der übergebene Parameter verändert. Da die Übergabe aber über einen "call-by-value" stattfindet, wird nur der Wert der übergebenen Variable in die Methode kopiert. Der Aufrufer bekommt somit nichts von der Änderung mit, da sich der übergebene Parameter somit ja nicht selber geändert hat, sondern nur eine lokale Kopie des Wertes. Deswegen lautet die zweite Ausgabe der Variable var ebenfalls 1.

Ein wenig komplizierter wird es jedoch bei der Übergabe von Objekten. Bei Objekt-Variablen muss man wissen, dass diese immer nur eine Referenz auf das Objekt beinhalten, nicht jedoch das Objekt selbst. Diese Referenz wird also in die lokale Variable der Methode kopiert.

Da nun aber die  kopierte Referenz auf dasselbe Objekt zeigt wie die, die beim Aufruf übergeben wurde, wirken sich alle Änderungen am referenzierten Objekt (z.B. Änderung eines Attributs) auch global aus. Dies gleicht in diesem Sonderfall also einem "call-by-reference" wie man es aus anderen Programmiersprachen kennt.

Beim Aufruf der methode2 haben wir einen solchen Fall. Wir übergeben das Objekt ref an methode2. In der Methode ändern wir das Attribut x dieses Objekts. Da wir dabei auf das referenzierte Objekt zugreifen, ist diese Veränderung auch beim Ausrufer sichtbar und es wird nach Ausruf der Methode diesmal eine 2 ausgegeben.

Wir hoffen, dass dieses kurze Beispiel Ihnen hilft, mehr über die Funktionsweise und dem Zusammenspiel zwischen Objekten und Methoden zu verstehen.