Was habe ich falsch gemacht? Hilfe!

Kapfski

Mitglied
Ich bekomme bei folgendem Code, zB bei insertAt immer einen stackOverflow bei toString. Kann mir bitte jemand helfen?!
Java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/**
 *
 * Beschreibung
 *
 * @version 1.0 vom 13.01.2021
 * @author
 */

public class GUI_DynArray extends JFrame {
  // Anfang Attribute
  private DynArray MeineDynamischeReihung = new DynArray();
 
  private JButton butIsEmpty = new JButton();
  private JLabel lblIsEmpy = new JLabel();
  private JTextField txtEingabe = new JTextField();
  private JNumberField numIndex = new JNumberField();
  private JButton butAppend = new JButton();
  private JButton butSetItem = new JButton();
  private JButton butInsertAt = new JButton();
  private JButton butDelete = new JButton();
  private JButton butGetItem = new JButton();
  private JButton butGetLength = new JButton();
  private JTextArea araAusgabe = new JTextArea("");
  private JScrollPane araAusgabeScrollPane = new JScrollPane(araAusgabe);
  // Ende Attribute
 
  public GUI_DynArray() {
    // Frame-Initialisierung
    super();
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    int frameWidth = 730;
    int frameHeight = 715;
    setSize(frameWidth, frameHeight);
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (d.width - getSize().width) / 2;
    int y = (d.height - getSize().height) / 2;
    setLocation(x, y);
    setTitle("GUI_DynArray");
    setResizable(false);
    Container cp = getContentPane();
    cp.setLayout(null);
    // Anfang Komponenten
    
    butIsEmpty.setBounds(16, 16, 161, 41);
    butIsEmpty.setText("isEmpty");
    butIsEmpty.setMargin(new Insets(2, 2, 2, 2));
    butIsEmpty.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butIsEmpty_ActionPerformed(evt);
      }
    });
    cp.add(butIsEmpty);
    lblIsEmpy.setBounds(192, 16, 97, 41);
    lblIsEmpy.setText("");
    cp.add(lblIsEmpy);
    txtEingabe.setBounds(16, 72, 281, 41);
    cp.add(txtEingabe);
    numIndex.setBounds(312, 72, 81, 41);
    numIndex.setText("");
    cp.add(numIndex);
    butAppend.setBounds(16, 128, 161, 41);
    butAppend.setText("append");
    butAppend.setMargin(new Insets(2, 2, 2, 2));
    butAppend.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butAppend_ActionPerformed(evt);
      }
    });
    cp.add(butAppend);
    butSetItem.setBounds(16, 184, 161, 41);
    butSetItem.setText("setItem");
    butSetItem.setMargin(new Insets(2, 2, 2, 2));
    butSetItem.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butSetItem_ActionPerformed(evt);
      }
    });
    cp.add(butSetItem);
    butInsertAt.setBounds(16, 240, 161, 41);
    butInsertAt.setText("insertAt");
    butInsertAt.setMargin(new Insets(2, 2, 2, 2));
    butInsertAt.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butInsertAt_ActionPerformed(evt);
      }
    });
    cp.add(butInsertAt);
    butDelete.setBounds(16, 296, 161, 41);
    butDelete.setText("delete");
    butDelete.setMargin(new Insets(2, 2, 2, 2));
    butDelete.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butDelete_ActionPerformed(evt);
      }
    });
    cp.add(butDelete);
    butGetItem.setBounds(16, 352, 161, 41);
    butGetItem.setText("getItem");
    butGetItem.setMargin(new Insets(2, 2, 2, 2));
    butGetItem.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butGetItem_ActionPerformed(evt);
      }
    });
    cp.add(butGetItem);
    butGetLength.setBounds(16, 408, 161, 41);
    butGetLength.setText("getLength");
    butGetLength.setMargin(new Insets(2, 2, 2, 2));
    butGetLength.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        butGetLength_ActionPerformed(evt);
      }
    });
    cp.add(butGetLength);
    araAusgabeScrollPane.setBounds(191, 128, 504, 532);
    cp.add(araAusgabeScrollPane);
    // Ende Komponenten
    
    setVisible(true);
  } // end of public GUI_DynArray
 
    
 
  // Anfang Methoden
 
  public static void main(String[] args) {
    new GUI_DynArray();
  } // end of main
 
  public void butIsEmpty_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    lblIsEmpy.setText(""+MeineDynamischeReihung.isEmpty());
  } // end of butIsEmpty_ActionPerformed

  public void butAppend_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    String temp = txtEingabe.getText();
    MeineDynamischeReihung.append(temp);
    araAusgabe.setText(MeineDynamischeReihung.toString());
  } // end of butAppend_ActionPerformed

  public void butSetItem_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    String temp = txtEingabe.getText();
    int index = numIndex.getInt();
    MeineDynamischeReihung.setItem(index, temp);
    araAusgabe.setText(MeineDynamischeReihung.toString());
  } // end of butSetItem_ActionPerformed

  public void butInsertAt_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    String temp = txtEingabe.getText();
    int index = numIndex.getInt();
    MeineDynamischeReihung.insertAt(index, temp);
    araAusgabe.setText(MeineDynamischeReihung.toString());
  } // end of butInsertAt_ActionPerformed

  public void butDelete_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    int index = numIndex.getInt();
    MeineDynamischeReihung.delete(index);
    araAusgabe.setText(MeineDynamischeReihung.toString());
  } // end of butDelete_ActionPerformed

  public void butGetItem_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    int index = numIndex.getInt();
    txtEingabe.setText(MeineDynamischeReihung.getItem(index));
  } // end of butGetItem_ActionPerformed

  public void butGetLength_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    numIndex.setInt(MeineDynamischeReihung.getLength());
  } // end of butGetLength_ActionPerformed

  // Ende Methoden
} // end of class GUI_DynArray

