Domanda

Mi sono imbattuto in una classe creata in questo modo:

public class MyClass {

  private static boolean started = false;

  private MyClass(){
  }

  public static void doSomething(){
    if(started){
      return;
    }
    started = true;
    //code below that is only supposed to run
    //run if not started
  }
}

La mia comprensione con i metodi statici è che non dovresti usare le variabili di classe in esse a meno che non siano costanti e non cambino. Invece dovresti usare i parametri. La mia domanda è: perché questo non si interrompe quando viene chiamato più volte facendo MyClass.doSomething (). Mi sembra che non dovrebbe funzionare ma funziona. Passerà l'istruzione if solo una volta.

Quindi qualcuno potrebbe spiegarmi perché questo non si rompe?

È stato utile?

Soluzione

Il metodo doSomething () e la variabile iniziato sono entrambi statici, quindi esiste una sola copia della variabile ed è accessibile da doSomething () . La prima volta che viene chiamato doSomething () , iniziato è falso, quindi imposta avviato su true e quindi ... beh, qualcosa. La seconda e successiva volta si chiama, iniziato è vero, quindi ritorna senza fare nulla.

Altri suggerimenti

Non c'è motivo per cui l'uso di una variabile statica non funzioni. Non sto dicendo che è una buona pratica, ma funzionerà.

Quello che dovrebbe succedere è:

  1. Viene effettuata la prima chiamata. La classe è inizializzata, iniziata è falsa.
  2. doSomething viene chiamato. L'if non riesce e il codice lo ignora. avviato è impostato su true e viene eseguito l'altro codice.
  3. doSomething viene richiamato di nuovo. Il if passa e l'esecuzione si interrompe.

L'unica cosa da notare è che qui non c'è sincronizzazione, quindi se doSomething () è stato chiamato su thread separati incredibilmente vicini tra loro, ogni thread potrebbe leggere avviato come falso, bypassare l'istruzione if e fare il lavoro, cioè c'è un condizioni di gara.

Il codice fornito non è thread-safe. Il modo semplice per rendere sicuro questo thread di codice sarebbe fare qualcosa del genere

public class MyClass {

  private static AtomicBoolean started = new AtomicBoolean(false);

  private MyClass(){
  }

  public static void doSomething(){
    boolean oldValue = started.getAndSet(true);
    if (oldValue)
      return;
    }

    //code below that is only supposed to run
    //run if not started
  }
}

Questo dovrebbe essere sicuro per i thread poiché AtomicBoolean getAndSet è sincronizzato.

È vero che questo non è un problema se non si usano i thread (si noti che una webapp può usare molti thread che gestiscono varie richieste senza che tu ne sia consapevole).

Non è un codice particolarmente carino - in genere i progetti dovrebbero usare istanze di oggetti in cui lo stato cambia, ma non c'è nulla di illegale in esso.

  

La mia comprensione con i metodi statici è che non dovresti usare le variabili di classe in esse a meno che non siano costanti e non cambino.

Sembra che tu abbia estrapolato da una linea guida di progettazione a una funzione linguistica. Leggi uno dei tanti tutorial Java disponibili online su ciò che è effettivamente consentito nella lingua. Puoi puoi usare liberamente campi statici non finali in metodi statici, ma porta a un codice procedurale piuttosto che orientato agli oggetti.

  

Invece dovresti usare i parametri.

È difficile vedere come verrebbe utilizzato un parametro iniziato - se il chiamante sapeva che il processo è stato avviato, perché dovrebbe chiamare il metodo?

All'interno del metodo statico, è consentito richiamare o accedere a membri statici all'interno della stessa classe.

Ignorando scenari con più thread, La prima chiamata a doSomething renderà la variabile statica booleana vera, quindi la seconda chiamata eseguirà il codice del blocco if che semplicemente esce dal metodo.

Il tuo metodo statico sta parlando con una variabile di classe statica, quindi dovrebbe andare bene. Potresti pensarlo come un codice globale e una variabile globale, sebbene sia nello spazio dei nomi della classe.

Se hai provato ad accedere a una variabile membro non statica:

private int foo = 0;

dall'interno del metodo statico, il compilatore dovrà e dovrebbe lamentarsi.

started is false - initial state.
MyClass.doSomething() - statered is now true
MyClass.doSomething() - started is STILL true

MyClass foo = new MyClass();
foo.started -> it's STILL true, because it's static
foo.doSomething() - not sure you can do this in Java, but if you can, it's be STILL TRUE!

Ora, ci sono problemi nel codice sopra con sicurezza thread, ma a parte questo, sembra funzionare come progettato.

Ricorda solo la regola del pollice secondo cui le variabili statiche sono variabili a livello di classe e tutte le variabili non statiche sono istanza variabili " ;. Quindi non avrai alcuna confusione!

vale a dire. Per la variabile statica, tutti i riferimenti fatti nel codice alla variabile puntano alla stessa posizione di memoria. E per le variabili non statiche, la nuova allocazione di memoria viene eseguita ogni volta che viene creata una nuova istanza di quella classe (quindi ogni riferimento fatto nel codice alla variabile punta a una diversa posizione di memoria allocata per l'istanza della classe chiamante).

Il codice sopra funziona perfettamente (a meno che non venga eseguito in un ambiente multithread). Perché pensi che dovrebbe rompersi?

  

La mia comprensione con i metodi statici è che non dovresti usare le variabili di classe in esse a meno che non siano costanti e non cambino

Suppongo che sia possibile accedere solo ai membri statici. Non deve essere costante!

  

La mia domanda è perché questo non si interrompe quando viene chiamato più volte facendo MyClass.doSomething (). Mi sembra che non dovrebbe funzionare ma funziona. Passerà l'istruzione if solo una volta

Secondo la logica esistente. Solo la prima chiamata esegue il // code da eseguire parte

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top