Uniprojekt (BlueJ)

JoRo

Mitglied
Hallo. Bei folgendem Code stimmt irgendetwas bei der Ausführung nicht.
Code:
public class Nand                                    
{                                 
    int eingaenge;                                
    boolean wert;                                 
    boolean[] inputs;
  
    Nand(int eingaenge){                             
        boolean[] inputs = new boolean[eingaenge];
    };
     
    public void setInput(int nummer, Signal in){  
        inputs[nummer] = in.getValue();            
        };

    public void setOutput(Signal out){           
        };

}
in der Zeile "inputs[nummer] = in.getValue();" wird der Fehlercode:

java.lang.NullPointerException:
null

angezeigt.

Wenn man an der Stelle einen vom Array "inputs" unabhängigen Befehl hat (z.B. System.out.println("Hello World"); ), kommt keine Fehlermeldung.

Ich weiß nicht, ob es eine Rolle spielt. Aber es wird erst 12 mal der Constructor ausgeführt und danach erst setInput und setOutput.
Ich weiß auch nicht, ob ich irgendwelche relevante Informationen ausgelassen habe oder ob ich hier überhaut richtig bin.

schon mal vielen Dank im Voraus für eure Hilfe.

EDIT:
in der Konsole steht folgendes:

java.lang.NullPointerException
at Nand.setInput(Nand.java:18)
at FunctionalSimulator.<init>(FunctionalSimulator.java:68)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at bluej.runtime.ExecServer$3.run(ExecServer.java:746)
 
Zuletzt bearbeitet:
Code:
public class Nand                                     
{                                  
    Nand(int eingaenge){                              
        boolean[] inputs = new boolean[eingaenge]; 
    };
}

Hier erzeugst du ein lokales boolean array.
Stattdessen willst du natürlich das Array, welches bereits in der Klasse definiert ist benutzen:

Java:
public class Nand                                     
{                                  
    Nand(int eingaenge){                              
        //boolean[] inputs = new boolean[eingaenge];  
        inputs = new boolean[eingaenge];  
    };
}
 
neues Problem. gleiche Fehlermeldung.

der Fehler tritt in Zeile 19 (bei inv1.berechnen()) auf und lautet wieder

java.lang.NullPointerException:
null

EDIT: hat es etwas damit zu tun, dass die Nand Elemente nicht neu "definiert" werden? Der Konstruktor wird vorher in einer anderen Klasse ausgeführt.

Die Klasse:

Java:
public class Signal                 
{
   String       name;                               //jedes Signal hat einen Namen (Zuordnung)
   boolean      value;                              //Status des Signals
   char         buchstabe1;                         //erster Buchstabe des Namens (i, s, n, t)
   Nand         inv1,inv2,inv3,n1,n2,n3,n4,n5,n6,n7,n8,n9;

   Signal(String nam){                              //Signal wird erzeugt (Name wird ausgelesen)
       name = nam;
    }

   public void setValue(boolean val){               //Value eines Signals auf Klammerwert setzen
       value = val;
       char buchstabe1 = name.charAt(0);
       switch(buchstabe1){                     
           case 'i':                                // i-Signale aktivieren Inverter
            inv1.berechnen();                       // i --> n
            inv2.berechnen();
            inv3.berechnen();
           break;
           case 'n':                                // n-Sgnale aktivieren erste Stufe
            n1.berechnen();                         // i und n --> t
            n2.berechnen();
            n3.berechnen();
            n4.berechnen();
            n5.berechnen();
            n6.berechnen();
            n7.berechnen();
           break;
           case 't':                                // t-Signale aktivieren zweite Stufe
            n8.berechnen();                         // t --> s
            n9.berechnen();
           break;
           case 's':                                 //s-Signale werden ausgegeben.
            System.out.println
            (name + " -> " + value);
           break;
        };
        
    }

   public boolean getValue(){      
        return value;              
   }

}

Die aufgerufene Methode in der Klasse Nand:


