Static vs non static und Probleme daraus

berndoa

Top Contributor
Hallo,
ich habe folgenden Code programmiert:

Java:
import java.util.Arrays;

public class Test6
{
    static int days=770; //Standard 770
    static int range=11; //numbers 1-11 possible
    static int var=7; //variables a-g, aka 7 times multiplying
    //2 zeilen oberhalb anpassbar
    static int power=24;
    
    
    static int maxval=range+var-1; //11+7-1=18-1=17, 1 box less

  static long goodtuples = 0L;
  static long alltuples = 1L * (long) Math.pow (range, var);
  static double prob = 0.0;



  static int[] tuple1 = new int[range-1];
  static int[] tuple2 = new int[range];

  static int[] mintuple = new int[range-1];
    //{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  static int[] maxtuple = new int [range-1];
    //{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
 
  static double co=pow(1.1,power);


  public static void main (String args[])
  {
        
        if(args.length>0){
            days=Integer.parseInt(args[0]);
          var= (int)(days/((double) 110));
            power=(int)(days/((double) 30));
      System.out.println ("var= "+var+" power= "+power);
            maxval=range+var-1;
      tuple1 = new int[range-1];
      tuple2 = new int[range];
      mintuple = new int[range-1];
      maxtuple = new int [range-1];
      co=pow(1.1,power);
            
            goodtuples = 0L;
            alltuples = 1L * (long) Math.pow (range, var);
            prob = 0.0;
            
        }
        prework();
    calc ();
  }


    public static void prework(){
        for (int i=0;i<range-1;i++){
          mintuple[i]=i;
        }
        
        for (int i=0;i<range-1;i++){
          maxtuple[i]=(maxval-range+1)+i;
        }
        
        return;
    }

//Calculate the odds
  public static void calc (){ //f

    for (int i = 0; i < tuple1.length; i++){
        tuple1[i] = mintuple[i];
    }

    process (tuple1);

    while (!Arrays.equals (tuple1, maxtuple)){
      increase (tuple1);
      process (tuple1);

    }

    //final result for probabilty
    prob = prob + (double) goodtuples / (double) alltuples;
        /*
    System.out.println ("");
    System.out.println ("");
    System.out.println ("");
    System.out.println ("goodtuples: " + goodtuples);
    System.out.println ("alltuples: " + alltuples);
        */
    System.out.println ("Final probability: " + prob);


  }

//add +1 to tuple
  public static boolean increase (int[]tuple1){ //f
    int c = tuple1.length - 1;
    while (!(tuple1[c] < maxtuple[c])){
            c--;
            if (c < 0){
                return false;
            }
    }

    tuple1[c]++;

    int i = 1;
    while (c + i < tuple1.length){
            tuple1[c + i] = tuple1[c] + i;
            i++;
    }
    return true;
  }

//Calculate follow up tuple and check condition
  public static boolean process (int[]tuple1){ //f
    //calculate second tuple       
    tuple2[0] = tuple1[0] - (-1) - 1;//=tuple1[0]+0
    for (int i = 1; i < tuple1.length; i++){
        tuple2[i] = tuple1[i] - tuple1[i - 1] - 1;
    }
    tuple2[tuple2.length-1] = maxval - tuple1[tuple1.length-1] - 1;

    //berechne funktionswert
    double result = 1.0;
    for (int i = 0; i < range; i++){
        result = (double) result *pow(((45+(double)i)*1.5/50), tuple2[i]);
    }

    //check if function value above threshold
    boolean result2 = (result >= co);

    if (result2){
      long m=1L;
            m=m*(long)fac(var);
            for(int i=0;i<tuple2.length;i++){
                if(tuple2[i]>1){
                    m=m/((long)fac(tuple2[i]));
                }
            }
            goodtuples = goodtuples+((long)m);
        
            /*
        System.out.print ("Tuple1=");
      printer(tuple1);
      System.out.print ("Tuple2=");
      printer(tuple2);
            System.out.println("m= "+m);
      System.out.println ("result= "+result);
            System.out.println();
            */
        }
    return result2;
  }

//Array ausdrucken
  public static void printer (int[]tuple){
    for (int i = 0; i < tuple.length; i++){
            System.out.print (" " + tuple[i]);
    }
    System.out.println ("");
  }

//a^b
  public static double pow(double a, int b){
    double result=1.0;
    for(int i=1;i<=b;i++){
            result=result*a;
    }
        return result;
  }

//a!
  public static int fac(int a){
        int result=1;
        for(int i=1;i<=a;i++){
            result=result*i;
        }
        return result;
  }

}