class DynArray {
 
  private boolean frei;
  private int nr;
  private String inhalt;
  private DynArray nachfolger;
 
  public DynArray() {
    this.frei=true;
    this.nr=0;
    this.inhalt="";
  } // Ende des Konstruktors.
 
  public boolean isEmpty() {
    return this.frei;
  } // Ende von isEmpty
 
  public String getItem(int index) {
    
    // ist die aktuelle Karte diejenige mit dem gewünschten Index?
    if(this.nr == index) {
       // wenn ja, prüfe, ob die Karte "belegt" ist.
      if(!this.frei) {
          // wenn auch das der Fall ist, gib this.inhalt zurück.
          return this.inhalt;
      } else { // wenn nicht, muss eine Fehlermeldung erzeugt werden.
          return "==> Der Index existiert nicht!";
      }
    } else {
    // wenn nicht,
       // prüfe, ob es einen Nachfolger gibt.
      if(this.nachfolger!=null) {
        return this.nachfolger.getItem(index);
          // wenn ja, reiche das Problem an ihn weiter.
      } else {  // wenn nein, muss eine Fehlermeldung erzeugt werden.
        return "==> Der Index existiert nicht!";
      }
    }
  } // Ende von getItem 
 
  public void append(String s) {
    // Ist die aktuelle Karte frei?
    if(this.frei) {
      // Wenn ja, nimmt sie den Inhalt auf. Fertig.
      this.inhalt=s;
      this.frei=false;
    } else {
      // Wenn nein, prüfe, ob es einen Nachfolger gibt.
      if(this.nachfolger==null) {
        // Nachfolger anlegen
        this.nachfolger = new DynArray();
        this.nachfolger.nr = this.nr + 1;
      }
      // Nachfolger mit der Aufgabe betrauen, den Inhalt aufzunehmen.
      this.nachfolger.append(s);
    }
  } // Ende von append
 
  public void insertAt(int n, String s) {
    // negative Einfügepositionen werden ignoriert
    if(n>=0) {
      // ist die aktuelle Karte die gewünschte Position?
      if(this.nr == n) {
        // ist die Karte frei?
        if(this.frei) {
          this.frei=false;
          this.inhalt=s;
        } else {
          // Lege eine neue Dynamische Reihung an mit Namen "temp"
          DynArray temp = new DynArray();
          // Speichere eine Kopie der aktuellen Dynamischen Reihung in temp
          temp = this;
          // Speichere den neuen Inhalt auf der aktuellen Karte
          this.inhalt = s;
          // Lege die vorher angefertigte Kopie als Nachfolger fest
          this.nachfolger = temp;
          // this.nachfolger.neueNummern();
        }
      } else {
        // Gib das Problem an den Nachfolger weiter
        if(this.nachfolger==null) {
          this.nachfolger = new DynArray();
          this.nachfolger.nr = this.nr + 1;
          this.nachfolger.append(s);
        } else {
          this.nachfolger.insertAt(n, s);
        }
      }
    } 
  } // Ende von insertAt
 
  private void neueNummern() {
    this.nr = this.nr + 1;
    if(this.nachfolger != null) {
      this.nachfolger.neueNummern();
    }
  } // Ende von neueNummern
 
