Java ruft Methoden nicht der Reihe nach auf

knutmithut

Mitglied
Hi,

nachdem ich auf Google und hier in der Sufu nichts gefunden habe, habe ich mir mal einen Account gemacht damit ich mein Problem mal posten kann.

Also, ich arbeite zurzeit an einem eigenen Schachprogramm welches ich unter anderem für Bewerbungszwecke als "Fähigkeitenpräsentation" verwenden will. Ich habe jetzt aber einen komischen Fehler.

Nämlich, meine Methoden werden nicht der Reihe nach aufgerufen. In meiner Main starte ich zuerst mit der initialisierung der Gui, danach mach ich eine Instanz ich einer Klasse die erstmal unwichtig ist, und danach mach ich eine Instanz von meinem Figur_Manager, welche im Konstruktor eine Methode aufruft, welche die Gui füllen soll bzw. die Schachfiguren auf die Felder setzt. Das ist meine Main:

Java:
    public static void main(String[] args) {
        gui_man = new Gui_Manager();
        move_man = new Move_Manager();
        fig_man = new Figur_Manager();
       
    //    turns = 0;
    }

Gui_Manager initialisiert die Gui, Figur_Manager füllt die Gui beim initialisieren mit den Schachfiguren. Aus einem mir unbekannten Grund, wird Figur_Manager mehr oder weniger vor dem Gui_Manager ausgeführt. Dadurch bekomm ich einen Nullpointer-Error.
Ich habe nach langem rumprobieren und Fehlersuche folgendes ausprobiert:

Java:
    public static void main(String[] args) {
        gui_man = new Gui_Manager();
        for(int i = 0; i < 100000; i++){
            System.out.println("lets waste some time");
        }
        move_man = new Move_Manager();
        fig_man = new Figur_Manager();
       
    //    turns = 0;
    }

Wenn ich das mache, dann funktioniert mein Programm. Die Gui wird gestartet und ordnungsgemäß mit den Schachfiguren gefüllt. Ich habe die vermutung das mein Rechner meint er muss Multithreading machen und deswegen führt er Figur_Manager zusammen mit Gui_Manager aus, wodurch ich den Nullpointer-Error bekomm weil der Figur_Manager auf Objekte zugreift die bis dahin noch nicht existieren.

Ich poste hier auch nochmal meinen Fehlercode:

Gui wird initialisiert
Figurmanager wird initialisiert
Exception in thread "main" java.lang.NullPointerException
at gui_manager.GuiSwing.setFigur(GuiSwing.java:105)
at gui_manager.Gui_Manager.setKoords(Gui_Manager.java:18)
at main_manager.Main.setKoords(Main.java:100)
at figur_manager.Figur_Manager.setFigur(Figur_Manager.java:60)
at figur_manager.Figur.<init>(Figur.java:25)
at figur_manager.Bauer.<init>(Bauer.java:11)
at figur_manager.Figur_Manager.init(Figur_Manager.java:26)
at figur_manager.Figur_Manager.<init>(Figur_Manager.java:14)
at main_manager.Main.main(Main.java:25)
Gui wurde initialisiert

Ich habe die printlns am Anfang des Konstruktors und in der letzten Zeile der letzten Methode die vom jeweiligen Konstrutor aufgerufen wird. Wenn ich im Debugger durchgehe funktioniert alles einwandfrei, da er ja alles sauber und brav nacheinander abarbeitet.

Falls noch Fragen offen sind beantworte ich diese gerne. Hoffentlich könnt ihr mir helfen. 🙂
 
Ohne den Inhalt der entsprechenden Klassen zu sehen, kann man nur raten. Wäre also sinnvoll wenn du uns auch den Inhalt der anderen Klassen zeigst (Gui_Manager, Figur_Manager, etc.)

Ansonsten solltest du dich dringend an die Java Konventionen halten. Klassennamen schreibt man in UpperCamelCase, also GuiManager anstatt Gui_Manager
 
Vielen dank für deine Antwort. Und danke für den Hinweiß mit den Konventionen, ich schätze ich muss mich da nochmal informieren, wenn ich mein Programm als Fähigkeitenpräsentation verwenden will. 😉

Klasse Gui_Manager (das mit dem Underline pass ich später an):

Java:
import figur_manager.Figur;

public class Gui_Manager {
    private GuiSwing gui;

    public Gui_Manager() {
        System.out.println("Gui wird initialisiert");
        gui = new GuiSwing();
              
    }

    public void setKoords(int x, int y, Figur f) {
        gui.setFigur(x, y, f.getRoleId(), f.getColor());
      
    }
Klasse GuiSwing (ohne Imports, da nur Gui-Elemente importiert werden):
Java:
public class GuiSwing implements ActionListener{
  
    private JToggleButton[][] spielfeld = new JToggleButton[10][10];  // Zugunsten der Einfachheit wird mit leeren Feldern gearbeitet
    private JLabel[][] beschriftung = new JLabel[10][10];          

    private JFrame frame;