Was er jetzt im Detail tut, ist eher nebensächlich.
Ich habe nur 2 eher grundsätzliche Probleme damit:
Anfangs hatte ich alle vorkommenden Variabeln und Methoden ohne "static" davor, nur die Main Methode hatte (wie erforderlich) static dabei.

Beim Compilieren kamen dann aber Fehlermeldung über Fehlermeldung.
Statische methode darf keine nichtstatische Aufrufen,
keine nicht statische Variable in statischem kontext, etc.

Darum sit nun überall static davor, das programm tut zwar was es soll aber das war nur ein vorübergehender Fix.
Wie kann ich das richtig machen mit dem static?
Weil wenn ich überall static wegmache ausser bei der main Methode, kommen garantiert wieder dutzende Fehlermeldungen :-/


Was mir auch (negativ) auffiel:
ich habe die Klasse so gebaut (oder zumindest war es so gedacht) dass die vorkommenden Variabeln auch ohne Konsolenparameter einen default Wert haben.
Und wird die Klasse mit passenden Parameter aufgerufen, dann werden eben erst die Variabeln mit den übergebenen Werten übershcrieben und dann das Eigentliche gemacht.

Jetzt hatte ich aus Gründen eine 2. klasse gebaut, die im Prinzip der Reihe nahc diese Klasse mit verschiedenen parametern aufrufen soll.
Hierzu hatte ich bspw.
Java:
Test6.main(1);
Test6.main(2);
Test6.main(3);
als Code in der 2. klasse.

Beim Ausführen habe ich dann gemerkt dass, nachdem die klasse mit parameter 1 erstmals aufgerufen und auch fertig war, aber offenbar die vorhandenen Variabeln nicht gelöscht wurden oder so, jedenfalls kamen bei späteren Aufrufen immer unerwartertere Resultate raus.
Ich vermute mal dass es auch mit dem ganzen Static Kram zu tun hat aber ich weiß es nicht genau.


kann mir da bitte Jemand weiterhelfen bei dem Ganzen?

Ist es überhaupt richtig so, eine andere klasse über deren main methode aufzurufen? Oder macht man da normalerweise das anders?
 
Beim Compilieren kamen dann aber Fehlermeldung über Fehlermeldung.
Statische methode darf keine nichtstatische Aufrufen,
keine nicht statische Variable in statischem kontext, etc.
Ja, Du brauchst in dem Fall einfach eine Instanz der Klasse.

Ich vermute mal dass es auch mit dem ganzen Static Kram zu tun hat aber ich weiß es nicht genau.
Klar. Eine static-Variable ist globaler Zustand, der an der Klasse hängt.

Regel: mach nichts static außer main. Erzeuge in main ein Objekt und verwende dieses.

Ist es überhaupt richtig so, eine andere klasse über deren main methode aufzurufen? Oder macht man da normalerweise das anders?
Die main-Methode ist eine ganz normale, statische Methode, die Du natürlich aufrufen kannst. Beim Programmstart erledigt das die JVM für Dich. Der Parameter (das String-Array) entspricht dann den Argumenten, die Du beim Aufruf mitgibst.

Allerdings: mit Test.main(1) wird das nicht funktionieren, weil ein String-Array erwartet wird. Du bräuchtest dann schon etwas wie new Test.main(new String[]{"1"}).
 
Ist es überhaupt richtig so, eine andere klasse über deren main methode aufzurufen? Oder macht man da normalerweise das anders?
Normalerweise gibt es nur eine Klasse mit einer main() Methode. Mittels dieser wird das gesamte Programm gestartet. Darin werden i.d.R. Instanzen von anderen Klassen erzeugt und Methoden dieser Instanzen aufgerufen.

Ein fiktives Beispiel:
Java:
class Main {
 
    public static void main(String[] args) {
     
        Player one = new Player("Hans"); // es gibt eine Klasse Player, von der eine Instanz erzeugt wird
        Player two = new Player("Fritz");
     
        Game game = new Game(one, two); // es gibt eine Klasse Game, der die beiden Spieler bei der Erzeugung der Instanz übergeben werden
        game.start(); // das Spiel wird durch Aufruf der Methode start() (auf die Instanz der Klasse Game) begonnen
    }
}

