Pergunta

Eu corri em toda uma classe que foi configurado como este:

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

O meu entendimento com métodos estáticos é que você não deve usar variáveis ??de classe neles a menos que eles são constantes, e não mudam. Em vez disso você deve usar parâmetros. A minha pergunta é porque é que esta não quebrar quando chamado várias vezes, fazendo MyClass.doSomething (). Parece-me que ele não deve funcionar, mas faz. Ele só vai passar a instrução if uma vez.

Então alguém poderia me explicar por que isso não quebrar?

Foi útil?

Solução

O método doSomething() ea variável started são ambos estático, para que haja apenas uma cópia da variável e é acessível a partir doSomething(). O primeiro doSomething() tempo é chamado, started é falso, por isso define started como true e, em seguida, faz ... bem, alguma coisa. A segunda e subsequentes vezes é chamado, started é verdade, então ele retorna sem fazer nada.

Outras dicas

Não há nenhuma razão por que usar uma variável estática não iria funcionar. Eu não estou dizendo que é particularmente boa prática, mas vai funcionar.

O que deve acontecer é:

  1. A primeira chamada é feita. A classe é inicializado, começou é falsa.
  2. doSomething é chamado. O que falha e o código ignora-lo. começou é definido como verdadeiro e os outros código é executado.
  3. doSomething é chamado novamente. O caso passes e execução pára.

A única coisa a notar é que não há sincronização aqui, por isso, se doSomething () foi chamado em segmentos separados incrivelmente perto juntos, cada thread pode ler começou como falsa, o desvio da instrução if e fazer o trabalho ou seja, há uma corrida condição.

O código dado não é thread-safe. A maneira mais fácil de fazer este segmento seguro código seria fazer algo parecido

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

Esta deve ser thread-safe como o AtomicBoolean getAndSet é sincronizado.

É certo que este não é um problema se você não usar threads (Por favor note que um webapp pode usar um monte de tópicos lidar com vários pedidos sem que se aperceba disso).

Não é particularmente agradável código -. Geralmente projeta deve usar objeto instâncias onde as mudanças de estado, mas não há nada de ilegal com ele

O meu entendimento com métodos estáticos é que você não deve usar variáveis ??de classe neles a menos que eles são constantes, e não mudam.

Você parece ter extrapolado a partir de uma diretriz de design a um recurso de linguagem. Leia um dos muitos tutoriais Java disponíveis on-line, como o que realmente é permitido na língua. Você pode usar campos estáticos não-finais livremente em métodos estáticos, mas leva a processual em vez de código orientada a objetos.

Em vez disso você deve usar parâmetros.

É difícil ver como um parâmetro started seria utilizado - se o chamador sabia que o processo foi iniciado, por que chamar o método

?

Dentro de método estático, você está autorizado a invocar ou membros acesso estáticos dentro da mesma classe.

desconsiderando vários fios cenários, A primeira chamada para doSomething fará a variável estática boolean a verdade, portanto, a segunda chamada vai executar o código de bloco if que simplesmente sair do método.

Você método estático está falando com uma variável de classe estática, então ele deve estar bem. Você pode pensar nisso como código global e uma variável global, tho é no namespace da classe.

Se você tentou acessar uma variável de membro não-estático:

private int foo = 0;

de dentro do método estático, o compilador e deve reclamar.

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!

Agora, existem problemas no código acima com a segurança do thread, mas fora isso, ele parece estar funcionando como projetado.

Basta lembrar a regra de ouro que "variáveis ??estáticas são classe de nível variáveis ??e todas as variáveis ??não-estáticas são instância variáveis". Então você não terá qualquer confusão em tudo!

i. Para variável estática, todas as referências feitas no código para o ponto variável a mesma posição de memória. E para a variável não-estático, nova alocação de memória é feito sempre que uma nova instância dessa classe é criada (assim que cada referência feita no código para os pontos variáveis ??para um local de memória diferente alocado para chamar instância da classe).

O código acima funciona completamente bem (a menos que ele seja executado em um ambiente multithread). Por que você acha que deveria quebrar?

O meu entendimento com métodos estáticos é que você não deve usar variáveis ??de classe neles a menos que eles são constantes, e não mudar

Eu acho que apenas membros estáticos pode ser acessado. Ele não precisa ser constante!

A minha pergunta é porque é que esta não quebrar quando chamado várias vezes, fazendo MyClass.doSomething (). Parece-me que ele não deve funcionar, mas faz. Ele só vai passar a declaração se uma vez

Pela lógica existente. Apenas a primeira chamada é executado a parte //code to be run

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top