  public int getLength() {
    if(this.frei) {
      return 0;
    } else {
      if(this.nachfolger != null) {
        return 1 + this.nachfolger.getLength();
      } else {
        return 1;
      }
    }
  } 
 
  public void setItem(int n, String s) {
    if(n>=0) {
      if(this.nr == n) {
        this.inhalt=s;
        this.frei=false;
      } else {
        if(this.nachfolger != null) {
          this.nachfolger.setItem(n, s);
        }
      }
    }
  } // Ende von setItem
 
  public void delete(int n) {
    if(n>=0) {
      if(this.nr == n) {
        if(this.nachfolger==null) {
          this.frei=true;
        } else {
          this.frei = this.nachfolger.frei;
          this.nr = this.nachfolger.nr;
          this.inhalt = this.nachfolger.inhalt;
          this.nachfolger = this.nachfolger.nachfolger;
          this.neueNummern2();
        }
      } else {
        if(this.nachfolger!=null) {
          this.nachfolger.delete(n);
        }
      }
    } 
  } // Ende von delete
 
  private void neueNummern2() {
    this.nr = this.nr - 1;
    if(this.nachfolger != null) {
      this.neueNummern2();
    }
  } // Ende von neueNummern2
 
  public String toString() {
    if(this.frei) {
      return "===";
    }   
    if(this.nachfolger != null) {
      return "" + this.nr + ": " + this.inhalt + "\n" + this.nachfolger.toString();
    }
    return "" + this.nr + ": " + this.inhalt + "\n===";
  } // Ende von toString   
 
} // Ende von class DynArray
 
Wenn du innerhalb von:
Java:
public String toString() {
  if (this.frei) {
    return "===";
  }  
  if (this.nachfolger != null) {
    return "" + this.nr + ": " + this.inhalt + "\n" + this.nachfolger.toString();
  }
  return "" + this.nr + ": " + this.inhalt + "\n===";
}
einen StackOverflowError bekommst, dann liegt das zu 100% daran, dass du einen Zyklus in den nachfolger Referenzen hast. Es gibt also eine Kette von nachfolger Referenzen, die irgendwann wieder auf dieselbe DynArray Instanz zeigt.
 
Wenn du innerhalb von:
Java:
public String toString() {
  if (this.frei) {
    return "===";
  } 
  if (this.nachfolger != null) {
    return "" + this.nr + ": " + this.inhalt + "\n" + this.nachfolger.toString();
  }
  return "" + this.nr + ": " + this.inhalt + "\n===";
}
einen StackOverflowError bekommst, dann liegt das zu 100% daran, dass du einen Zyklus in den nachfolger Referenzen hast. Es gibt also eine Kette von nachfolger Referenzen, die irgendwann wieder auf dieselbe DynArray Instanz zeigt.
Ich glaube, das soweit verstanden zu haben, jedoch kann ich den Fehler nicht finden. Sehe vermutlich den Wald vor lauter Bäumen nicht...
 
Der Fehler ist nicht im Code sondern in der Logik.

Es gibt zwei Möglichkeiten:
1. Es sind Kreise in der Struktur erlaubt. Dann ist die Ausgabe so logisch falsch, weil Du bei einem Kreis nie abbrichst. Lösung wäre dann, dass man sich merkt, welche Nodes ausgegeben wurden und abbricht, wenn ein Node bereits ausgegeben wurde.
2. Es sind keine Kreise erlaubt. Das ist das, was ich als wahrscheinlich ansehen würde, denn bei der Ausgabe ist ja so eine Art "Ende" Symbol ("===") vorgesehen. Wären Kreise erlaubt, dann wäre dies nicht wirklich sinnvoll. In diesem Fall liegt ein Fehler im Bereich des Codes vor, der Elemente einfügt.
 
Müsstest du das nicht schon anhand der Ausgabe erkennen können? Es müssten doch Inhalte wiederholt auftauchen.
 
Müsstest du das nicht schon anhand der Ausgabe erkennen können? Es müssten doch Inhalte wiederholt auftauchen.
Es kommt ja zu keiner Ausgabe, da er den String ja erst zusammen setzt. Und da er damit nie fertig wird, gibt es keine Ausgabe.