In den anderen Klassen werden dann auch wieder Instanzen von weiteren Klassen erzeugt. In der Praxis ist es häufig so, dass in der main() Methode nur sehr wenig Anweisungen stehen.
 
Zuletzt bearbeitet:
Für die static Fehlermeldungen braucht es nicht mal das 2. Programm.
Ich habe mal im Ursprungsprogramm überall die static wieder entfernt:

Java:
import java.util.Arrays;

public class Test7
{
    int days=770; //Standard 770
  int range=11; //numbers 1-11 possible
    int var=7; //variables a-g, aka 7 times multiplying
    //2 zeilen oberhalb anpassbar
    int power=24;
    
    
    int maxval=range+var-1; //11+7-1=18-1=17, 1 box less

  long goodtuples = 0L;
  long alltuples = 1L * (long) Math.pow (range, var);
  double prob = 0.0;



  int[] tuple1 = new int[range-1];
  int[] tuple2 = new int[range];

  int[] mintuple = new int[range-1];
    //{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  int[] maxtuple = new int [range-1];
    //{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
 
  double co=pow(1.1,power);


  public static void main (String args[])
  {
        
        if(args.length>0){
            days=Integer.parseInt(args[0]);
          var= (int)(days/((double) 110));
            power=(int)(days/((double) 30));
      System.out.println ("var= "+var+" power= "+power);
            maxval=range+var-1;
      tuple1 = new int[range-1];
      tuple2 = new int[range];
      mintuple = new int[range-1];
      maxtuple = new int [range-1];
      co=pow(1.1,power);
            
            goodtuples = 0L;
            alltuples = 1L * (long) Math.pow (range, var);
            prob = 0.0;
            
        }
        prework();
    calc ();
  }


    public void prework(){
        for (int i=0;i<range-1;i++){
          mintuple[i]=i;
        }
        
        for (int i=0;i<range-1;i++){
          maxtuple[i]=(maxval-range+1)+i;
        }
        
        return;
    }

//Calculate the odds
  public void calc (){ //f

    for (int i = 0; i < tuple1.length; i++){
        tuple1[i] = mintuple[i];
    }

    process (tuple1);

    while (!Arrays.equals (tuple1, maxtuple)){
      increase (tuple1);
      process (tuple1);

    }

    //final result for probabilty
    prob = prob + (double) goodtuples / (double) alltuples;
        /*
    System.out.println ("");
    System.out.println ("");
    System.out.println ("");
    System.out.println ("goodtuples: " + goodtuples);
    System.out.println ("alltuples: " + alltuples);
        */
    System.out.println ("Final probability: " + prob);


  }

//add +1 to tuple
  public boolean increase (int[]tuple1){ //f
    int c = tuple1.length - 1;
    while (!(tuple1[c] < maxtuple[c])){
            c--;
            if (c < 0){
                return false;
            }
    }

    tuple1[c]++;

    int i = 1;
    while (c + i < tuple1.length){
            tuple1[c + i] = tuple1[c] + i;
            i++;
    }
    return true;
  }

//Calculate follow up tuple and check condition
  public boolean process (int[]tuple1){ //f
    //calculate second tuple       
    tuple2[0] = tuple1[0] - (-1) - 1;//=tuple1[0]+0
    for (int i = 1; i < tuple1.length; i++){
        tuple2[i] = tuple1[i] - tuple1[i - 1] - 1;
    }
    tuple2[tuple2.length-1] = maxval - tuple1[tuple1.length-1] - 1;

    //berechne funktionswert
    double result = 1.0;
    for (int i = 0; i < range; i++){
        result = (double) result *pow(((45+(double)i)*1.5/50), tuple2[i]);
    }

    //check if function value above threshold
    boolean result2 = (result >= co);

    if (result2){
      long m=1L;
            m=m*(long)fac(var);
            for(int i=0;i<tuple2.length;i++){
                if(tuple2[i]>1){
                    m=m/((long)fac(tuple2[i]));
                }
            }
            goodtuples = goodtuples+((long)m);
        
            /*
        System.out.print ("Tuple1=");
      printer(tuple1);
      System.out.print ("Tuple2=");
      printer(tuple2);
            System.out.println("m= "+m);
      System.out.println ("result= "+result);
            System.out.println();
            */
        }
    return result2;
  }

//Array ausdrucken
  public void printer (int[]tuple){
    for (int i = 0; i < tuple.length; i++){
            System.out.print (" " + tuple[i]);
    }
    System.out.println ("");
  }

//a^b
  public double pow(double a, int b){
    double result=1.0;
    for(int i=1;i<=b;i++){
            result=result*a;
    }
        return result;
  }

//a!
  public int fac(int a){
        int result=1;
        for(int i=1;i<=a;i++){
            result=result*i;
        }
        return result;
  }

}


