2013-03-26 20 views
6

mam ten singleton staram się używać, ale getInstance może pozornie zwróci null:Java Singleton.getInstance() zwraca wartość null?

class Singleton { 
    public static final String K_LEVEL = "level"; 
    static Singleton instance = new Singleton(); 
    private int level; 

    static Singleton getInstance() { 
     return instance; 
    } 

    int getLevel() { 
     return level; 
    } 

    void incrementLevel() { 
     System.out.println("LEVEL INCREASED TO " + ++level); 
    } 

    void addToLevel(int x) { 
     for(int i=0;i<x;i++) 
      incrementLevel(); 
    } 

} 

class A { 
    public static void main(String[] args) { 
     Singleton s = Singleton.getInstance(); 
     Integer i = Integer.getInteger(Singleton.K_LEVEL); 
     s.addToLevel(i); 
    } 
} 

usłyszałem wdrażania pojedynczych w Javie jest bardzo trudne i podatne na wyścig warunki. Czy mój wzór singletonowy jest błędny? Ostatnio zmieniłem kod tak, aby wyglądał tak, a teraz getInstance zwraca czasami wartość null. Czemu?

$ java A -Dlevel=1 
Exception in thread "main" java.lang.NullPointerException 
    at A.main(A.java:29) 
+1

Co to jest 'System.out.println (i);' tuż przed 's.addToLevel (i);' print? – jlordo

Odpowiedz

2

Nie ma nic złego w Singletonie. Nie ma problemów z współbieżnością, ponieważ nie jest to kod wielowątkowy.

Myślałeś, że s jest pusty, ale naprawdę jest i, który był pusty.

Ponieważ addToLevel bierze int jako parametru, Integer i został autounboxed (niejawnie konwertowane z Integer do int), ale ponieważ i był null, NullPointerException został wygenerowany. Autounboxing wyrzuca NullPointerException, gdy wartość jest pokrywane null.

Powód: Integer.getInteger(Singleton.K_LEVEL) zwrócił z powodu java A -Dlevel=1 w przeciwieństwie do java -Dlevel=1 A. Ta druga jest poprawną składnią.

2

Nie chodzi o twój wzór singletonowy, który wygląda dobrze dla mnie. Jest to metoda Integer.getInteger(Singleton.K_LEVEL);, która zwraca wartość null. Założę się, że właściwość systemowa "level" nie została ustawiona i jest null.

Z moich komentarzy, musisz wstawić -Dlevel=1przed klasy A w wierszu polecenia. Jeśli debugujesz swój kod lub wydrukujesz właściwość systemową, zobaczysz, że jest on pusty.

Dostajesz NPE podczas próby zabicia null do addToLevel(int x) i próbuje auto-unbox null być int x.

Odkładając na bok, jeśli ta klasa jest używana przez wiele wątków, należy rozważyć użycie klasy AtomicInteger wewnątrz klasy Singleton, która jest powtórką.

+0

Nie, ustawiłem to, wykonując następujące czynności: 'java A -Dlevel = 1'' – Dog

+1

' -D' musi być _ przed rozpoczęciem klasy @A' klasy @Dog. Mogę debugować twój kod lub wydrukować właściwość systemu, aby to zweryfikować. – Gray

+1

Zgadzam się. @Dog dlaczego nie wydrukujesz, tuż przed wywołaniem addToLevel do weryfikacji. –

1

java -Dlevel=1 A powinien odpowiadać Twoim potrzebom.

Z doc, składnia jest java [ options ] class [ argument ... ] i -Dlevel=1 jest uważany jako opcja (patrz rozdział options).

0

static Singleton instance = new Singleton(); powinna być ostateczna, aby zapobiec wyścigowi.