Eu sou um programador Java que é novo no mundo corporativo. Recentemente desenvolvi um aplicativo usando Groovy e Java. Durante todo o código que escrevi, utilizamos um bom número de estáticas. O lote técnico sênior me pediu para reduzir o número de estáticas usadas. Eu pesquisei sobre o mesmo e descobri que muitos programadores são contra o uso de variáveis estáticas.
Acho variáveis estáticas mais convenientes de usar. E presumo que eles também sejam eficientes (por favor, corrija-me se estiver errado), porque se eu tivesse que fazer 10.000 chamadas para uma função dentro de uma classe, ficaria feliz em tornar o método estático e usar um método simples Class.methodCall()
em vez de bagunçando a memória com 10.000 instâncias da classe, certo?
Além disso, a estática reduz as interdependências nas outras partes do código. Eles podem agir como detentores de estado perfeitos. Além disso, acho que as estáticas são amplamente implementadas em alguns idiomas, como Smalltalk e Scala . Então, por que essa opressão pela estática prevalece entre os programadores (especialmente no mundo do Java)?
PS: corrija-me se minhas suposições sobre estática estiverem erradas.
Respostas:
Variáveis estáticas representam estado global. Isso é difícil de raciocinar e difícil de testar: se eu criar uma nova instância de um objeto, posso raciocinar sobre seu novo estado nos testes. Se eu usar código que está usando variáveis estáticas, ele pode estar em qualquer estado - e qualquer coisa pode estar modificando-o.
Eu poderia continuar por um bom tempo, mas o conceito maior em que pensar é que quanto mais restrito o escopo de algo, mais fácil é o raciocínio. Somos bons em pensar em coisas pequenas, mas é difícil argumentar sobre o estado de um sistema de um milhão de linhas se não houver modularidade. A propósito, isso se aplica a todo tipo de coisa - não apenas às variáveis estáticas.
fonte
Não é muito orientado a objetos: Uma razão pela qual as estáticas podem ser consideradas "más" por algumas pessoas é que elas são contrárias ao paradigma orientado a objetos . Em particular, viola o princípio de que os dados são encapsulados em objetos (que podem ser estendidos, ocultação de informações etc.). As estáticas, da maneira que você as descreve, são essencialmente para usá-las como uma variável global para evitar lidar com questões como escopo. Entretanto, variáveis globais são uma das características definidoras do paradigma de programação procedural ou imperativa, não uma característica do código "bom" orientado a objetos. Isso não quer dizer que o paradigma processual seja ruim, mas tenho a impressão de que seu supervisor espera que você escreva "um bom código orientado a objetos" e que realmente queira escrever "
Existem muitas dicas em Java quando você começa a usar estática que nem sempre é imediatamente óbvia. Por exemplo, se você tiver duas cópias do seu programa em execução na mesma VM, elas dividirão o valor da variável estática e interferirão no estado uma da outra? Ou o que acontece quando você estende a classe, você pode substituir o membro estático? Sua VM está ficando sem memória porque você tem números insanos de estática e essa memória não pode ser recuperada para outros objetos de instância necessários?
Vida útil do objeto: Além disso, as estáticas têm uma vida útil que corresponde ao tempo de execução inteiro do programa. Isso significa que, mesmo quando você terminar de usar sua classe, a memória de todas essas variáveis estáticas não poderá ser coletada como lixo. Se, por exemplo, você tornou suas variáveis não estáticas e, em sua função main (), criou uma única instância da sua classe e pediu à sua classe para executar uma função específica 10.000 vezes, uma vez que essas 10.000 chamadas foram feitas , e você excluir suas referências para a instância única, todas as suas variáveis estáticas poderão ser coletadas e reutilizadas como lixo.
Impede certa reutilização: Além disso, métodos estáticos não podem ser usados para implementar uma interface, portanto, métodos estáticos podem impedir que certos recursos orientados a objetos sejam utilizáveis.
Outras opções: Se a eficiência é sua principal preocupação, pode haver outras maneiras melhores de resolver o problema de velocidade do que considerar apenas a vantagem de a invocação ser geralmente mais rápida que a criação. Considere se os modificadores transitórios ou voláteis são necessários em qualquer lugar. Para preservar a capacidade de inclusão, um método pode ser marcado como final em vez de estático. Os parâmetros do método e outras variáveis podem ser marcados como finais para permitir certas otimizações do compilador com base em suposições sobre o que pode alterar essas variáveis. Um objeto de instância pode ser reutilizado várias vezes, em vez de criar uma nova instância a cada vez. Pode haver opções de otimização do compilador que devem estar ativadas para o aplicativo em geral. Talvez o design deva ser configurado para que as 10.000 execuções possam ser multiencadeadas e aproveitar os núcleos de vários processadores. Se a portabilidade não for
Se, por algum motivo, você não desejar várias cópias de um objeto, o padrão de design singleton, possui vantagens sobre objetos estáticos, como segurança de thread (presumindo que seu singleton seja bem codificado), permitindo inicialização lenta, garantindo que o objeto tenha sido inicializado corretamente quando usado, subclassificação, vantagens em testar e refatorar seu código, para não mencionar, se em algum momento você mudar de idéia sobre querer apenas uma instância de um objeto, é MUITO mais fácil remover o código para evitar instâncias duplicadas do que refatorar todo o seu código de variável estática para usar variáveis de instância. Já tive que fazer isso antes, não é divertido, e você acaba editando muito mais classes, o que aumenta o risco de introduzir novos bugs ... muito melhor configurar as coisas "corretamente" na primeira vez, mesmo que pareça ter suas desvantagens. Para mim, o re-trabalho necessário, se você decidir no futuro que precisa de várias cópias de algo, é provavelmente um dos motivos mais convincentes para usar a estática com a menor frequência possível. E, portanto, eu também discordo de sua afirmação de que a estática reduz as interdependências. Acho que você terminará com um código mais acoplado se você tiver muitas estáticas que podem ser acessadas diretamente, em vez de um objeto que "sabe fazer" algo "em si mesmo.
fonte
synchronized
métodos), isso não significa que o código de chamada esteja livre de condições de corrida em relação ao estado do singleton.Object Lifetime
, é um ponto muito importante que a @jessica mencionou.Mal é um termo subjetivo.
Você não controla a estática em termos de criação e destruição. Eles vivem a pedido do programa, carregando e descarregando.
Como as estáticas residem em um espaço, todos os threads que desejam usá-las devem passar pelo controle de acesso que você precisa gerenciar. Isso significa que os programas são mais acoplados e essa mudança é mais difícil de visualizar e gerenciar (como diz J Skeet). Isso leva a problemas de isolamento do impacto das mudanças e, portanto, afeta a maneira como os testes são gerenciados.
Estes são os dois principais problemas que tenho com eles.
fonte
Não. Os estados globais não são maus por si só. Mas precisamos ver seu código para ver se você o usou corretamente. É bem possível que um novato abuse dos estados globais; assim como ele abusaria de todos os recursos do idioma.
Estados globais são necessidade absoluta. Não podemos evitar estados globais. Não podemos evitar o raciocínio sobre estados globais. - Se queremos entender nossa semântica de aplicativos.
As pessoas que tentam se livrar dos estados globais por causa disso inevitavelmente acabam com um sistema muito mais complexo - e os estados globais ainda estão lá, disfarçados de maneira inteligente / idiota sob muitas camadas de indiretos; e ainda temos que raciocinar sobre estados globais, depois de desembrulhar todos os indiretos.
Como as pessoas da Primavera que declaram generosamente os estados globais em xml e pensam que de alguma forma é superior.
@ Jon Skeet
if I create a new instance of an object
agora você tem duas razões para pensar: o estado dentro do objeto e o estado do ambiente que hospeda o objeto.fonte
Existem 2 problemas principais com variáveis estáticas:
fonte
Se você estiver usando a palavra-chave 'estática' sem a palavra-chave 'final', isso deve ser um sinal para considerar cuidadosamente seu design. Mesmo a presença de um 'final' não é um passe livre, pois um objeto final estático mutável pode ser igualmente perigoso.
Eu estimaria algo em torno de 85% das vezes que vejo uma 'estática' sem uma 'final', é ERRADO. Muitas vezes, vou encontrar soluções alternativas estranhas para mascarar ou ocultar esses problemas.
Por favor, não crie mutáveis estáticos. Especialmente coleções. Em geral, as coleções devem ser inicializadas quando o objeto que os contém é inicializado e devem ser projetadas para que sejam redefinidas ou esquecidas quando o objeto que as contém é esquecido.
O uso de estática pode criar bugs muito sutis, o que causará muitos dias de sofrimento aos engenheiros. Eu sei, porque eu criei e caço esses bugs.
Se você quiser obter mais detalhes, leia…
Por que não usar estática?
Há muitos problemas com a estática, incluindo a escrita e a execução de testes, além de erros sutis que não são imediatamente óbvios.
O código que depende de objetos estáticos não pode ser facilmente testado em unidade, e as estáticas não podem ser facilmente ridicularizadas (geralmente).
Se você usa estática, não é possível trocar a implementação da classe para testar componentes de nível superior. Por exemplo, imagine um CustomerDAO estático que retorne objetos Customer que ele carrega do banco de dados. Agora eu tenho uma classe CustomerFilter, que precisa acessar alguns objetos Customer. Se o CustomerDAO for estático, não posso escrever um teste para o CustomerFilter sem primeiro inicializar meu banco de dados e preencher informações úteis.
E a população e a inicialização do banco de dados levam muito tempo. E, na minha experiência, sua estrutura de inicialização do banco de dados mudará com o tempo, o que significa que os dados se transformarão e os testes poderão ser interrompidos. IE, imagine que o Cliente 1 costumava ser um VIP, mas a estrutura de inicialização do DB mudou e agora o Cliente 1 não é mais VIP, mas seu teste foi codificado para carregar o Cliente 1…
Uma abordagem melhor é instanciar um CustomerDAO e passá-lo para o CustomerFilter quando ele é construído. (Uma abordagem ainda melhor seria usar o Spring ou outra estrutura de Inversão de controle.
Depois de fazer isso, você pode rapidamente zombar ou deletar um DAO alternativo no CustomerFilterTest, permitindo que você tenha mais controle sobre o teste,
Sem o DAO estático, o teste será mais rápido (sem inicialização do banco de dados) e mais confiável (porque não falhará quando o código de inicialização do banco de dados for alterado). Por exemplo, nesse caso, garantir que o Cliente 1 seja e sempre será um VIP, no que diz respeito ao teste.
Executando testes
A estática causa um problema real ao executar conjuntos de testes de unidade juntos (por exemplo, com o servidor de Integração Contínua). Imagine um mapa estático de objetos Socket de rede que permaneçam abertos de um teste para outro. O primeiro teste pode abrir um soquete na porta 8080, mas você esqueceu de limpar o mapa quando o teste for interrompido. Agora, quando um segundo teste é iniciado, é provável que ocorra um erro fatal ao tentar criar um novo soquete para a porta 8080, pois a porta ainda está ocupada. Imagine também que as referências de soquete em sua coleção estática não sejam removidas e (com exceção do WeakHashMap) nunca são elegíveis para serem coletadas como lixo, causando um vazamento de memória.
Este é um exemplo super generalizado, mas em sistemas grandes, esse problema ocorre o tempo todo. As pessoas não pensam nos testes de unidade iniciando e parando seus softwares repetidamente na mesma JVM, mas é um bom teste para o design de seu software e, se você deseja obter alta disponibilidade, é algo que precisa estar ciente.
Esses problemas geralmente surgem com objetos de estrutura, por exemplo, suas camadas de acesso ao banco de dados, cache, sistema de mensagens e log. Se você estiver usando Java EE ou algumas das melhores estruturas de criação, provavelmente elas gerenciam muito disso para você, mas se, como eu, você está lidando com um sistema legado, pode ter muitas estruturas personalizadas para acessar essas camadas.
Se a configuração do sistema que se aplica a esses componentes da estrutura for alterada entre os testes de unidade, e a estrutura de teste de unidade não desmontar e reconstruir os componentes, essas alterações não terão efeito e, quando um teste depender dessas alterações, elas falharão. .
Mesmo componentes que não sejam de estrutura estão sujeitos a esse problema. Imagine um mapa estático chamado OpenOrders. Você escreve um teste que cria alguns pedidos em aberto e verifica se todos estão no estado correto e o teste termina. Outro desenvolvedor escreve um segundo teste que coloca os pedidos de que precisa no mapa OpenOrders e afirma que o número de pedidos é preciso. Executar individualmente, esses testes passariam, mas quando executados juntos em um conjunto, eles falhariam.
Pior, a falha pode ser baseada na ordem em que os testes foram executados.
Nesse caso, evitando a estática, você evita o risco de persistência de dados nas instâncias de teste, garantindo melhor confiabilidade do teste.
Erros sutis
Se você trabalha no ambiente de alta disponibilidade ou em qualquer lugar em que os encadeamentos possam ser iniciados e parados, a mesma preocupação mencionada acima com os conjuntos de testes de unidade pode ser aplicada quando o código também estiver em produção.
Ao lidar com threads, em vez de usar um objeto estático para armazenar dados, é melhor usar um objeto inicializado durante a fase de inicialização do thread. Dessa maneira, toda vez que o encadeamento é iniciado, uma nova instância do objeto (com uma configuração potencialmente nova) é criada e você evita que os dados de uma instância do encadeamento fluam para a próxima instância.
Quando um thread morre, um objeto estático não é redefinido ou coletado como lixo. Imagine que você tenha um segmento chamado "EmailCustomers" e, quando iniciado, preenche uma coleção estática de String com uma lista de endereços de email e começa a enviar cada um dos endereços. Digamos que o encadeamento seja interrompido ou cancelado de alguma forma, portanto sua estrutura de alta disponibilidade reinicia o encadeamento. Então, quando o encadeamento é iniciado, ele recarrega a lista de clientes. Mas como a coleção é estática, ela pode reter a lista de endereços de email da coleção anterior. Agora, alguns clientes podem receber e-mails duplicados.
An Aside: Final Estático
O uso de "final estático" é efetivamente o equivalente em Java de um C # definido, embora haja diferenças técnicas de implementação. AC / C ++ #define é trocado de código pelo pré-processador, antes da compilação. Um Java "estático final" acabará com a memória residente na pilha. Dessa forma, é mais semelhante a uma variável "const estática" em C ++ do que a um #define.
Sumário
Espero que isso ajude a explicar algumas razões básicas pelas quais a estática é problemática. Se você estiver usando uma estrutura Java moderna, como Java EE ou Spring, etc, poderá não encontrar muitas dessas situações, mas se estiver trabalhando com um grande corpo de código legado, elas poderão se tornar muito mais frequentes.
fonte
Como ninguém * mencionou: simultaneidade. As variáveis estáticas podem surpreendê-lo se você tiver vários threads lendo e gravando na variável estática. Isso é comum em aplicativos da web (por exemplo, ASP.NET) e pode causar alguns erros bastante enlouquecedores. Por exemplo, se você tiver uma variável estática atualizada por uma página e a página for solicitada por duas pessoas "quase ao mesmo tempo", um usuário poderá obter o resultado esperado pelo outro usuário ou pior.
Espero que você esteja preparado para usar bloqueios e lidar com disputas.
* Na verdade, Preet Sangha mencionou.
fonte
Resumindo algumas vantagens e desvantagens básicas do uso de métodos estáticos em Java:
Vantagens:
Desvantagens:
fonte
Você precisa equilibrar a necessidade de encapsular dados em um objeto com um estado, versus a necessidade de simplesmente computar o resultado de uma função em alguns dados.
O mesmo acontece com o encapsulamento. Em aplicações grandes, as estáticas tendem a produzir código espaguete e não permitem facilmente refatoração ou teste.
As outras respostas também fornecem boas razões contra o uso excessivo de estática.
fonte
As variáveis estáticas são geralmente consideradas ruins porque representam o estado global e, portanto, são muito mais difíceis de raciocinar. Em particular, eles quebram as suposições da programação orientada a objetos. Na programação orientada a objetos, cada objeto tem seu próprio estado, representado por variáveis de instância (não estáticas). As variáveis estáticas representam o estado entre instâncias, o que pode ser muito mais difícil de testar na unidade. Isso ocorre principalmente porque é mais difícil isolar alterações em variáveis estáticas em um único teste.
Dito isto, é importante fazer uma distinção entre variáveis estáticas regulares (geralmente consideradas ruins) e variáveis estáticas finais (constantes AKA; não tão ruins).
fonte
Na minha opinião, quase nunca é sobre desempenho, é sobre design. Eu não considero o uso de métodos estáticos errado, ao contrário do uso de variáveis estáticas (mas acho que você está realmente falando sobre chamadas de método).
É simplesmente sobre como isolar a lógica e dar a ela um bom lugar. Às vezes, isso justifica o uso de métodos estáticos, dos quais
java.lang.Math
é um bom exemplo. Eu acho que quando você nomeia a maioria de suas aulasXxxUtil
ouXxxhelper
é melhor reconsiderar seu design.fonte
Acabei de resumir alguns dos pontos apresentados nas respostas. Se você encontrar algo errado, sinta-se à vontade para corrigi-lo.
Dimensionamento: Temos exatamente uma instância de uma variável estática por JVM. Suponha que estamos desenvolvendo um sistema de gerenciamento de bibliotecas e decidimos colocar o nome do livro em uma variável estática, pois existe apenas um por livro. Mas se o sistema cresce e estamos usando várias JVMs, não temos como descobrir com qual livro estamos lidando?
Segurança de thread: Tanto a variável de instância quanto a variável estática precisam ser controladas quando usadas em ambientes multithread. Porém, no caso de uma variável de instância, ela não precisa de proteção, a menos que seja explicitamente compartilhada entre os encadeamentos, mas no caso de uma variável estática, ela sempre é compartilhada por todos os encadeamentos no processo.
Teste: embora o design testável não seja igual ao bom design, mas raramente observaremos um bom design que não é testável. Como as variáveis estáticas representam o estado global e fica muito difícil testá-las.
Raciocínio sobre o estado: Se eu criar uma nova instância de uma classe, podemos raciocinar sobre o estado dessa instância, mas se ela tiver variáveis estáticas, poderá estar em qualquer estado. Por quê? Porque é possível que a variável estática tenha sido modificada por alguma instância diferente, pois a variável estática é compartilhada entre instâncias.
Serialização: A serialização também não funciona bem com eles.
Criação e destruição: a criação e a destruição de variáveis estáticas não podem ser controladas. Geralmente eles são criados e destruídos no tempo de carregamento e descarregamento do programa. Isso significa que eles são ruins para o gerenciamento de memória e também aumentam o tempo de inicialização na inicialização.
Mas e se realmente precisarmos deles?
Mas, às vezes, podemos ter uma necessidade genuína deles. Se realmente sentimos a necessidade de muitas variáveis estáticas compartilhadas no aplicativo, uma opção é fazer uso do padrão Singleton Design, que terá todas essas variáveis. Ou podemos criar algum objeto que tenha essas variáveis estáticas e possa ser transmitido.
Além disso, se a variável estática estiver marcada como final, ela se tornará uma constante e o valor atribuído a ela uma vez não poderá ser alterado. Isso significa que nos salvará de todos os problemas que enfrentamos devido à sua mutabilidade.
fonte
Parece-me que você está perguntando sobre variáveis estáticas, mas também aponta métodos estáticos em seus exemplos.
Variáveis estáticas não são más - elas são adotadas como variáveis globais, como constantes, na maioria dos casos combinadas com o modificador final, mas como foi dito, não as use demais.
Métodos estáticos, também conhecido como método utilitário. Geralmente, não é uma prática ruim usá-los, mas a grande preocupação é que eles possam obstruir os testes.
Como exemplo de um ótimo projeto java que usa muita estática e o faz da maneira correta, veja o Play! estrutura . Também há discussões sobre isso no SO.
Variáveis / métodos estáticos combinados à importação estática também são amplamente utilizados em bibliotecas que facilitam a programação declarativa em java, como: facilite ou Hamcrest . Não seria possível sem muitas variáveis e métodos estáticos.
Portanto, variáveis estáticas (e métodos) são boas, mas use-as com sabedoria!
fonte
As variáveis estáticas criam mais importante o problema com a segurança dos dados (a qualquer momento, qualquer pessoa pode mudar, acesso direto sem objeto, etc.)
Para mais informações, leia isto Obrigado.
fonte
Pode-se sugerir que na maioria dos casos em que você usa uma variável estática, você realmente deseja usar o padrão singleton .
O problema com os estados globais é que, às vezes, o que faz sentido como global em um contexto mais simples, precisa ser um pouco mais flexível em um contexto prático, e é aí que o padrão singleton se torna útil.
fonte
Mais um motivo: fragilidade.
Se você tem uma aula, a maioria das pessoas espera poder criá-la e usá-la à vontade.
Você pode documentar que não é o caso ou se proteger (padrão de singleton / fábrica) - mas isso é trabalho extra e, portanto, um custo adicional. Mesmo assim, em uma grande empresa, é provável que alguém tente em algum momento usar sua classe sem prestar atenção total a todos os bons comentários ou à fábrica.
Se você estiver usando muitas variáveis estáticas, isso será interrompido. Bugs são caros.
Entre uma melhoria de desempenho de 0,0001% e robustez a ser alterada por desenvolvedores potencialmente sem noção, em muitos casos a robustez é a boa escolha.
fonte
Acho variáveis estáticas mais convenientes de usar. E presumo que eles também sejam eficientes (por favor, corrija-me se estiver errado), porque se eu tivesse que fazer 10.000 chamadas para uma função dentro de uma classe, ficaria feliz em tornar o método estático e usar uma classe direta.methodCall () nele em vez de bagunçar a memória com 10.000 instâncias da classe, certo?
Entendo o que você pensa, mas um simples padrão Singleton fará o mesmo sem precisar instanciar 10.000 objetos.
métodos estáticos podem ser usados, mas apenas para funções relacionadas ao domínio do objeto e não precisam nem usam propriedades internas do objeto.
ex:
fonte
Class.Instance
) é pouco melhor do que uma variável estática. É um pouco mais testável, mas ainda muito pior do que os designs em que você cria uma única instância em vez de criar seu código na suposição de que há apenas uma.Class.Instance
) que carrega um estado mutável é um design IMO ruim. Nesse caso, eu prefiro fortemente um design em que obtenho os singletons necessários para passar como parâmetro para a classe que os utiliza (normalmente com a ajuda do DI). Singletons clássicos logicamente imutáveis são excelentes para IMO.A questão de 'Statics being evil' é mais uma questão sobre o estado global. O momento apropriado para uma variável ser estática é se ela nunca tiver mais de um estado; As ferramentas do IE que devem estar acessíveis por toda a estrutura e sempre retornar os mesmos resultados para as mesmas chamadas de método nunca são 'más' como as estáticas. Quanto ao seu comentário:
A estática é a escolha ideal e eficiente para variáveis / classes que nunca mudam .
O problema com o estado global é a inconsistência inerente que ele pode criar. A documentação sobre testes de unidade geralmente aborda esse problema, pois sempre que existe um estado global que pode ser acessado por mais de vários objetos não relacionados, seus testes de unidade ficam incompletos e não são granulados por 'unidade'. Conforme mencionado neste artigo sobre estado global e singletons , se os objetos A e B não estiverem relacionados (como em um não é expressamente dada referência a outro), então A não poderá afetar o estado de B.
Existem algumas exceções ao estado global de proibição em bom código, como o relógio. O tempo é global e, em certo sentido, altera o estado dos objetos sem ter um relacionamento codificado.
fonte
Meu $ .02 é que várias dessas respostas estão confundindo a questão, em vez de dizer "estática é ruim". Acho melhor falar sobre escopo e instâncias.
O que eu diria é que uma estática é uma variável de "classe" - representa um valor que é compartilhado em todas as instâncias dessa classe. Normalmente, o escopo também deve ser definido dessa maneira (protegido ou privado para a classe e suas instâncias).
Se você planeja colocar o comportamento em nível de classe em torno dele e expô-lo a outro código, um singleton pode ser uma solução melhor para suportar mudanças no futuro (como @ Jessica sugeriu). Isso ocorre porque você pode usar interfaces no nível da instância / singleton de maneiras que não podem ser usadas no nível da classe - em particular na herança.
Algumas reflexões sobre por que acho que alguns dos aspectos em outras respostas não são essenciais para a pergunta ...
A estática não é "global". No Java, o escopo é controlado separadamente do estático / instância.
A simultaneidade não é menos perigosa para a estática do que os métodos de instância. Ainda é um estado que precisa ser protegido. Claro que você pode ter 1000 instâncias com uma variável de instância, cada uma delas apenas uma variável estática, mas se o código acessado não for gravado de uma maneira segura para threads, você ainda está ferrado - pode demorar um pouco mais para você perceber. .
Gerenciar o ciclo de vida é um argumento interessante, mas acho que é menos importante. Não vejo por que é mais difícil gerenciar um par de métodos de classe como init () / clear () do que a criação e destruição de uma instância singleton. De fato, alguns podem dizer que um singleton é um pouco mais complicado devido ao GC.
PS: Em termos de Smalltalk, muitos de seus dialetos têm variáveis de classe, mas, em Smalltalk, as classes são na verdade instâncias do Metaclass e, na verdade, são variáveis na instância do Metaclass. Mesmo assim, eu aplicaria a mesma regra de ouro. Se eles estão sendo usados para estado compartilhado entre instâncias, ok. Se eles oferecem suporte à funcionalidade pública, você deve procurar um Singleton. Suspiro, com certeza sinto falta de Smalltalk ....
fonte
Há duas perguntas principais em sua postagem.
Primeiro, sobre variáveis estáticas. Variáveis estáticas são totalmente desnecessárias e seu uso pode ser evitado facilmente. Em idiomas OOP em geral, e em Java em particular, os parâmetros de função são colados por referência, ou seja, se você passa um objeto para um funciont, está passando um ponteiro para o objeto, portanto, não é necessário definir variáveis estáticas, pois você pode passar um ponteiro para o objeto para qualquer escopo que precise dessas informações. Mesmo que isso implique que você preencherá sua memória com ponteiros, isso não será necessário para um desempenho ruim, porque os sistemas de paginação de memória reais são otimizados para lidar com isso e manterão na memória as páginas referenciadas pelos ponteiros que você passou para o novo escopo; o uso de variáveis estáticas pode fazer com que o sistema carregue a página de memória onde estão armazenadas quando precisam ser acessadas (isso acontecerá se a página não for acessada há muito tempo). Uma boa prática é reunir todo esse material estático em alguns pequenos "clases de configuração", isso garantirá que o sistema coloque tudo na mesma página de memória.
Segundo, sobre métodos estáticos. Os métodos estáticos não são tão ruins, mas podem reduzir rapidamente o desempenho. Por exemplo, pense em um método que compara dois objetos de uma classe e retorne um valor indicando qual dos objetos é maior (método típico de comparação). Esse método pode ser estático ou não, mas ao invocá-lo, a forma não estática será mais eficiente pois ele terá que resolver apenas duas referências (uma para cada objeto) face às três referências que terão que resolver a versão estática do mesmo método (uma para a classe mais duas, uma para cada objeto). Mas, como eu disse, isso não é tão ruim, se dermos uma olhada na classe Math, podemos encontrar muitas funções matemáticas definidas como métodos estáticos. Isso é realmente mais eficiente do que colocar todos esses métodos na classe que define os números,
Conclusão: evite o uso de variáveis estáticas e encontre o equilíbrio correto de desempenho ao lidar com métodos estáticos ou não estáticos.
PS: Desculpe pelo meu inglês.
fonte
Não há nada errado com variáveis estáticas em si. É apenas a sintaxe Java que está quebrada. Cada classe Java realmente define duas estruturas - um objeto singleton que encapsula variáveis estáticas e uma instância. Definir os dois no mesmo bloco de origem é pura maldade e resulta em um código difícil de ler. Scala fez isso certo.
fonte
a) Razão sobre os programas.
Se você tem um programa de pequeno a médio porte, onde a variável estática Global.foo é acessada, a chamada para ela normalmente não vem do nada - não há caminho e, portanto, não há cronograma, como a variável chega ao local, onde é usado. Agora, como sei quem definiu o valor real? Como sei o que acontece se eu o modificar agora? Eu tenho grep sobre toda a fonte, para coletar todos os acessos, para saber o que está acontecendo.
Se você souber como usá-lo, porque acabou de escrever o código, o problema é invisível, mas se você tentar entender código estrangeiro, entenderá.
b) Você realmente precisa apenas de um?
Variáveis estáticas geralmente impedem que vários programas do mesmo tipo sejam executados na mesma JVM com valores diferentes. Geralmente, você não prevê usos, onde mais de uma instância do seu programa é útil, mas se ela evoluir, ou se for útil para outras pessoas, elas poderão enfrentar situações em que gostariam de iniciar mais de uma instância do seu programa. .
Somente código mais ou menos inútil, que não será usado por muitas pessoas por um longo período de forma intensiva, pode funcionar bem com variáveis estáticas.
fonte
tudo (pode :) ter seu objetivo, se você tiver um monte de threads que precisam compartilhar / armazenar dados em cache e também toda a memória acessível (para não se dividir em contextos em uma JVM), a estática é a melhor escolha
-> é claro que você pode forçar apenas uma instância, mas por quê?
Eu acho que alguns dos comentários neste tópico são maus, não estáticos;)
fonte
Variáveis estáticas não são boas nem más. Eles representam atributos que descrevem toda a classe e não uma instância específica. Se você precisar de um contador para todas as instâncias de uma determinada classe, uma variável estática seria o local certo para armazenar o valor.
Os problemas aparecem quando você tenta usar variáveis estáticas para manter valores relacionados à instância.
fonte
Todas as respostas acima mostram por que as estáticas são ruins. A razão pela qual eles são maus é porque isso dá a falsa impressão de que você está escrevendo código orientado a objetos, quando na verdade não está. Isso é simplesmente mau.
fonte
Há muitas boas respostas aqui, adicionando a ela,
Memória: as variáveis estáticas permanecem ativas enquanto o carregador de classes permanecer [em geral até a VM morrer], mas isso ocorre apenas no caso de objetos em massa / referências armazenados como estáticos.
Modularização: considere conceitos como IOC, dependencyInjection, proxy etc. Todos são totalmente contra implementações estáticas / de acoplamento rígido.
Outros Contras: Segurança de Rosca, Testabilidade
fonte
Pense que, se você tiver um aplicativo com muitos usuários e definir um formulário estático, todos os usuários também modificarão todos os outros formulários.
fonte
Eu acho que o uso excessivo de variáveis globais com palavra-chave estática também levará ao vazamento de memória em algum momento da aplicação
fonte
Do meu ponto de vista, a
static
variável deve ser apenas leitura de dados ou variáveis criadas por convenção .Por exemplo, temos uma interface do usuário de algum projeto e temos uma lista de países, idiomas, funções de usuário etc. E temos aulas para organizar esses dados. Temos certeza absoluta de que o aplicativo não funcionará sem essas listas. portanto, o primeiro que fazemos no init do aplicativo é verificar esta lista para atualizações e obter essa lista da API (se necessário). Portanto, concordamos que esses dados estão "sempre" presentes no aplicativo. São dados apenas para leitura, portanto, não precisamos cuidar do seu estado - pensando nesse caso, não queremos ter muitas instâncias desses dados - esse caso parece um candidato perfeito para ser estático .
fonte
Eu brinquei muito com estática e posso lhe dar uma resposta um pouco diferente - ou talvez uma maneira um pouco diferente de encará-la?
Quando eu usei estática em uma classe (membros e métodos, ambos), comecei a perceber que minha classe é na verdade duas classes que compartilham responsabilidades - existe a parte "Estática", que age muito como um singleton e existe a não parte estática (uma classe normal). Tanto quanto eu sei, você sempre pode separar completamente essas duas classes apenas selecionando todas as estáticas para uma classe e as não estáticas para a outra.
Isso costumava acontecer muito quando eu tinha uma coleção estática dentro de uma classe contendo instâncias da classe e alguns métodos estáticos para gerenciar a coleção. Quando você pensa sobre isso, é óbvio que sua turma não está fazendo "Apenas uma coisa", é uma coleção e está fazendo algo completamente diferente.
Agora, vamos refatorar um pouco o problema: se você dividir sua classe em uma classe onde tudo é estático e outro que é apenas uma "Classe Normal" e esquecer a "Classe Normal", sua pergunta se tornará puramente estática versus Singleton, que é abordada em comprimento aqui (e provavelmente uma dúzia de outras questões).
fonte