Java:
    public void berechnen(){                        //eigentliche Operation des Nand
        wert2 = true;
        for( int i = 0; i < inputs.length; i++)     //Schleife Start: i = 0, Bed.: i < Länge von inputs, i wird jedes mal um 1 erhöht
        {
            vergleich = inputs[i];                  //Stelle i des Array def. "vergleich"
            wert = vergleich.getValue();            //Value von vergleich wird ausgelesen
            wert1 = wert && wert2;                  //ausgelesener wert und wert aus letzter Schleife werden "verundet"
            wert2 = wert1;                          //wert2 wird auf wert1 gesetzt --> Rückführung in Schleife
        }
        wert = !wert2;                              //Endwert ist negierung von wert2
        outp.setValue(wert);                        //Signal am Output wird auf wert gesetzt
    }
 
Zuletzt bearbeitet:
Die werden in der Vorbereitung durch eine andere Klasse erzeugt.
Kann ich da irgendwie innerhalb dieser Klasse auf diese zugreifen oder muss ich mir da was anderes einfallen lassen?
 
Dazu müssen die Signal-Objekte Referenzen auf die Nand-Objekte haben. Den Variablen inv1 etc. müßten also vorher entsprechende Werte zugewiesen werden, beispielsweise durch geeignete Methodenaufrufe.
 
Es kann im Konstruktor geschehen oder über Setter-Methoden. Wenn du beispielsweise Gatter mit vielen Eingängen simulieren willst (verstehe den Zweck deines Codes noch nicht, aber es scheint ja in die Richtung zu gehen), willst du vielleicht nicht für jeden Eingang einen eigenen Konstruktor-Parameter oder Setter haben. Dann kannst auch eine Methode wiepublic void addInputConnection(Gate gate);zum Hinzufügen anbieten, die man dann eben mehrmals aufruft.
 
Das Problem ist, dass diese ganzen Objekte in einer Klasse erzeugt werden, die wir nicht verändern sollen.
Ich kann den Code heute Abend einmal Hochladen, dann hast du vllt einen kleinen Überblick.
 
Ich darf die Klasse FunctionalSimulator nicht verändern.
Also das gesamte Programm sieht so aus. :
Klasse FunctionalSimulator:
Java:
/**
 * Klasse FunctionalSimulator ist ein einfacher Logiksimulator, der nur 
 * Nand-Gatter simulieren kann und keine Zeitverzögerungen berücksichtigt.
 * Die zu simulierende Schaltung wird im Konstruktor der Klasse erzeugt.
 * Es handelt sich hierbei um einen einfachen Volladdierer.
 * Zum Testen Ihrer Klassen <CODE>Nand</CODE> und <CODE>Signal</CODE> müssen Sie
 * einfach nur eine Instanz dieser Klasse erzeugen und dann die Methode
 * <CODE>simulate()</CODE> aufrufen.
 * @author Christian Hochberger, TU Dresden
 * @version 1.0 Erste Fassung
 */
public class FunctionalSimulator {
    // Eingänge (i1-i3) und Ausgänge (s1,s0) der Schaltung
    Signal    i1,i2,i3,s1,s0;
    // Innere Signale, geben das invertierte Signal der Eingänge an
    Signal    ni1,ni2,ni3;
    // Innere Signale, die bei der Berechnung der Summe benötigt werden
    Signal    t1,t2,t3,t4,t5,t6,t7;

    // Nand-Gatter zum Invertieren der Eingänge
    Nand    inv1,inv2,inv3;
    // Nand-Gatter zur Berechnung der Summe
    Nand    n1,n2,n3,n4,n5,n6,n7,n8,n9;

