Question

J'ai rencontré une classe qui a été configurée comme suit:

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
  }
}

D'après ce que je comprends des méthodes statiques, vous ne devez pas utiliser de variables de classe à moins qu'elles ne soient constantes et qu'elles ne changent pas. Au lieu de cela, vous devriez utiliser des paramètres. Ma question est pourquoi est-ce que ceci ne rompt pas quand appelé plusieurs fois en faisant MyClass.doSomething (). Il me semble que cela ne devrait pas fonctionner, mais que ça fonctionne. Il ne passera la déclaration if qu'une seule fois.

Quelqu'un pourrait-il m'expliquer pourquoi cela ne casse pas?

Était-ce utile?

La solution

La méthode doSomething () et la variable commencée sont toutes deux statiques. Il n'y a donc qu'une copie de la variable et elle est accessible à partir de doSomething () . La première fois que doQuelque chose () <) est appelé, démarré est défini sur false, il définit donc démarré sur true, puis fait quelque chose.

La deuxième fois et les fois suivants, started est vrai.

Autres conseils

Il n'y a aucune raison pour que l'utilisation d'une variable statique ne fonctionne pas. Je ne dis pas que c'est une pratique particulièrement bonne, mais cela fonctionnera.

Ce qui devrait arriver est:

  1. Le premier appel est effectué. La classe est initialisée, elle est fausse.
  2. doQuelque chose s'appelle. Si échoue et que le code le contourne. started est défini sur true et l'autre code est exécuté.
  3. doQuelque chose est appelé à nouveau. Si passe et que l'exécution s'arrête.

La seule chose à noter est qu’il n’ya pas de synchronisation ici. Ainsi, si doSomething () était appelé sur des threads extrêmement proches les uns des autres, chaque thread pouvait se lire démarré comme faux, contourner l’instruction if et faire le travail, c’est-à-dire condition de concurrence.

Le code fourni n'est pas thread-safe. Le moyen le plus simple de sécuriser ce thread de code serait de faire quelque chose comme

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
  }
}

Cela devrait être sécurisé sur le plan thread car le getAndSet AtomicBoolean est synchronisé.

Certes, ce n'est pas un problème si vous n'utilisez pas de threads (veuillez noter qu'une webapp peut utiliser un grand nombre de threads traitant différentes requêtes sans que vous en soyez conscient).

Ce n'est pas un code particulièrement intéressant - les conceptions doivent généralement utiliser des instances d'objet dans lesquelles l'état change, mais il n'est pas illégal.

  

D'après ce que je comprends des méthodes statiques, vous ne devez pas utiliser de variables de classe à moins qu'elles ne soient constantes et qu'elles ne changent pas.

Vous semblez avoir extrapolé une directive de conception en une fonctionnalité linguistique. Lisez l'un des nombreux tutoriels Java disponibles en ligne pour savoir ce qui est réellement autorisé dans la langue. Vous pouvez utiliser librement des champs statiques non finaux dans les méthodes statiques, mais cela conduit à un code procédural plutôt qu'à un code orienté objet.

  

Vous devriez plutôt utiliser des paramètres.

Il est difficile de voir comment un paramètre démarré serait utilisé - si l'appelant savait que le processus a été démarré, pourquoi aurait-il appelé la méthode?

Dans la méthode statique, vous êtes autorisé à appeler ou à accéder aux membres statiques de la même classe.

Ignorer les scénarios à plusieurs threads, Le premier appel à faireQuelque chose transformera la variable statique booléenne en vrai; le deuxième appel exécutera donc le code de bloc if qui vient tout simplement de quitter la méthode.

Votre méthode statique parle à une variable de classe statique, donc ça devrait aller. Cela pourrait être considéré comme un code global et une variable globale, bien que ce soit dans l'espace de noms de la classe.

Si vous avez essayé d'accéder à une variable membre non statique:

private int foo = 0;

depuis la méthode statique, le compilateur se plaindra.

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!

Le code ci-dessus présente des problèmes de sécurité des threads, mais à part cela, il semble fonctionner comme prévu.

Rappelez-vous simplement que les "variables statiques sont des variables au niveau de la classe et que toutes les variables non statiques sont des instances , variables". Alors vous n'aurez aucune confusion du tout!

i.e. Pour la variable statique, toutes les références faites dans le code à la variable pointent vers le même emplacement de mémoire. Et pour les variables non statiques, une nouvelle allocation de mémoire est effectuée chaque fois qu'une nouvelle instance de cette classe est créée (ainsi, chaque référence faite dans le code à la variable pointe vers un emplacement mémoire différent alloué pour l'instance de la classe appelante).

Le code ci-dessus fonctionne parfaitement (sauf s’il s’exécute dans un environnement multithread). Pourquoi pensez-vous que cela devrait casser?

  

D'après ce que je comprends des méthodes statiques, vous ne devez pas utiliser de variables de classe à moins qu'elles ne soient constantes et ne changent pas

Je suppose que seuls les membres statiques sont accessibles. Cela n'a pas besoin d'être constant!

  

Ma question est de savoir pourquoi cela ne rompt pas lorsqu'il est appelé plusieurs fois en utilisant MyClass.doSomething (). Il me semble que cela ne devrait pas fonctionner, mais que ça fonctionne. Il ne fera que passer l’instruction if une fois

Selon la logique existante. Seul le premier appel exécute la partie // code à exécuter

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top