Pergunta

Vamos dizer que eu tenho uma classe projetado para ser instanciado. Tenho vários métodos privados "ajudante" dentro da classe que não requerem acesso a qualquer um dos membros da classe, e operar exclusivamente em seus argumentos, retornando um resultado.

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne(member);
       total += computeMore(member);
       return total;         
   }

   private double computeOne(Something arg) { ... }
   private double computeMore(Something arg) {... } 
} 

Existe alguma razão em particular para especificar computeOne e computeMore como métodos estáticos - ou qualquer razão particular para não

É certamente mais fácil deixá-los como não-estático, embora eles certamente podem ser estáticos, sem causar quaisquer problemas.

Foi útil?

Solução

Eu prefiro esses métodos auxiliares para ser private static; o que tornará mais claro para o leitor que não irá modificar o estado do objeto. Meu IDE também irá mostrar as chamadas para métodos estáticos em itálico, por isso vou conhecer o método é estático, sem olhar a assinatura.

Outras dicas

Pode resultar em um pouco menor bytecode, já que os métodos estáticos não terá acesso a this. Eu não acho que isso faça alguma diferença na velocidade (e se o fizesse, seria provavelmente muito pequena para fazer uma diferença global).

eu iria fazê-los estático, desde que eu geralmente fazê-lo, se possível. Mas isso é só comigo.


EDIT: Essa resposta continua ficando downvoted, possivelmente por causa da afirmação sem fundamento sobre o tamanho do bytecode. Então, eu realmente vai executar um teste.

class TestBytecodeSize {
    private void doSomething(int arg) { }
    private static void doSomethingStatic(int arg) { }
    public static void main(String[] args) {
        // do it twice both ways
        doSomethingStatic(0);
        doSomethingStatic(0);
        TestBytecodeSize t = new TestBytecodeSize();
        t.doSomething(0);
        t.doSomething(0);
    }
}

Bytecode (recuperado com javap -c -private TestBytecodeSize):

Compiled from "TestBytecodeSize.java"
class TestBytecodeSize extends java.lang.Object{
TestBytecodeSize();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

private void doSomething(int);
  Code:
   0:   return

private static void doSomethingStatic(int);
  Code:
   0:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   invokestatic    #2; //Method doSomethingStatic:(I)V
   4:   iconst_0
   5:   invokestatic    #2; //Method doSomethingStatic:(I)V
   8:   new     #3; //class TestBytecodeSize
   11:  dup
   12:  invokespecial   #4; //Method "<init>":()V
   15:  astore_1
   16:  aload_1
   17:  iconst_0
   18:  invokespecial   #5; //Method doSomething:(I)V
   21:  aload_1
   22:  iconst_0
   23:  invokespecial   #5; //Method doSomething:(I)V
   26:  return

}

Ao invocar o método estático leva dois Bytecodes (byteops?): iconst_0 (para o argumento) e invokestatic
. Invocar o método não-estático leva de três: aload_1 (para o objeto TestBytecodeSize, suponho), iconst_0 (para o argumento), e invokespecial. (Nota que, se estes não tinham sido métodos privados, teria sido invokevirtual vez de invokespecial; ver JLS métodos de invocação §7.7 .)

Agora, como eu disse, eu não esperar que haja qualquer grande diferença de desempenho entre estes dois, além do fato de que invokestatic requer um a menos bytecode. invokestatic e invokespecial ambos devem ser ligeiramente mais rápido do que invokevirtual, já que ambos uso estático de ligação em vez de dinâmico, mas eu não tenho idéia se quer é mais rápido do que o outro. Não consigo encontrar qualquer boas referências também. O mais próximo que posso encontrar é este artigo JavaWorld 1997 , que reafirma, basicamente, o que eu disse:

As instruções mais rápidos provavelmente será invokespecial e invokestatic, porque os métodos invocados por estas instruções, são estáticas. Quando a JVM resolve a referência simbólica para essas instruções e substitui-lo com uma referência directa, essa referência direta provavelmente incluirá um ponteiro para os bytecodes reais.

Mas muitas coisas mudaram desde 1997.

Portanto, em conclusão ... Eu acho que eu ainda estou furando com o que eu disse antes. A velocidade não deve ser a razão para escolher um sobre o outro, uma vez que seria um micro-otimização na melhor das hipóteses.