Wie zu erwarten war, werde ich wieder überschüttet von Fehlermeldungen (siehe Screenshot) :-/

Woran liegt das, habe ich was Grundlegendes übersehen?

Ich erinnere mich an dutzende Programme in der Vergangenheit wo ich auch Attribute und Alles hatte,
aber sich der Compiler nicht aufgeregt hat weil in der statischen Main methode nicht-statische Variabeln und Methoden benutzt werden :-/
 

Anhänge

  • static errors.png
    static errors.png
    134,9 KB · Aufrufe: 0
Ich erinnere mich an dutzende Programme in der Vergangenheit wo ich auch Attribute und Alles hatte,
aber sich der Compiler nicht aufgeregt hat weil in der statischen Main methode nicht-statische Variabeln und Methoden benutzt werden :-/
Da erinnerst Du Dich falsch. Der Compiler muss meckern. Du kannst nicht aus statischen Methoden heraus (Nachtrag: ohne Objekt/Instanz) auf Instanz-Methoden bzw. Instanzvariablen zugreifen. Das ist schlicht nicht möglich.
 
Ich muss in der Klasse selbst eine Instanz der Klasse aufrufen um auch ihre Methoden benutzen zu können? :O

Puh, also irgendwie scheinen da meine Erinnerungen aus Informatik grundkurs richtig mies zu sein :-/

Oder vielleicht sollte ich einfach mal einen Konstruktor dazu bauen.

Dss heißt dann wohl auh, die Main methode kann keine einzige Methode oder Variabl direkt benutzen :-/
 
Ich muss in der Klasse selbst eine Instanz der Klasse aufrufen um auch ihre Methoden benutzen zu können? :O
Nein, das muss nicht innerhalb der Klasse passieren 🙂

Oder vielleicht sollte ich einfach mal einen Konstruktor dazu bauen.
Das hat mit dem Konstruktor wenig zu tun.

Dss heißt dann wohl auh, die Main methode kann keine einzige Methode oder Variabl direkt benutzen :-/
Keine Instanzvariable/-methode, richtig.

Das kannst Du Dir auch ganz einfach überlegen: die Klasse ist der Bauplan für Objekte. Jedes Objekt hat seine eigenen Attribute und die Methoden dazu, die mit diesen Attributen arbeiten. Wie soll jetzt ohne Objekt mit den Attributen eines Objekts gearbeitet werden können?!? Geht nicht.

Wenn Du Klassenvariablen/-methoden (= static) verwendest, dann würde das funktionieren - hat nur nichts mehr mit Objektorientierung zu tun.
 
Nein, das muss nicht innerhalb der Klasse passieren 🙂


Das hat mit dem Konstruktor wenig zu tun.


Keine Instanzvariable/-methode, richtig.

Das kannst Du Dir auch ganz einfach überlegen: die Klasse ist der Bauplan für Objekte. Jedes Objekt hat seine eigenen Attribute und die Methoden dazu, die mit diesen Attributen arbeiten. Wie soll jetzt ohne Objekt mit den Attributen eines Objekts gearbeitet werden können?!? Geht nicht.

Wenn Du Klassenvariablen/-methoden (= static) verwendest, dann würde das funktionieren - hat nur nichts mehr mit Objektorientierung zu tun.
Naja, jetzt mal rein von der Logik her:
Wenn ich IN einer Klasse bin (z.B. in deren Main methode, konstruktor, sosntwo), die bestimmte Methoden und (ggbfls. mit default Werten belegte) Attribute hat, erwarte ich eigentlich schon dass ich auf diese von innehralb der Klasse gelegenen Methoden aus zugreifen kann.Von mir aus auch über this.variable oder so.
Aber scheinbar gilt das nicht für die statische main Methode :-/

Aber gut, ich bring da offenbar was durcheinander.
 