    /**
     * Konstruktor, der die zu simulierende Schaltung aufbaut.
     * Simuliert wird ein einfacher Volladdierer.
     */
    public FunctionalSimulator() {
    // Alle Signale anlegen
    // Der Konstruktor bekommt einen Signalnamen als Parameter
    i1=new Signal("i1");
    i2=new Signal("i2");
    i3=new Signal("i3");
    ni1=new Signal("ni1");
    ni2=new Signal("ni2");
    ni3=new Signal("ni3");
    s1=new Signal("s1");
    s0=new Signal("s0");
    t1=new Signal("t1");
    t2=new Signal("t2");
    t3=new Signal("t3");
    t4=new Signal("t4");
    t5=new Signal("t5");
    t6=new Signal("t6");
    t7=new Signal("t7");

    // Alle Gatter anlegen
    // Parameter des Konstruktors ist die Anzahl von Eingängen
    // Die Inverter sind sozusagen entartete Nand-Gatter (1 Eingang)
    inv1=new Nand(1);
    inv2=new Nand(1);
    inv3=new Nand(1);
    n1=new Nand(3);
    n2=new Nand(3);
    n3=new Nand(3);
    n4=new Nand(3);
    n5=new Nand(3);
    n6=new Nand(3);
    n7=new Nand(3);

    n8=new Nand(4);
    n9=new Nand(4);

    // Inverter mit Ein- und Ausgängen verbinden.
    // Die Methode setInput() des Gatters bekommt die Nummer des Eingangs
    // und das Signal, mit dem dieser Eingang verbunden werden soll.
    inv1.setInput(0,i1);
    // Die Methode setOutput() bekommt nur ein Signal, welches durch diesen
    // Ausgang bestimmt wird
    inv1.setOutput(ni1);
    inv2.setInput(0,i2);
    inv2.setOutput(ni2);
    inv3.setInput(0,i3);
    inv3.setOutput(ni3);

    // Die Nand-Gatter zur Summenberechnung richtig verbinden
    n1.setInput(0,ni1);
    n1.setInput(1,ni2);
    n1.setInput(2,i3);
    n1.setOutput(t1);
   
    n2.setInput(0,ni1);
    n2.setInput(1,i2);
    n2.setInput(2,ni3);
    n2.setOutput(t2);
   
    n3.setInput(0,ni1);
    n3.setInput(1,i2);
    n3.setInput(2,i3);
    n3.setOutput(t3);
   
    n4.setInput(0,i1);
    n4.setInput(1,ni2);
    n4.setInput(2,ni3);
    n4.setOutput(t4);
   
    n5.setInput(0,i1);
    n5.setInput(1,ni2);
    n5.setInput(2,i3);
    n5.setOutput(t5);
   
    n6.setInput(0,i1);
    n6.setInput(1,i2);
    n6.setInput(2,ni3);
    n6.setOutput(t6);
   
    n7.setInput(0,i1);
    n7.setInput(1,i2);
    n7.setInput(2,i3);
    n7.setOutput(t7);

    // n8 und n9 berechnen die eigentlichen Ausgänge
    n8.setInput(0,t1);
    n8.setInput(1,t2);
    n8.setInput(2,t4);
    n8.setInput(3,t7);
    n8.setOutput(s0);

    n9.setInput(0,t3);
    n9.setInput(1,t5);
    n9.setInput(2,t6);
    n9.setInput(3,t7);
    n9.setOutput(s1);

    // Die Signale s1 und s0 sind mit keinen weiteren Gattern verbunden.
    // Sorgen Sie dafür, dass in diesem Fall eine Wertänderung dieser
    // Signale ausgegeben wird.
    }