Minha preferência pessoal seria declarar-los estáticos, como é uma bandeira claro que eles são apátridas.

A resposta é ... depende.

Se membro é uma instância variável específica para o objeto que você está lidando, então por que passá-lo como um parâmetro em tudo?

Por exemplo:

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne();
       total += computeMore();
       return total;         
   }

   private double computeOne() { /* Process member here */ }
   private double computeMore() { /* Process member here */ } 
}

Uma das razões que você pode querer declarar métodos auxiliares estáticos é se você precisa chamá-los no construtor da classe "antes" this ou super. Por exemplo:

public class MyClass extends SomeOtherClass { 
    public MyClass(String arg) {
       super(recoverInt(arg));
    }

    private static int recoverInt(String arg) {
       return Integer.parseInt(arg.substring(arg.length() - 1));
    }
}

Este é um pouco de um exemplo inventado, mas claramente recoverInt não pode ser um método de instância neste caso.

Eu realmente não posso pensar em vantagens claras para método estático privado. Dito isto, não há vantagens específicas para torná-los não-estático também. É principalmente uma questão de apresentação:. Você pode querer torná-los estática para claramente sublinhado o fato de que eles não estão alterando um objeto

Para o método com diferentes privilégios de acesso, eu acho que existem dois principais argumentos:

  • métodos estáticos pode ser chamado sem criar uma instância de um objeto, que pode ser útil
  • métodos estáticos não pode ser herdada, que pode ser um problema se você precisar de polimorfismo (mas é irrelevante para métodos privados).

Além disso, a diferença é muito pequena, e eu fortemente dúvida de que o adicional este ponteiro passado para método de instância faz uma diferença significativa.

Resposta correta é:

qualquer método que não toma qualquer informação a partir de um campo, e não colocar qualquer informação em um campo, não tem de ser um método de instância. Qualquer método que não usa ou alterar todos os campos da sua classe ou objeto poderia muito bem ser um método estático.

ou qualquer razão particular para não [declará-los como estático]?

Sim.

Ao mantê-los como métodos de instância, você permitir-se a fornecer uma implementação diferente mais tarde.

Pode parecer bobagem (e, na verdade, seria se esses métodos são usados ??apenas por você em um programa de 50 linha), mas em aplicações maiores, ou em bibliotecas usadas por outra pessoa, você pode decidir escolher uma melhor implementação, mas não quero quebrar código existente.

Assim que você criar uma subclasse e retorno que nas novas versões, e uma vez que os métodos foram declarados como métodos de instância, você acabou de deixar o polimorfismo fazer o seu trabalho.

Além disso, você pode se beneficiar de fazer o construtor privado e fornecer um método de fábrica estático para o mesmo motivo.

Assim, a minha recomendação é mantê-los como métodos de instância, e evitar estática, se possível.
Aproveitar o dinamismo da língua fornece.

Veja aqui um vídeo algo relacionado: Como conceber uma boa API e porque é importante

Embora não seja diretamente relacionado à discussão método "estática vs instância", ele toca em alguns pontos interessantes no projeto API.

Uma questão sobre ter métodos estáticos é que ele pode fazer o objeto mais difícil de usar em testes unidade . Mockito não pode criar simulações para métodos estáticos e você não pode criar uma implementação subclasse do método.

Se o método é basicamente apenas uma sub-rotina que nunca vai usar previsivelmente informações de estado, declare-estático.

Isso permite que ele seja usado em outros métodos estáticos ou na inicialização da classe, ou seja:.

public class Example {
   //...

   //Only possible if computeOne is static
   public final static double COMPUTED_ONE = computeOne(new Something("1"));

   //...
}

A minha preferência em casos como estes é fazer com que métodos computeOne e estáticas computeMore. A razão: encapsulamento. A menos código que tem acesso à implementação de sua classe, o melhor.

No exemplo que você dá, você afirma que computeOne computeMoreand não deve precisar de acesso a parte interna da classe, então por que dar a oportunidade para os mantenedores da classe para se intrometer com os internos.

Eu gostaria de esclarecer algumas coisas que outros cartazes disse como dando informação errada.