Wenn ich IN einer Klasse bin (z.B. in deren Main methode, konstruktor, sosntwo), die bestimmte Methoden und (ggbfls. mit default Werten belegte) Attribute hat, erwarte ich eigentlich schon dass ich auf diese von innehralb der Klasse gelegenen Methoden aus zugreifen kann.
Kannst Du ja: von statischen Methoden aus auf statische Variablen und statische Methoden. Von nicht-statischen Methoden aus auf alles.

Von mir aus auch über this.variable oder so.
Genau das ist ja der Punkt: this ist eine Referenz auf ein Objekt - da es in statischen Methoden kein Objekt gibt, gibts auch kein this.
 
erwarte ich eigentlich schon dass ich auf diese von innehralb der Klasse gelegenen Methoden aus zugreifen kann
Welche Ausgabe würdest du dir denn von der markierten Zeile in folgendem Beispiel wünschen?
Java:
public class MyClass {
    int a;

    public MyClass(int a) {
        this.a = a;
    }

    public static void main(String[] args) {
        MyClass object1 = new MyClass(1);
        MyClass object2 = new MyClass(2);
        System.out.println(a);                 // Was soll hier ausgegeben werden?
        System.out.println(object1.a);         // Ausgabe: 1
        System.out.println(object2.a);         // Ausgabe: 2
    }

}
 
Evtl. kann ich etwas zum Verständnis beitragen:
Bei Java handelt es sich um eine Objektorientierte Entwicklung. Das bedeutet, dass man ind em Programm in Objekten denkt. Du hast also diverse Objekte und die interagieren.

Du hast also Klassen (=> Baupläne) und daraus erzeugst Du Instanzen (=> Objekte). Und innerhalb der Vorstellung machen diese Baupläne an sich nichts. Du hast ein Auto. Das enthält ein Motor, ein Getriebe, ... Diese Objekte interagieren miteinander. Und es wird ein Interface abgebildet, und daher kann jemand mit Führerschein jedes "KFZMitGangschaltung" steuern.

Das ist also eine relativ interessante Vorstellung und Herangehensweise. Denn das entspricht ja auch dem, das wir ständig machen. Und da ist es üblich, dass wir nur mit den Objekten interagieren. Wie interagierst Du mit dem Bauplan eines Apfels? In der Realität haben wir oft nicht einmal einen Bauplan, auf den wir zurück greifen können.

Das ist in manchen Sprachen auch deutlich intensiver gemacht. Ich finde in dem Bereich z.B. Smalltalk sehr gut und interessant. Da geht der Ansatz halt so weit, dass hier dann gesagt wird: Die Objekte kommunizieren miteinander. Das ist also auch eine recht interessante Sichtweise, die das objektorientierte auch deutlich macht.
 
Wenn ich IN einer Klasse bin...
Aber scheinbar gilt das nicht für die statische main Methode :-/
Der ausdruck "ich bin in einer Klasse" ist schon mal recht ... vage, sagt eigentlich gar nichts aus, da alle Quellcodes in Klassen gespeichert sind.

Statische Methoden haben den Sinn, dass man darauf zugreifen kann, ohne eine Instanz der Klasse zu erstellen.
Deshalb ist auch main(...) statisch. Die JRE weiß ja nichts über die Klasse bis auf den Namen, ruft darin main auf, um dein Programm anzustoßen. Wie jeder andere statische Methode erzeugt main aber nicht automatische eine Instanz deiner Klasse, das musst du manuell machen. main kann lediglich auf andere statische Methoden/Variablen und auf die Methoden von in main erzeugten Instanzen zugreifen.

Wenn die Methoden einfach nur Hilfsmethoden sind, denen man alle benötigten Parameter übergibt und nur auf Hilfsmethoden zugreifen, dann sollten sie statisch sein (ein gutes Beispiel sind die Methoden in java.lang.Math). gehören sie aber zu einem Objekt der Klasse, in denen sie gespeichert sind, dann können sie nicht statisch sein.
Zuerst mal muss man das Objekt überhaupt erzeugen, damit man was damit machen kann.

Machen wir's mal á la Frankenstein. Was würde die "lebe()" Methode denn machen, wenn sie nicht zu seinem zusammengebastelten Wesen gehören würde? Nein, Frankenstein musste das Ding erst mal erstellen, bevor er ihm das Kommando geben konnte:
Java:
new AusLeichenTeilenZusammengesetztesWesen().lebe();
 

Zurück
Oben