    /**
     * Diese Methode führt die eigentliche Simulation durch. Dazu werden den
     * Eingangssignalen (i1,i2,i3) einfach nur neue Werte zugeordnet. Diese
     * Wertänderungen propagieren sich dann durch die Schaltung bis zum Ausgang
     * und werden dort ausgegeben.
     */
    public void simulate() {
    // Zunächst alle Eingänge auf false setzen (ist zwar schon nach dem)
    // Erzeugen des Gatters so, aber durch ein erneutes Setzen werden
    // die inneren Signale der Schaltung vernünftig berechnet)
    i1.setValue(false);
    i2.setValue(false);
    i3.setValue(false);

    // Eingang i1 auf true: Dadurch sollte als Summe s1=false und s0=true
    // herauskommen. Es ist aber normal, dass Änderungen an s1 und s0 mehrfach
    // ausgegeben werden, bevor das Endergebnis herauskommt.
    System.out.println("==== i1 -> true");
    i1.setValue(true);
   
    // Eingang i1 und i2 auf true: Dadurch sollte als Summe s1=true und
    // s0=false herauskommen.
    System.out.println("==== i2 -> true");
    i2.setValue(true);
   
    // Eingang i1,i2 und i3 auf true: Dadurch sollte als Summe s1=true und
    // s0=true herauskommen.
    System.out.println("==== i3 -> true");
    i3.setValue(true);
   
    // Eingang i1 und i3 auf true: Dadurch sollte als Summe s1=true und
    // s0=false herauskommen.
    System.out.println("==== i2 -> false");
    i2.setValue(false);
   
    // Eingang i3 auf true: Dadurch sollte als Summe s1=false und
    // s0=true herauskommen.
    System.out.println("==== i1 -> false");
    i1.setValue(false);
   
    // Eingang i2 und i3 auf true: Dadurch sollte als Summe s1=true und
    // s0=false herauskommen.
    System.out.println("==== i2 -> true");
    i2.setValue(true);
    }

    /**
     * Main Methode dieser Klasse. Sie müssen das im Moment noch nicht
     * verstehen. Diese Methode wird benötigt, wenn Sie den Simulator ohne
     * BlueJ laufen lassen wollen. Wenn Sie diese Klasse in BlueJ nutzen,
     * dann ignorieren Sie diese Methode einfach.
     */
    public static void main(String[] args) {
    FunctionalSimulator s=new FunctionalSimulator();

    s.simulate();
    }
}

Klasse Nand:

Java:
public class Nand                                      
{                                                   //Z. 10-18 Parameter werden erzeugt
    int eingaenge;                                 
    int eingang;
    Signal inp;                                     //Variablen sind Objekte der Klasse "Signal"
    Signal outp;
    Signal vergleich;
    boolean wert = true;                            //werden erzeugt und auf true gesetzt. (tw. unnötig)
    boolean wert1 = true;
    boolean wert2 = true;
    Signal[] inputs;                                //inputs ist ein Array mit Signal-Objekten als Einträge
    Nand[] gatter = new Nand[100];
    Nand(int eingaenge){                            //Konstruktor: Objekt wird erzeugt. Zahl der Eingänge wird definiert.  
        inputs = new Signal[eingaenge];             //Ein Signal-Array der Länge eingaenge wird erzeugt.
    }       
   
    public void setInput(int nummer, Signal in){    //Inputs werden in einem Objekt-Array gelistet.
        eingang = nummer;
        inp = in;
        inputs[eingang] = inp;                      //Stelle eingang bekommt das Signal inp
    }
   
    public void setOutput(Signal out){              //ein output wird definiert
        outp = out;
    }
   
    public void berechnen(){                        //eigentliche Operation des Nand
        wert2 = true;
        for( int i = 0; i < inputs.length; i++)     //Schleife Start: i = 0, Bed.: i < Länge von inputs, i wird jedes mal um 1 erhöht
        {  
            vergleich = inputs[i];                  //Stelle i des Array def. "vergleich"
            wert = vergleich.getValue();            //Value von vergleich wird ausgelesen
            wert1 = wert && wert2;                  //ausgelesener wert und wert aus letzter Schleife werden "verundet"
            wert2 = wert1;                          //wert2 wird auf wert1 gesetzt --> Rückführung in Schleife
        }
        wert = !wert2;                              //Endwert ist negierung von wert2
        outp.setValue(wert);                        //Signal am Output wird auf wert gesetzt
    }
   
    public void anzeigen(){                         //zum anschauen eines Arrays zu testzwecken
        for( int i = 0; i < inputs.length; i++)     //Schleife Start: i = 0, Bed.: i < Länge von inputs, i wird jedes mal um 1 erhöht
        {  
            vergleich = inputs[i];                  //Stelle i des Array def. "vergleich"
            wert = vergleich.getValue();            //Value von vergleich wird ausgelesen
            System.out.println(wert);               //Dieser wert wird angezeigt.
        }                                           //i wird erhöht, Schleife beginnt von vorn, wenn i < Länge des Array
    }
}