Aber man könnte es Sichtbar machen, indem man da Ausgaben einbaut:
Java:
public String toString() {
  if (this.frei) {
    System.out.println("===");
    return "===";
  } 
  if (this.nachfolger != null) {
    System.out.println("" + this.nr + ": " + this.inhalt + "\n + this.nachfolger.toString()");
    return "" + this.nr + ": " + this.inhalt + "\n" + this.nachfolger.toString();
  }
  System.out.println("" + this.nr + ": " + this.inhalt + "\n===");
  return "" + this.nr + ": " + this.inhalt + "\n===";
}
 
Es kommt ja zu keiner Ausgabe, da er den String ja erst zusammen setzt. Und da er damit nie fertig wird, gibt es keine Ausgabe.

Aber man könnte es Sichtbar machen, indem man da Ausgaben einbaut:
Java:
public String toString() {
  if (this.frei) {
    System.out.println("===");
    return "===";
  }
  if (this.nachfolger != null) {
    System.out.println("" + this.nr + ": " + this.inhalt + "\n + this.nachfolger.toString()");
    return "" + this.nr + ": " + this.inhalt + "\n" + this.nachfolger.toString();
  }
  System.out.println("" + this.nr + ": " + this.inhalt + "\n===");
  return "" + this.nr + ": " + this.inhalt + "\n===";
}
0: 1
===
0: 1
+ this.nachfolger.toString()
1: 2
===
0: 1
+ this.nachfolger.toString()
1: 2
+ this.nachfolger.toString()
2: 23
===
0: 1
+ this.nachfolger.toString()
1: 234
+ this.nachfolger.toString()
1: 234
+ this.nachfolger.toString()
 
1: 234
+ this.nachfolger.toString()
1: 234
+ this.nachfolger.toString()
1: 234
+ this.nachfolger.toString()
Das Zeigt recht schön, dass da ein Element auf sich selbst verweist. Ist vorgesehen, dass ein Element sein eigener Nachfolger ist?
Vermutlich nicht, daher schau Dir den Code an, mit dem Du das Element 234 eingefügt hast. Da hast Du den Nachfolger falsch gesetzt.

Edit: Die ersten Einfügen (2 und 23) waren noch ok. Also wirklich schauen, was Du gemacht hast, als 234 hinzu gekommen ist! (Nicht, dass Du wieder an der falschen Stelle nach Fehlern suchst!)
 
Das Zeigt recht schön, dass da ein Element auf sich selbst verweist. Ist vorgesehen, dass ein Element sein eigener Nachfolger ist?
Vermutlich nicht, daher schau Dir den Code an, mit dem Du das Element 234 eingefügt hast. Da hast Du den Nachfolger falsch gesetzt.
Java:
public void insertAt(int n, String s) {
    // negative Einfügepositionen werden ignoriert
    if(n>=0) {
      // ist die aktuelle Karte die gewünschte Position?
      if(this.nr == n) {
        // ist die Karte frei?
        if(this.frei) {
          this.frei=false;
          this.inhalt=s;
        } else {
          // Lege eine neue Dynamische Reihung an mit Namen "temp"
          DynArray temp = new DynArray();
          // Speichere eine Kopie der aktuellen Dynamischen Reihung in temp
          temp = this;
          // Speichere den neuen Inhalt auf der aktuellen Karte
          this.inhalt = s;
          // Lege die vorher angefertigte Kopie als Nachfolger fest
          this.nachfolger = temp;
          // this.nachfolger.neueNummern();
        }
      } else {
        // Gib das Problem an den Nachfolger weiter
        if(this.nachfolger==null) {
          this.nachfolger = new DynArray();
          this.nachfolger.nr = this.nr + 1;
          this.nachfolger.append(s);
        } else {
          this.nachfolger.insertAt(n, s);
        }
      }
    } 
  } // Ende von insertAt

Hier wird der Wert ersetzt
 
[CODE lang="java" highlight="1,5"] temp = this;
// Speichere den neuen Inhalt auf der aktuellen Karte
this.inhalt = s;
// Lege die vorher angefertigte Kopie als Nachfolger fest
this.nachfolger = temp;
// this.nachfolger.neueNummern();[/CODE]

Da siehst Du. Der Nachfolger von this ist this (da temp = this!) und schon hast Du den Kreis.

Und überleg Dir genau, was Du machen willst (Auf einem Zettel und mal es Dir auf ... referenzen als Pfeile einzeichnen....)

Was Du derzeit machst: Du erzeugst ein neues DynArray in temp. Das brauchst du aber nicht, denn temp ersetzt du durch this....

Das dürfte eher nicht sein, was Du machen willst, oder?