Em primeiro lugar, pois os métodos são privados, mesmo se você declará-los estáticos você não será capaz de acessá-los fora desta classe. Em segundo lugar, são privados para que você não pode mesmo substituir na subclasse de modo estático ou não-estático não faz qualquer diferença. Em terceiro lugar um método privado não-estático pode ser chamado de um construtor da classe, também, ele não precisa ser estático.

Agora, chegando à sua pergunta se um método auxiliar privado deve ser definido como estático ou não-estático. Eu vou com a resposta de Steve como marcando um privadas mostras método estático que este método é apátrida como eu também seguir esta regra quando eu código.

A partir da experiência eu afirmar que tais métodos privados tendem a ser bastante universal e reutilizável.

Eu acho que a primeira coisa a fazer é perguntar a questão de saber se o método pode ser útil fora do contexto classe atual. Se assim for, eu faria exatamente o que todo mundo sugere e extrair este método como estático para alguma classe utils onde alguém esperançosamente verificações antes de implementar novo método fazendo exatamente a mesma coisa.

Tal uso geral métodos privados são fonte de grande parte da duplicação de código no projeto porque cada desenvolvedor reinventa-los de forma independente apenas no lugar que ela precisa usá-lo. Assim, a centralização de tais métodos é um caminho a percorrer.

A questão estático / non-static se resume a "será que eu realmente precisa usar um objeto dessa classe"?

Então, você está passando o objeto entre diferentes métodos? Será que o objeto conter informações que é útil fora do contexto dos métodos estáticos? Existe alguma razão para não definir métodos para os dois lados, se você vai usá-los em ambos os sentidos?

Se você está neste dilema, parece-me que você tem todos os dados necessários para o método flutuando em sua parte externa do código do objeto. É isso que voce quer? Seria mais fácil simplesmente sempre a cobrar que os dados em um objeto de cada vez? Você pode apenas ser ambivalente sobre comprometendo-se a um único modelo. Se você pode fazer tudo isso usando um caminho, em seguida, escolher estático ou não-estático e ir com ele.

Mais especificamente para o exemplo que você deu, parece que a finalidade de definir estes métodos é mais para maior clareza código quando você estiver lendo isso do que para a funcionalidade (que são definido como privado) . Nesse caso, indo com estática realmente não faz nada para você, uma vez que o propósito de estática é para expor a funcionalidade de classe.

Uma razão é que, ceteris paribus, chamadas de método estático deve ser mais rápido. Os métodos estáticos não pode ser virtual, e não tomar um implícito esta referência.

Off-Topic: Eu manteria os métodos auxiliares em uma classe de utilitário / ajudante autônomo com apenas métodos estáticos na mesma.

O problema com ter métodos auxiliares no ponto de uso (leia 'mesma classe') é que alguém abaixo da linha pode apenas optar por publicar seus próprios métodos auxiliares não relacionadas no mesmo lugar

class Whatever {

    public static varType myVar = initializeClassVariable();

    private static varType initializeClassVariable() {

        //initialization code goes here
    }
}

A vantagem de métodos estáticos privados é que eles podem ser reutilizados mais tarde, se você precisa reinicializar a variável de classe.

  1. Sem o estático modificador você não pode descobrir que o método é apátrida, sem análise adicional que pode ser feito facilmente quando você (re) escrever o método.

  2. Depois modificador "estático" pode lhe dar idéias sobre refatoração além de outras coisas que outros podem achar unuseful. Por exemplo. movendo-se o método para alguma classe Utility ou convertê-lo para um método membro ..

Gostaria de declará-los como estático para sinalizá-las como apátrida.

Java não tem um melhor mecanismo para operações menores que não são exportados, então eu acho estática privada é aceitável.

Como muitas pessoas disseram, torná-lo é como um estática ! Aqui é a regra de ouro que eu sigo: Se você acha que o método é apenas um função matemática ou seja, é apátrida, não envolve quaisquer variáveis ??de instância (=> nenhuma cor azul vars [no eclipse] no método), e o resultado do método será o mesmo para número 'n' de chamadas (com os mesmos parâmetros, é claro), em seguida, marcar esse método como estático.

E se você acha que este método será útil para outra classe, em seguida, movê-lo para uma classe Util de outra forma, colocar o método como privado no sameclass. (Minimizando a acessibilidade)

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