Klasse Signal:
Java:
public class Signal                      
{
   String       name;                               //jedes Signal hat einen Namen (Zuordnung)
   boolean      value;                              //Status des Signals
   char         buchstabe1;                         //erster Buchstabe des Namens (i, s, n, t)
   Nand         inv1,inv2,inv3;
   Nand         n1,n2,n3,n4,n5,n6,n7,n8,n9;
   
   Signal(String nam){                              //Signal wird erzeugt (Name wird ausgelesen)  
       name = nam;
       //System.out.println(buchstabe1);
    }  

   public void setValue(boolean val){               //Value eines Signals auf Klammerwert setzen
       value = val;
       char buchstabe1 = name.charAt(0);
       switch(buchstabe1){                          
           case 'i':                                // i-Signale aktivieren Inverter 
            inv1.berechnen();                       // i --> n
            inv2.berechnen();
            inv3.berechnen();
           break;
           case 'w':                                // n-Sgnale aktivieren erste Stufe
            n1.berechnen();                         // i und n --> t
            n2.berechnen();
            n3.berechnen();
            n4.berechnen();
            n5.berechnen();
            n6.berechnen();
            n7.berechnen();
           break;
           case 'e':                                // t-Signale aktivieren zweite Stufe
            n8.berechnen();                         // t --> s
            n9.berechnen();
           break;
           case 'r':                                 //s-Signale werden ausgegeben.
            System.out.println
            (name + " -> " + value);
           break;
        };
             
    }

   public boolean getValue(){          
        return value;                  
   }
}
 
Wenn einem Nand-Objekt mittels setInput() ein Eingangssignal zugeordnet wird, könnte sich das Nand-Objekt noch innerhalb der setInput()-Methode bei diesem Signal registrieren, so dass das Signal die Nands kennt, für die es die Neuberechnung aufrufen muss, sobald sich der Wert des Signals ändert. Ein Nand-Objekt benötigt so nur eine Liste seiner Eingangssignale und ein Signal-Objekt eine Liste seiner Ausgangs-Nands. Die ganzen Variablennamen aus der Simulationsklasse benötigst du in deinen Klassen nicht.

Dadurch sind deine Klassen auch dann noch einsetzbar, wenn in der Simulationsklasse eine ganz andere Schaltung simuliert werden soll.
 
Ja, genau so soll es sein. und wie verändere ich die setInput Methode dementsprechend? Ich weiß leider bisher noch nicht, wie man diese Rückverbindung hinbekommt.
 
wenn ich die Methode für das Signal aufrufe, Brauche ich doch die Bezeichnung des Nandgatters, dass die Methode aufruft. Geht das mit "this"?
 
Okay, wenn ich nun alle Nand Gatter, die einen Eingang durch das Signal x haben in einem Array anordnen will. Wie mache ich das mit der Länge und an welche Stelle das Nand Gatter geschrieben werden soll?
Bei der Zuordnung von Signal zu Nand hatte ich eine vordefinierte Länge und die Stelle war bekannt, wo es hin soll.

EDIT: Ich hab kurz gesucht, ich glaube, dass das mit einem Vector geht. (hab ich noch nie von gehört)
Ich werd mich etwas schlau machen und versuchen selbst eine Lösung zu finden.

Vielen Dank erstmal für deine Hilfe.
 
Zuletzt bearbeitet:
Ich würde anstelle eines Arrays lieber eine andere Datenstruktur nehmen, z.B. eine ArrayList. Da muß man sich auf keine Größe festlegen und auch nicht um den Index kümmern.

Falls es trotzdem ein Array sein soll, könntest du dir beim Speichern einen unbenutzten Index heraussuchen. Wenn das Array voll ist, könntest du dir ein größeres erstellen und die bereits eingetragenen Nands umkopieren.
 

Zurück
Oben