Jetzt anmelden...

Login
Passwort
Registrieren

Java Tutorial #12

Methoden in Java erstellen und aufrufen

Methoden beschreiben die Funktionalität einer Klasse. Einfache Beispiele hierfür sind: Text auf der Konsole ausgeben, das Ergebnis einer Berechnung zurückliefern oder den Wert von Instanzvariablen verändern. Wir schauen uns in diesem Kapitel die Feinheiten im Einsatz von Java-Methoden genauer an.

Kommentare [0]

Stefan 20.11.2018

Infos zum Artikel

Kategorie Java
Autor Stefan
Datum 20.11.2018

Thema in Kurzform

  • Methoden werden in Klassen definiert. Sie beschreiben, was Objekte einer bestimmten Klasse ausführen/ tun können.
  • Methoden werden auf einem Objekt mit dem Punktoperator aufgerufen: obj.meineMethode();
  • Beispielcode für eine typische Methode in Java:
    public void meineMethode(){
        System.out.print("Ich bin eine Methode!");
    }
    

Methodendefinition

Bevor wir loslegen erst einmal ein Blick auf den allgemeinen Aufbau einer Methode, die Methodendefinition:

Java Methoden Aufbau Deklaration Signatur

Als Methodendefinition wird der komplette Code einer Methode bezeichnet, also das "ganze Ding".

Methoden bestehen aus einem Methodenkopf - hier: public void methodeX(int para) - und einem Methodenkörper, der von zwei geschweiften Klammern { } umschlossen wird. Im Methodenkörper befinden sich die einzelnen Anweisungen, die beim Methodenaufruf durchgeführt werden.

Was Sie sich auch gut merken sollten:

  • Die Reihenfolge der Schlüsselbegriffe im Methodenkopf darf nicht verändert werden!
  • Bei der Auswahl des Methodennamens müssen bestimmte Regeln eingehalten werden. Es handelt sich dabei um die gleichen Benennungsregeln wie bei den Namen für Java-Variablen.
  • keine doppelten Methoden: Jede Methodensignatur darf in einer Klasse nur einmal vorkommen.

Wir schauen uns im nächsten Teil einmal an, wie wir Methoden aufrufen. Danach gehen wir auf die einzelnen Schlüsselbegriffe der Methoden-Signatur genauer ein.

Methoden aufrufen

Wir fangen ganz allgemein an. Um die Funktionsweise von Methoden zu erklären, schreiben wir eine Klasse namens Roboter.

package paket1;

public class Roboter {

    private String bezeichnung;
    private String typ;
    private double energie;
    private int aktuelleGeschwindigkeit;

    public Roboter(){
        bezeichnung = "Opportunity";
        typ = "Mars Rover";
        energie = 100;
        aktuelleGeschwindigkeit = 0;
    }

    // Methoden:
    public void printInfos(){
        System.out.println("Details: " + bezeichnung + "/ " + typ);
        System.out.println("Energiestatus: " + energie);
        System.out.println("Aktuelle Geschwindigkeit: " + aktuelleGeschwindigkeit);
    }

    public void beschleunige(){
        aktuelleGeschwindigkeit += 2;
        energie -= 2;
    }

    public void bremse(){
        aktuelleGeschwindigkeit -= 2;
        energie -= 1;
    }
}

Ab Zeile 18 im Code-Beispiel sehen wir die Methoden. Insgesamt gibt es drei Methoden namens printInfos(), beschleunigen() und bremsen(). Wenn wir ein Roboter-Objekt erzeugen, wird dieses Objekt die drei Methoden ausführen können.

Sehen wir uns die drei Methoden einmal genauer an. Sie werden schnell merken, dass diese recht simpel sind:

Die Methode printInfos() hat drei System.out.print-Anweisungen, die uns die Werte der Instanzvariablen auf der Konsole printen.

Die Methoden beschleunigen() und bremsen() besitzen jeweils zwei Anweisungen: Erstens wird der Wert der Instanzvariablen aktuelleGeschwindigkeit erhöht bzw. verringert. Zweitens wird der Wert der Instanzvariablen energie um -2 bzw. -1 veringert.

Alles kein Hexenwerk, oder?

Erstellen wir nun in einer Klasse namens Startklasse ein neues Roboter-Objekt und führen auch gleich die Methoden darauf aus.

package paket1;

public class Startklasse {

    public static void main(String[] args){
        Roboter r1 = new Roboter();
        r1.beschleunige();
        r1.beschleunige();
        r1.printInfos();
    }
}

