Die statische Main-Methode ändert Instanzvariable?

JavaLernen1

Mitglied
Es ist doch in Java so, dass statische Methoden nicht mit nicht-statischen Variablen umgehen können.

Aber man kann doch mit der Main-Methode die Variablen von Objekten ändern...

Also ich meine Folgendes:

Ich habe eine Klasse:

Java:
class Angestellter
{
  String vorname;
  String nachname;
  int alter;
  int gehalt;

  void erhöheGehalt(int erhöhung)
  {
    gehalt += erhöhung;
  }
}

sowie die Klasse

Code:
class AngestelltenVerwaltung
{
  public static void main(String[] args)
  {
     // Angestellte Müller anlegen
    Angestellter mül = new Angestellter();
    mül.vorname = "Petra";
    mül.nachname = "Müller";
    mül.alter = 45;
    mül.gehalt = 1800;
     // Angestellten Wawrzyniak anlegen
    Angestellter waw = new Angestellter();
    waw.vorname = "Leszek";
    waw.nachname = "Wawrzyniak";
    waw.alter = 23;
    waw.gehalt = 1300;
    // Gehalt von Herrn Wawrzyniak erhöhen
    System.out.println("Das alte Gehalt von Herrn Wawrzyniak: " + waw.gehalt);
    waw.erhöheGehalt(50); // geänderte Zeile
    System.out.println("Das neue Gehalt von Herrn Wawrzyniak: " + waw.gehalt);
  }
}

Hierbei sind doch vorname, nachname, alter und gehalt Instanzvariablen und diese werden doch in der statischen Main-Methode der Klasse AngestelltenVerwaltung "bearbeitet", z.B. in der Zeile

Code:
waw.vorname = "Leszek";

wird die Variable vorname der Instanz waw gesetzt.

Damit greift doch aber eine statische Methode auf eine nicht-statische (d.h. Instanzvariable) Variable zu? Wo ist da mein Denkfehler?
 
Du hast das etwas falsch verstanden.

Für den Zugriff auf eine Instanzvariable brauchst Du eine Instanz. Und bei waw.vorname = "Leszek"; hast Du ja eine Instanz: waw

Wenn Du eine statische Methode aufrufst, dann wird die Methode ja "auf der Klasse" aufgerufen, d.h. Du hast den Aufruf nicht auf einer Instanz und damit hast Du in der Methode nicht die Instanz wie Du diese in Instanzmethoden hast: Das this.

Java:
public class SomeClass {
    int someVariable;
    
    public static void someStaticMethod() {
        // kein this und damit kein Zugriff auf this.someVariable!
    }
    
    public void someMethod() {
        someVariable = 1; // Das gleiche wie this.someVariable
    }
}
 
Das heißt, wenn ich in der statischen Methode main den Ausdruck
Java:
waw.vorname
habe, handelt es sich dabei nicht um eine nicht-statische Variable? So ganz klar ist mir das noch nicht geworden.
 
Dein waw ist eine lokale Variable innerhalb deiner main-Methode, der du eine neue Instanz einer Angestellter Klasse zuweist.
Das hat überhaupt nichts mit statisch oder nicht-statisch zu tun. Jede Methode kann lokale Variablen haben, wo sie Dinge drin speichern kann.
Und wenn du nun einen Ausdruck hast mit waw. dann referenzierst du damit irgendetwas innerhalb des Objektes, was in der waw Variable gespeichert ist.
 
Probier doch mal:
Java:
class AngestelltenVerwaltung
   
    Angestellter ang = new Angestellter();
   
{
  public static void main(String[] args)
  {
    ang.vorname = "Petra";
   
    // ...
  }
}
Du wirst eine Fehlermeldung erhalten, weil "ang" keine lokale Variable mehr ist, sondern eine Instanzvariable von AngestelltenVerwaltung. Davon gibt es aber keine Instanz. Darum wird es auch nicht funktionieren.

Du müsstest erst eine Instanz davon erzeugen:
Java:
class AngestelltenVerwaltung
    Angestellter ang = new Angestellter();
   
{
  public static void main(String[] args)
  {
    AngestelltenVerwaltung av = new AngestellenVerwaltung(); // das ist wieder eine lokale Variable
    av.ang.vorname = "Petra"; // und auf die Instanz kannst zu zugreifen
   
    // ...
  }
}

oder die Variable ang müsste wiederum statisch sein.
Java:
class AngestelltenVerwaltung
   
    static Angestellter ang = new Angestellter();
   
{
  public static void main(String[] args)
  {
    ang.vorname = "Petra";
   
    // ...
  }
}

Als Grundsatz kannst du dir mal mitnehmen, dass du im Normalfall nur genau einmal "static" in deinem Programm haben solltest und zwar vor der main-Methode.
 
Als Grundsatz kannst du dir mal mitnehmen, dass du im Normalfall nur genau einmal "static" in deinem Programm haben solltest und zwar vor der main-Methode.
Das ist, sagen wir mal, nicht ganz richtig. Konstanten werden als "static final" deklariert, davon gibt es oft eine Menge. Methoden, meist privat, welche nicht auf Instanzvariablen zugreifen können alle als static deklariert werden usw.. Es gibt sehr viele Gründe für das Schlüsselwort static, nicht nur die Main-Methode. Ich sehe hier keinen Grundsatz. Der Grundsatz ist eher: Man muss verstehen was static bewirkt und wozu es benutzt wird. Damit ist der TE auf dem richtigen Weg.
 
Ja, es gibt Ausnahmen aber gerade am Anfang ist es wichtig, dass man den Leuten klar macht, dass auf static wenn möglich zu verzichten ist.