Edit: Auch Zeile 1 markiert und "(da temp = this!)" eingefügt in den Text um es deutlich zu machen!
 
[CODE lang="java" highlight="1,5"] temp = this;
// Speichere den neuen Inhalt auf der aktuellen Karte
this.inhalt = s;
// Lege die vorher angefertigte Kopie als Nachfolger fest
this.nachfolger = temp;
// this.nachfolger.neueNummern();[/CODE]

Da siehst Du. Der Nachfolger von this ist this (da temp = this!) und schon hast Du den Kreis.

Und überleg Dir genau, was Du machen willst (Auf einem Zettel und mal es Dir auf ... referenzen als Pfeile einzeichnen....)

Was Du derzeit machst: Du erzeugst ein neues DynArray in temp. Das brauchst du aber nicht, denn temp ersetzt du durch this....

Das dürfte eher nicht sein, was Du machen willst, oder?

Edit: Auch Zeile 1 markiert und "(da temp = this!)" eingefügt in den Text um es deutlich zu machen!
Jetzt, wo Du es sagst, es ergibt Sinn. Genau, das DynArray temp ist lediglich dazu da, den INhalt der Karten zwischenzuspeichern, dann wird der Wert an der Position n ersetzt und die alten Karten, bzw. die alte Karte soll angehängt werden.

Edit: Trotzdem - ich stehe auf dem Schlauch, obwohl ich den Fehler verstehe.
 
Zuletzt bearbeitet:
Dann überlege Dir, wie Du das hin bekommen kannst. Das musst Du alles wie machen?

Wenn der Inhalt sozusagen an den Kopf soll (this.inhalt = s), dann musst du den this,inhalt evtl. vorher weg schreiben so er nicht verloren gehen soll ... Das ist evtl. etwas, das Du mit "temp = this" machen wolltest. Das was in this gespeichert ist, soll in temp gespeichert werden ...

Aber wenn Du alle meine Möbel bekommen sollst, dann änderst Du ja nicht Deine Adresse zu meiner Adresse sondern du bringst alle meine Möbel zu Deiner Adresse. Das evtl. als kleine Hilfe um da den Unterschied zu sehen.
 
Dann überlege Dir, wie Du das hin bekommen kannst. Das musst Du alles wie machen?

Wenn der Inhalt sozusagen an den Kopf soll (this.inhalt = s), dann musst du den this,inhalt evtl. vorher weg schreiben so er nicht verloren gehen soll ... Das ist evtl. etwas, das Du mit "temp = this" machen wolltest. Das was in this gespeichert ist, soll in temp gespeichert werden ...

Aber wenn Du alle meine Möbel bekommen sollst, dann änderst Du ja nicht Deine Adresse zu meiner Adresse sondern du bringst alle meine Möbel zu Deiner Adresse. Das evtl. als kleine Hilfe um da den Unterschied zu sehen.
Das Möbelbeispiel ist gut. Aber ich dachte das in etwa so: ich möchte meinen Schrank gegen deinen austauschen, meinen Schrank jedoch trotzdem (am Ende des Flurs) platzieren.

Edit: Der Schlauch will nicht schwinden
 
Zuletzt bearbeitet:
Das Problem ist aber, dass alles feste Orte hat. Also Du kannst einen neuen Schrank erzeugen, aber so lange alle zu einem bestimmten Platz gehen um da am Schrank was zu machen, musst Du denen eine neue Referenz zu dem neuen Schrank geben...

Das ist aber schwer, denn Du hast den Vorgänger ja nicht ... Daher ist es doch am Einfachsten, einfach einen neuen Schrank zu erzeugen um dann den davor zu setzen...

Du hast also:
(Vorgänger) -> this -> Nachfolger
Der Vorgänger existiert (bzw. kann existieren), aber den habe ich in Klammern gesetzt, weil den kennen wir nicht.

Daher können wir so ohne weiteres nichts bauen das so aussieht:
(Vorgänger) -> neuesElement -> this -> Nachfolger

Was wir aber bauen können:
(Vorgänger) -> this -> neuesElement -> Nachfolger

Und nun kannst Du Dir an so einer Skizze überlegen, wo was stehen soll, woher die Information kommt und in welcher Reihenfolge Du was setzen musst, damit Du nichts überschreibst, was Du noch brauchst.
Vorgänger und Nachfolger bleiben wohl unverändert. Also musst Du nur die Elemente von this und neuesElement (bei dir "temp" genannt, aber ist ja nicht temporär! Also blöder Name.)
 

Zurück
Oben