    /**
     * Launch the application.
     */
    public GuiSwing() {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    initialize();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

  
  

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 600, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new MigLayout("wrap 10", "[grow]", "[grow]"));
      
    //    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);

      
        for(int j = 0; j < 10; j++){
            for(int i = 0; i < 10; i++){
                if(i == 0 || i == 9){
                    if(j != 0 && j != 9){
                        beschriftung[i][j] = new JLabel(Character.toString((char) (64 + j)));
                        beschriftung[i][j].setHorizontalAlignment(SwingConstants.CENTER);
                        frame.getContentPane().add(beschriftung[i][j], "grow");
                    }
                    else {
                        beschriftung[i][j] = new JLabel("");
                        frame.getContentPane().add(beschriftung[i][j], "grow");
                    }
                }
                else if(j == 0 || j == 9){
                    beschriftung[i][j] = new JLabel("" + i);
                    beschriftung[i][j].setHorizontalAlignment(SwingConstants.CENTER);
                    frame.getContentPane().add(beschriftung[i][j], "grow");
                }
                else{
                    spielfeld[i][j] = new JToggleButton(i + "" + j);
                    spielfeld[i][j].addActionListener(this);
                    frame.getContentPane().add(spielfeld[i][j], "grow");
                }
            }
        }
        frame.setVisible(true);
        System.out.println("Gui wurde initialisiert");
    }

    public void actionPerformed(ActionEvent ae) {
        for(int i = 1; i < 9; i++){
            for(int j = 1; j < 9; j++){
                if(ae.getSource() == spielfeld[i][j]){              
                    System.out.println(i + "&" + j);
                    //TODO
                }
            }
        }
      
    }


/*    public JToggleButton[][] getSpielfeld() {
        return spielfeld;
    }


    public void setSpielfeld(JToggleButton[][] spielfeld) {
        this.spielfeld = spielfeld;
    }*/
  
    public void setFigur(int x, int y, int roleId, int color){
        if(color == 0){
            spielfeld[x][y].setText(roleId + " W");
        }else{
            spielfeld[x][y].setText(roleId + " S");
        }
    }
  
  
}


Der FigurManager erstellt bei Init die einzelnen Schachfiguren. Das läuft so ab, es wird ein neues Objekt von z.B. Bauer gemacht, der Konstruktor von (z.B.) Bauer erstellt ein neues Objekt Figur und gibt sich selbst in die Hände von dem Objekt Figur. Das Objekt Figur geht daraufhin zurück zum Figur_Manager und will der Gui hinzugefügt werden.

Code FigurManager:

Java:
import main_manager.Main;

public class Figur_Manager {
    private static Figur[][] fig = new Figur[10][10]; // zur einfacheren handhabung haben die arrays fig und koords die gleiche größe
    // belegungen außerhalb des rahmens (TODO) sind nicht möglich
  

  
    public Figur_Manager(){
        System.out.println("Figurmanager wird initialisiert");
        init();
        System.out.println("Figur_Manager wurde initialisiert");
    }
  
    public void figur_moved(int x1, int y1, int x2, int y2){
        fig[x2][y2] = fig[x1][y1];
        fig[x1][y1] = null;
    }
  
    public void init(){

        for(int i = 1; i < 9; i++)
        {
            new Bauer(i, 2, 0);
            new Bauer(i, 7, 1);
        }
         // (int x, int y, int color) x = A-H     y = 1-8
        new Turm(1, 1, 0);
        new Turm(8, 1, 0);
        new Turm(1, 8, 1);
        new Turm(8, 8, 1);
        new Laeufer(2, 1, 0);
        new Laeufer(7, 1, 0);
        new Laeufer(2, 8, 1);
        new Laeufer(7, 8, 1);
        new Springer(3, 1, 0);
        new Springer(6, 1, 0);
        new Springer(3, 8, 1);
        new Springer(6, 8, 1);
        new Koenig(5, 1, 0);
        new Koenig(5, 8, 1);
        new Koenigin(4, 1, 0);
        new Koenigin(4, 8, 1);
      
      
    }
  
    public Figur[][] getAllFigurs(){
        return fig;
    }
  
  
    public static void setFigur(int x, int y, Figur f){
        f.setX(x);
        f.setY(y);
        fig[x][y] = f;
        Main.setKoords(x, y, f);
    }
  
  
    public Figur getFigur(int x, int y)
    {
        return fig[x][y];
    }

}

Code (z.B.) Bauer:

Java:
public class Bauer{


    private static int roleId = 5;

    public Bauer(int x, int y, int color)
    {
        new Figur(x, y, Integer.parseInt(roleId + "" + color + "" + x + "" + y), roleId, color);
      
    }
}

Code Figur (Getter und Setter sind hier nicht relevant und werden zur Übersichtlichkeit weggelassen):
Java:
import figur_manager.Figur_Manager;

public class Figur {
  
    //public static Figur_Manager fig_man = Main.fig_man;
    private int figurId;
    private int x;
    private int y;
    private int roleId;
    private int color;
    private boolean has_moved = false;
    private boolean alive = true;
  