Und ehrlich: bei einer private static Methode fehlt mir schlicht das Verständnis. Wie kommt man zu sowas? Und wie testet man sowas? Eine static Methode könnte super zu testen sein ..: so diese keinen State hat und so. Aber sie ist ja private ..:
Vielleicht hast du ja ein Beispiel für so eine Methode?
 
Und ehrlich: bei einer private static Methode fehlt mir schlicht das Verständnis. Wie kommt man zu sowas? Und wie testet man sowas? Eine static Methode könnte super zu testen sein ..: so diese keinen State hat und so. Aber sie ist ja private ..:
Vielleicht hast du ja ein Beispiel für so eine Methode?
Also bei einem aktuellen Projekt wird sehr funktional programmiert, dort gibt es fast ausschließlich static Methoden, die sehr viel mit Kombinatoren auf Streams arbeiten: z.B. Stream<Product> als Parameter rein und aggregieren, filtern, zippen, mappen. Eigentlich gibt es kaum Zustand in Klasseninstanzen.
Es hängt halt vom Programmierstil ab. Aber dort gibt es natürlich auch public static Methoden, die man testen konnte. Deren Funktionalität wurde aber natürlich mit Hilfe von private static Methoden zusammenkomponiert.
 
Vielleicht hast du ja ein Beispiel für so eine Methode?
In einem aktuellem Projekt werden Excel-Dateien erzeugt. Diese sind immer ganz individuell auf den Kontext bezogen. So kann es vorkommen, das immer wieder bestimmte Zellen erzeugt werden müssen, welche ich aber in anderen Berichte nicht verwenden kann, z.B.: ein rosa Hintergrund + bestimmtes Zahlenformat ...
So etwas kann man gut in eine Methode packen und einfach von verschiedenen Stellen aufrufen, z.B.: Streams, Schleifen.
 
Also bei einem aktuellen Projekt wird sehr funktional programmiert, dort gibt es fast ausschließlich static Methoden, die sehr viel mit Kombinatoren auf Streams arbeiten: z.B. Stream<Product> als Parameter rein und aggregieren, filtern, zippen, mappen. Eigentlich gibt es kaum Zustand in Klasseninstanzen.
Es hängt halt vom Programmierstil ab. Aber dort gibt es natürlich auch public static Methoden, die man testen konnte. Deren Funktionalität wurde aber natürlich mit Hilfe von private static Methoden zusammenkomponiert.
Ich möchte das nicht unnötig vertiefen, da es nicht wirklich zum Thread passt, aber: Macht es aber da nicht auch Sinn, eben diese Methoden auch zu testen? Man könnte so Methoden z.B. einfach package private lassen? So es wirklich ausgeschlossen ist, dass dies nicht auch woanders benötigt werden könnte. (Ja klar, kann ja über die public Methoden mit getestet werden, und dann verläßt man sich auf die coverage. Wobei man ja eh keine 100% hat und man hat ja auch eine gute Quote von x%. Und genau drauf schauen kann/will man nicht, denn man hat ja eh einen engen Zeitplan und man will ja den Sprint erfolgreich hinter sich bringen... Kann man ja ggf. am Ende noch mal drauf schauen, wenn noch Zeit ist ... Sind das nicht die "bekannten" Abläufe?)

Ich möchte sowas nicht ausschließen, aber wie sagt man so schön? "it smells". Das sind so typische Dinge, bei denen ich noch einmal drauf schauen würde um das Design zu prüfen.

Aber natürlich soll das jedes Team so handhaben, wie es das möchte und diese Theorie wird man in der Praxis ggf. aus guten Gründen so nicht umsetzen wollen. Aber es wäre schön, wenn sowas bewusste Entscheidungen wären.
 
Das heißt, wenn ich in der statischen Methode main den Ausdruck
Java:
waw.vorname
habe, handelt es sich dabei nicht um eine nicht-statische Variable? So ganz klar ist mir das noch nicht geworden.
Eine Instanzvariable existiert nur im Kontext einer Instanz. Ohne Instanz, keine Instanzvariable, ohne Instanzvariable kein Zugriff auf sie.

Statische Methoden oder Attribute sind solche, die explizit als static deklariert wurden. Sie existieren im Kontext einer Klasse (darum spricht man z. B. auch von Klassenvariable). Die JVM kann dadurch die main-Methode ausführen, ohne zuvor ein Objekt (= Instanz) der sie enthaltenen Klasse erstellen zu müssen.

Wie jede andere Methode kann auch eine statische Methode
a) auf statische Methoden und Attribute zugreifen
b) auf Instanzvariablen von Instanzen zugreifen

Der Unterschied ist lediglich, dass die statische Methode im Kontext der Klasse ausgeführt wird und damit this nicht existiert.

Java:
public class Person {
    private String name;

    public void setName(String neuerName) {
        name = neuerName;
        // ist gleichbedeutend zu
        // this.name = neuerName;
    }

    public static void main(String[] args) {
        // Erklärungen s. unten
    }
}
Die main-Methode ist statisch, existiert also im Kontext der Klasse Person. Sie kann ohne eine Instanz der Klasse Person aufgerufen werden, z. B. kannst Du überall in der Anwendung Person.main(null) aufrufen.

Wenn Du nun in main schreibst:
Java:
setName("Hans");
ist das gleichbedeutend zu
Java:
this.setName("Hans");
Da main aber im Kontext der Klasse ausgeführt wird, gibt es kein this und damit ist der Aufruf unzulässig.

Du kannst aber einfach eine Instanz erzeugen und die Referenz in einer lokalen Variablen speichern:
Java:
Person person = new Person();
Jetzt hast Du eine Instanz, die Du über die lokale Variable adressieren kannst:
Java:
person.setName("Hans");
Liest sich vielleicht kompliziert, ist aber ganz einfach.
 

Neue Themen


Zurück
Oben