Wir erzeugen mit dem new-Operator innerhalb der Main-Methode das neue Roboter-Objekt. Wir nennen es r1.

In den folgenden Zeilen rufen wir auf diesem Objekt zweimal die Methode beschleunige() und anschließend printInfos() auf. Auf der Konsole erhalten wir dann folgenden Text angezeigt:

Details: Opportunity/ Mars Rover
Energiestatus: 96.0
Aktuelle Geschwindigkeit: 4

Das Grundprinzip, wie wir Methoden auf Objekten benutzen, ist recht einfach:

Java Methoden Punktoperator aufrufen

Wir schreiben immer die Namen des Objekts, setzen direkt dahinter einen Punkt (Punktoperator) und nennen anschließend die Methode, die wir auf dem Objekt benutzen wollen. Die Methode beschleunige() hat keine Parameter. Deshalb ist die Klammer nach dem Methodennamen leer.

Access Modifier

Für Methoden müssen wir eine Zugriffsstufe festsetzen. Java besitzt insgesamt vier Zugriffsstufen, die mit dem sog. Access Modifier geregelt werden. Das Modifier-Schlüsselwort legt fest, welcher Code von außerhalb der Methode auf die Methode zugreifen darf.

Zugriffstufe Klasse Paket Sub-Klasse Welt
public
protected
kein Modifier-Schlüsselwort (default)
private

Wichtig: Der Access Modifier ist immer das erste Schlüsselwort im Methodenkopf.

public Access

Wenn eine Methode mit public gekennzeichnet ist, bedeutet dies, dass sie von überall in unserem Java-Projekt aus aufgerufen werden kann. Selbst wenn sich die Klasse, zu der die Methode gehört, in einem anderen Paket befindet, ist das kein Problem!

package paket1;

public class Roboter {

    public void beschleunige(){ // Code... }

}
package paket2;
import paket1.Roboter;

public class Werkstatt {

    public void checkRobots() {

        Roboter robot1 = new Roboter();
        robot1.beschleunige(); // läuft!
    }
}

Die Klasse Roboter liegt im package paket1. Ein Objekt dieser Klasse (robot1) wurde nun in der Klasse Werkstatt in einem anderen Paket erstellt. Da die Roboter-Methode beschleunige() als public markiert wurde, kann sie in der Klasse Werkstatt (wie auch überall sonst im gesamten Java-Projekt) problemlos aufgerufen werden.

protected Access

Auf eine Methode mit protected kann zugegriffen werden, wenn sie sich in derselben Klasse, demselben package oder einer vererbten Klasse (außerhalb des packages) des auf sie zugreifenden Codes befindet.

Zu Beginn Ihrer Java-Karriere werden Sie protected wohl kaum einsetzen. Außerdem kann dieser Modifier sehr tricky sein. Ohne ein tieferes Verständnis von Vererbung macht es keinen Sinn, ihn hier im Detail zu erklären. Wir kommen zu einem späteren Zeitpunkt darauf zurück.

kein Modifier-Schlüsselwort (default)

Wie wir in der Tabelle oben sehen, kann eine Methode ohne expliziten Access Modifier nur von Klassen innerhalb desselben Pakets aufgerufen werden (das schließt die Klasse, in der die Methode erstellt wurde, automatisch mit ein).

Um eine Methode auf default zu setzen, lassen wir das Modifier-Schlüsselwort einfach weg. Java weiß dann Bescheid, dass hier die Standard-Zugriffsebene gesetzt wird (und für diese gibt es keinen Modifier-Schlüsselbegriff).

Die Methode beschleunige() mit default-Zugriffsstufe sieht - wenig überraschend - dann so aus:

void beschleunige(){ // Code... }

Testen wir das Ganze mal in der Klasse Werkstatt in paket2:

package paket2;
import paket1.Roboter;
public class Werkstatt {

    public void checkRobots() {
        Roboter robot1 = new Roboter();
        robot1.beschleunige(); // Fehler! Versucht default-Zugriffsstufe aufzurufen!
    }
}

☝️ Aha! Der Code kann so nicht kompiliert werden. Das Problem ist nämlich, in der Klasse Werkstatt versucht wird, auf die Methode beschleunige() der Klasse Roboter zuzugreifen. Roboter aber befindet sich im Paket paket1, Werkstatt dagegen in paket2.

private Access

Die private Zugriffsstufe ist einfach: Eine Methode, die auf private gesetzt ist, kann nur innerhalb der eigenen Klasse aufgerufen werden:

package paket1;
// Code...
private void beschleunige(){ // Code... }
// Code...

Die Klasse Cyborg kann, obwohl sie auch in paket1 ist, niemals auf die private-Methode der Klasse Roboter zugreifen:

package paket1;

public class Cyborg {

    public void tuEtwas(){
        Roboter r1 = new Roboter();
        r1.beschleunige; // Fehler! Versucht private-Zugriffsstufe aufzurufen!
    }
}

Ganz klar ist jedoch der Einsatz von beschleunige() in der Klasse, in der sie erstellt wurde, also Roboter:

package paket1;

public class Roboter {
// Code...
    public void tuEtwas(){
        Roboter r1 = new Roboter();
        r1.beschleunige; // läuft!
    }
// Code...
}

Rückgabetyp

Jede Methode in Java muss einen Rückgabetyp haben und dieser Rückgabetyp muss in der Methodendefinition auch explizit genannt sein. Doch was bedeutet das eigentlich?

Methoden können nach ihrem Aufruf einen Wert zurückliefern, etwa eine Ganzzahl (int), einen Wahrheitswert (boolean), eine Zeichenkette (String) oder was auch immer. Der Rückgabetyp wird im Methodenkopf genannt. Sehen wir uns eine Methode an, die einen int-Wert zurückliefert:

public int getZahl(){
    return 100;
}

Im Methodenkopf steht direkt vor dem Methodennamen der Datentyp, den die Methode zurückliefern soll und das ist hier int.

Innerhalb der Methode sehen wir eine Anweisung: return 100; Das ist die Rückgabeanweisung. Sie sorgt dafür, dass ein Wert vom Typ int zurückgeliefert wird, genauso so, wie es im Kopf der Methode festgeschrieben ist. Die Rückgabeanweisung return ist immer die letzte Anweisung in einer Methode (return heißt nämlich auch Methodenende).

Wichtig ist: Der angezeigte Rückgabetyp im Methodenkopf muss kompatibel sein mit dem Datentyp hinter der Rückgabeanweisung return. Folgender Code ist deshalb Schrott:

public int getZahl(){
    return 10.15; // Inkompatibler Typ
}

"Versprochen" wird im Methodenkopf ein int-Wert, doch es soll mit return 10.15; ein double-Wert zurückkommen. Das läuft so nicht!

Eine Frage bleibt noch offen: Wozu sind return-Methoden (man sagt auch "sondierende Methoden") gut? Sehr häufig werden sie eingesetzt, um den Wert von Instanzvariablen abzufragen ("getter").

public double getEnergie(){
    return energie; //Liefere den Wert der Instanzvariablen energie zurück
}

Wir können den Rückgabewert in einer anderen Methode wiederum aufnehmen, um damit zu arbeiten. Zum Beispiel:

public void checkEnergie(){
    if(getEnergie() > 50){
        System.out.println("Energie ausreichend");
    }
    else{
        System.out.println("Energiestand gering");
        }
    }

Aber Moment mal! Haben wir nicht schon unzähle Methoden ohne eine return-Anweisung gesehen? 🤓

Stimmt genau. Methoden ohne return am Ende liefern auch keinen Wert zurück. Deshalb müssen wir diese Tatsache in der Methodendefinition mit dem Schlüsselwort void klar machen. void ("Nichts") bedeutet, dass die Methode keinen Rückgabewert hat:

public void beschleunige(){
    aktuelleGeschwindigkeit += 2; // führe Rechnung aus
    energie -= 2; // rechne noch etwas
    // die Methode liefert nichts zurück
}

Parameter

Methoden können nicht nur Werte zurückliefern, sie können "von außen" auch Werte (zur Verarbeitung) reinbekommen. Dies geschieht über Parameter.

Parameter sind Variablen, die im Kopf einer Methode direkt hinter dem Methoden-Namen in runden Klammern ( ) deklariert werden (hat eine Methode keine Parameter, bleiben die runden Klammern leer).

public void energieLaden(double a){
    energie += a;
}

Diese Methode hat eine Parameter-Variable a vom Typ double. Der Wert von a wird dann durch die Anweisung im Methodenkörper dem Wert der Instanzvariablen energie hinzugefügt.

Der konkrete Einsatz der Methode auf einem Roboter-Objekt sieht so aus:

public static void main(String[] args){
    Roboter r1 = new Roboter(); // Energie: 100.0
    r1.energieLaden(5); // Energie: 105.0
}

Methoden können auch mehrere Parameter haben. Diese werden dann kommasepariert nebeneinander gelistet:

public void energieLaden(double a, double b, double c){
    energie += a + b + c;
}
public static void main(String[] args){
    Roboter r1 = new Roboter(); // Energie: 100.0
    r1.energieLaden(5, 3.5, 1.1); // Energie: 109.6
}

Merke: Wenn wir eine Methode auf einem Objekt aufrufen, müssen alle Parameter-Positionen mit kompatiblen Werten besetzt sein. Folgendes wäre also nicht erlaubt:

r1.energieLaden(5, 3.5, true); // true ist kein double-Wert!
r1.energieLaden(5, 3.5); // es müssen drei Werte übergeben werden!

Methoden überladen

Doppelte Methoden sind grundsätzlich nicht erlaubt! Das heißt: Eine Methoden-Signatur darf nur einmal pro Klasse vorkommen. Folgender Code ist daher nicht gültig:

private void beschleunige(){ }
public void beschleunige(){ } // Fehler! Signatur doppelt

Die Methoden-Definitionen sind zwar unterschiedlich (verschiedene Access Modifier). Wir erhalten aber trotzdem einen Compiler-Fehler, der uns etwas sagt wie 'bechleunige()' is already defined in paket1.Roboter. Der Grund ist klar: Die Signatur der Methode beschleunige() ist mehrfach (hier 2x) vorhanden. Aua!

Allerdings können wir Methoden überladen. Das bedeutet, dass der Methoden-Name mehrfach vorhanden, aber die Parameterliste unterschiedlich ist. Damit ist die Methoden-Signatur nicht mehr identisch. Folgender Code ist 100% legal:

public void beschleunige(){ } // Methodendefinition: beschleunige()
public void beschleunige(int x){ } // Methodendefinition: beschleunige(int x)

Nochmal: Jede Methoden-Definition (name + Parameterliste) darf je Klasse nur einmal vorkommen. Wenn wir den gleichen Methodennamen mehrmals haben, aber jeweils unterschiedliche Parameterlisten, spricht man von Methodenüberladung - und diese ist ein sehr nützliches Programmierinstrument!

Übungen

einfach

Ist der folgende Code korrekt?

public void berechneZahl(int x, int y){
    int z = x * y;
    return z;
}
Lösung ein-/ausblenden

mittel

Können Sie erklären, ob die folgenden Methoden korrekt sind oder nicht?

public void analysiere1() { }

public void analysiere2() { return; }

public void analysiere3() { return 8; }

public String analysiere4() { return "";}

public String analysiere5() { }

public analysiere6() { }

String analysiere7() {
    if (getEnergie() > 80) {
        return "guter Energiestatus";
    }
}

Lösung ein-/ausblenden

schwer

Erstellen Sie eineKlasse Buch mit drei Instanzvariablen autor, titel und bewertung (alle drei vom Typ String). autor und titel werden im Konstruktor mit sinnvollen Werten initialisiert.

Die Instanzvariable bewertung dagegen soll innerhalb einer void-Methode mit Parameter initialisiert werden (Mögliche Bewertungen sind: "Super", "gut", "ganz ok", "mies")

Implementieren Sie drei return-Methoden getAutor(), getTitel() und getBewertung().

Erstellen Sie eine Methode, welche die return-Methoden benutzt und beim Aufrufen die Informationen zum Buch auf der Konsole nach folgendem Muster ausgibt:
Autor: Daniel Defoe, Titel: Robinson Crusoe, Bewertung: gut

Fügen Sie der Klasse Buch eine weitere Inszanzvariable hinzu: ausgeliehen. Diese soll einen Zähler modellieren, der angibt, wie häufig das Buch bereits ausgeliehen worden ist. Fügen Sie eine void-Methode ausleihen() hinzu, die den Zähler bei jedem Aufruf erhöht.

Überladen Sie die Methode ausleihen(), um den Zählerstand frei anzupassen.

Lösung ein-/ausblenden

Kommentar schreiben

Nur angemeldete und aktivierte Benutzer können kommentieren.

Alle Kommentare

Es gibt bislang noch keine Kommentare zu diesem Thema.

Initializer

Eher selten aber praktisch!

Objektsammlungen

Lernen Sie in diesem Kapitel, wie Sie eine Sammlung von Objekten erstellen können.

Pass-by-value in Java

wie genau der Vorgang der Parameterübergabe bei Methoden abläuft, klären wir hier.

FALCONBYTE.NET

Handmade with 🖤️

© 2018, 2019 Stefan E. Heller

Impressum | Datenschutz

facebook programmieren lernen twitter programmieren lernen youtube programmieren lernen