    public Figur(int x, int y, int figurId, int role,int color)
    {
        this.figurId = figurId;
        this.roleId = role;
        this.color = color;
        this.x = x;
        this.y = y;
      
        Figur_Manager.setFigur(x, y, this);
    }

Und zu guter letzt noch ein Code-Snippet aus der Main-Klasse, welche den setKoords Befehl vom FigurManager an den GuiManager weiterleitet.

Java:
    public static void setKoords(int x, int y, Figur f){
        gui_man.setKoords(x, y, f);
    }


P.S. Das ist mein erstes Projekt wo ich versuche alles möglichst Objektorientiert zu machen. Falls das, was ihr jetzt von meinem Projekt kennt, einfach nur schlecht ist, teilt es mir bitte mit. Ich will das bei Bewerbungen abgeben und möcht mich nicht unnötig blamieren... ;D
 
Zuletzt bearbeitet:
Was meinst du wohl warum die Methode invokeLater, invokeLater heißt?

Damit startest du einen neuen Thread der im EDT läuft und die Methode kehrt dann sofort zurück. Das UI wird dann irgendwann erstellt wenn der EDT Thread mal Zeit dafür von der CPU zugewiesen bekommt. In der Zwischenzeit dein Programm aber weiter und erzeugt brav seine anderen Manager.

Gruß

Claus
 
Boom, Volltreffer. Vielen dank für deine Hilfe!
Habe nachdem ich die Klasse erstellt habe die Main Methode in einen Konstruktor umgeschrieben und garnicht weiter über dieses invokeLater nachgedacht.

Habe jetzt mal invokeLater in invokeAndWait umgeschrieben und die Vorschläge und Wünsche von Eclipse generieren lassen und siehe da, es funktioniert!

Java:
    public GuiSwing() {
        try {
            EventQueue.invokeAndWait(new Runnable() {
                public void run() {
                    try {
                        initialize();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

Ich werde mich wohl noch etwas informieren müssen und die Methode nochmal anpassen müssen (2x Exception Handling scheint mir zuviel) aber mein Problem hast du gelöst. Nochmal vielen Dank!
 
Mal ganz abgesehen von deinem Problem. Schau dir bitte noch mal die Grundlagen von OOP an und wie man Objekte in Relation zueinander setzt. Kleiner Tipp: Wenn du überall static aus deinem Code löschen kannst bist du auf dem richtigen Weg.
 
Schau dir bitte noch mal die Grundlagen von OOP an und wie man Objekte in Relation zueinander setzt.
Hier ein Beispiel, wie man es NICHT machen sollte:
in Figur_Manager.init rufst du mehrfach den Konstruktor von Bauer auf. Die erzeugte Instanz von Bauer wird aber nirgendwo gespeichert. Stattdessen ruft der Konstruktor von Bauer den Konstruktor von Figur auf. Man sollte vermuten, dass Bauer die Klasse Figur erweitert, aber Bauer und Figur stehen in keinerlei Beziehung zueinander. Effektiv sorgt die Bauer-Instanz nur dafür, dass ein Figur-Objekt mit der richtigen roleId erzeugt wird. Danach sollte die Bauer-Instanz wieder vom gc abgeräumt werden. Im Konstruktor von Figur wiederum wird eine Figur angelegt und über eine statische Methode der Klasse FigurManager hinzugefügt. Das ganze Konstrukt ist ein gutes Beispiel von "Von hinten durch die Brust ins Auge".
Besser: in FigurManager.init erzeugst du Instanzen von Bauer, Turm usw. und speicherst die Instanzen direkt in Figur[][] fig. Dann muss fig auch nicht mehr statisch sein.

Worauf wolltest du dich mit deinem bisherigen Konzept denn bewerben?
 
Vielen Dank für die viele konstruktive Kritik. Mir ist bewusst das sich meine OOP-Kenntnisse in Grenzen halten. Deswegen Danke für all eure Tipps, Hinweise, Verbesserungsvorschläge und Zeit/Mühen.

Ich werde dann wohl mal Static aus meinem Code verbannen, mich mit MVC außeinander setzten (nachdem ich den ersten Absatz gelesen hab, scheint das genau das zu sein was ich will) und versuchen nichtmehr "von hinten durch die Brust ins Auge" zu gelangen... 😉

@stg Danke für deine ehrliche Meinung. Falls dir noch etwas aufgefallen ist, was die anderen noch nicht angesprochen haben würde es mich freuen das zu hören. Möglichst konstruktiv bitte. 😉

P.S. @Harry Kane Ich wollte mich mit dem Konzept für nichts bestimmtes Bewerben sondern eher dann, wenn es fertig ist, bei meinem Bewerbungen oder Vorstellungsgesprächen mit abgeben. Da meine Stadt allerdings hauptsächlich aus SAP-Betrieben und Rentenversicherungen besteht, werde ich vorrausichtlich später mal ABAP machen.
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben