2016-04-16 12 views
0

Ich habe die Erklärungen von nullPointerExceptions gelesen und weiß, dass es ist, wenn ein Wert auf einen Nullwert verweist, als ob es auf ein Objekt verweist, aber ich kann einfach nicht warum warum Ich bekomme eins mit einem Enum, das ungefähr wie eine switch-Anweisung verwendet wird, aber natürlich nicht mit einer switch-Anweisung. Das erwartete Verhalten sollte, wie ich schon sagte, wie eine switch-Anweisung sein. Vielleicht fehlt mir ein grundlegendes Verständnis sowohl der Enum- als auch der NPE-Konzepte. Mein Code ist wie folgt. (Dieser Code ist für eine Maschine Enigma-Chiffre)nullPointerException mit Enum mit Runnables in Java

void displayMenu() { 
    System.out.println("MAIN MENU"); 
    System.out.println(); 
    Stream.of(menuChoice.values()).map(stream -> stream.ordinal() + ". " + stream.msg).forEach(System.out::println); 
    System.out.println(); 
} 

public enum menuChoice { 

    QUIT("Quit the Enigma", EnigmaMachine.instance.quitAction), 
    ENCRPYT("Encrypt", EnigmaMachine.instance.encryptAction), 
    DECRYPT("Decrypt", EnigmaMachine.instance.decryptAction); 
    private String msg; 
    public Runnable action; 

    private menuChoice(String message, Runnable r) { 
     this.msg = message; 
     this.action = r; 
    } 
} 

menuChoice getUserChoice() { 
    System.out.print("Please enter your choice: "); 
    int choice = s.nextInt(); 
    return menuChoice.values()[choice]; 
} 

Auf der VERL Konstante ich ein lauffähiges bin mit, die Sets:

final Runnable quitAction =() -> { 
    EnigmaMachine.instance.running = false; 
}; 

Der Stacktrace ist wie folgt:

Exception in thread "main" java.lang.ExceptionInInitializerError 
    at enigmamachine.EnigmaMachine.displayMenu(EnigmaMachine.java:24) 
    at enigmamachine.EnigmaMachine.<init>(EnigmaMachine.java:85) 
    at enigmamachine.EnigmaMachine.main(EnigmaMachine.java:91) 
Caused by: java.lang.NullPointerException 
    at enigmamachine.EnigmaMachine$menuChoice.<clinit>(EnigmaMachine.java:30) 
    ... 3 more 
Java Result: 1 

Meine Konstruktor ist wie folgt:

public EnigmaMachine() { 
    this.running = true; 
    while (this.running) { 
     displayMenu(); 
     getUserChoice().action.run(); 
    } 
} 

Objektinstanz wird direkt oberhalb der Hauptfunktion definiert, die sich am Ende meines Codes befindet.

Ich bin nicht unbedingt auf der Suche nach einer Lösung, aber vielleicht eine besser nachvollziehbare Erklärung dessen, was ich damit zu tun habe. Vielen Dank.

+1

Was 'EnigmaMachine.instance', der es initialisiert und wann passiert das? Nun, ich denke, die Antwort wird mich nicht "befriedigen", weil ich sicher bin, dass der Initialisierungsteil passieren wird _nach_ der Klassenlader versucht, 'menuChoice' zu ​​laden, und deshalb schlägt es fehl. – Tom

+0

Ich habe meine Frage aktualisiert, wenn das irgendeinen Nutzen bringt. Es wird in der Hauptfunktion gestartet. – TooLateTheHero

+1

* "Wenn das irgendeinen Nutzen hat *" natürlich ist es :). * "Es ist in der Hauptfunktion initiiert." * Und das ist zu spät. Um Ihre 'main'-Methode auszuführen, muss die JVM die' EnigmaMachine'-Klasse und jedes statische Material darin laden. Da Ihr Enum darin enthalten ist (und implizit statisch)] (http://stackoverflow.com/questions/663834/in-java-are-enum-types-inside-a-class-static), wird es geladen als gut und dann mit dem mitgelieferten 'menuChoice'-Konstruktor initialisiert. An diesem Punkt kann "EnigmaMachine.instance.quitAction" nicht verwendet werden, da "instance" immer noch "null" ist. – Tom

Antwort

1

Sie erhalten dieses Problem einfach, weil EnigmaMachine.instance immer noch null ist, wenn es hier anrufen ist QUIT("Quit the Enigma", EnigmaMachine.instance.quitAction). Sie sollten displayMenu() in Ihrem Konstruktor nicht aufrufen, da es zu früh ist, sollten Sie es eine Methode nennen, um dieses Problem zu vermeiden.

Sie könnten beispielsweise hinzufügen, eine Methode, um Ihre Klasse beginnen wie folgt:

public void start() { 
     this.running = true; 
     while (this.running) { 
      displayMenu(); 
      getUserChoice().action.run(); 
     } 
    } 

es dann in der main Methode aufrufen, als nächste

instance = new EnigmaMachine(); 
    instance.start();