Por que utilizar métodos e atributos estáticos em Java ou em qualquer outra linguagem?
Fala ai pessoal, blza? Me surgiu uma dúvida... Sei o que são métodos e atributos estáticos e para que eles servem. No entanto, não consigo pensar em nenhum exemplo que eu possa utilizar um atributo estático de uma classe, por exemplo.
Digo, uma classe pessoa, qual atributo estático posso criar para uma pessoa, sendo que cada pessoa tem suas características.
Sei que o ideal seria eu abstrair o máximo de informação desnecessária possível, porem, conseguiriam me dar um exemplo prático onde a criação de um método é melhor com ele sendo estático?
Você achou a solução e agora quer arrumar um problema para usar a solução. É mais ou menos o que fazem as pessoas que descobrem os design petterns do GOF.
Quando não acha como usar em um lugar tem grande chance de não ter uso ali.
No seu exemplo, não é fácil achar algo estático para uma Pessoa
. É possível, mas tem grande chance de ser um design errado e que deveria estar em outra classe.
Aí caímos em outro problema dos exemplos artificiais. Eles podem ajudar em algo específico, mas no fim ensina errado o geral. Por exemplo, o tal do Cachorro
e Gato
que herdam de Animal
mostra muito bem como é a herança e ensina errado como usar.
Com requisitos reais, tem o problema, bem descrito, e aí vamos achando soluções para ele, e podemos aplicar algum mecanismo adequado para aquele caso, quem sabe algo estático.
Se sabe que os membros estáticos pertencem à classe e não aos objetos, devem entender que serão dados globais, que só existe um por toda a aplicação. Sua classe precisa disto?
Cuidado, estado global pode ser um enorme problema, a menos que seja imutável. Veja mais em https://pt.stackoverflow.com/q/21158/101.
Uma boa estratégia para começar a ter uma ideia onde faz sentido ter algo assim é começar a olhar a documentação das bibliotecas padrões do Java. Verá que a maioria das classes não possuem nada estático, em especial campos estáticos, ou até mesmo getters/setters. Mas tem alguns, e ali vai entendendo porque usaram daquela forma.
Vamos pegar a classe String
. Notamos que tem apenas um campo imutável e alguns poucos métodos. O que eles têm de diferente? Elas não operam em cima de uma string existente, portanto não podem ser de instância. Mas por que eles estão nesta classe? Porque são métodos que produzem uma string de forma generalizada. Não quer dizer que tudo que gere uma string deve estar ali, mas aquilo que tem uma ligação muito direta com um objeto desse tipo.
Já parou para pensar que os construtores são estáticos? E algumas linguagens nem tem construtores de verdade, apenas métodos factories, que são estáticos. Muitos ou todos os métodos estáticos do exemplo acima provavelmente são factories.
Um exemplo que algumas linguagens adotam é poder manipular um objeto que pode ser nulo. Se o método fosse de instância daria erro, com um método estático é possível definir uma estratégia para este caso sem dar um erro. A possível ausência de um objeto é um bom motivo para ter um método estático.
Em C# temos métodos de extensão, que são estáticos. Estes métodos "simulam" métodos de uma classe sem pertencer a elas. Não vou entrar em detalhes aqui.
Tem uns casos que uma classe herdando de outra pode mudar um estado da API e você precisa saber disso. Ou seja, você precisa saber se aquela classe tem uma certa capacidade e tem um método na classe base que diz se tem ou não a capacidade, e quem herdar deve dizer se a capacidade está disponível ou não. Algumas pessoas dirão que isso viola o polimorfismo e Liskov, mas existe por aí.
Quase sempre é algo ruim, mas vamos dizer que uma classe guarde dados que vão sendo adicionados (em alguma coleção), então precisa de campo estático e pelo menos um método para adicionar, provavelmente outros para pegar, remover, etc. Quase sempre que precise fazer isso deveria ser em uma instância e não na classe, mesmo que a instância seja única por toda a aplicação. Mas se fizer precisa ter certeza que não haverá concorrência ou que tudo está preparado para funcionar corretamente dentro deste cenário. Um exemplo semelhante é ter um contador conforme vai criando novas instâncias ou por alguma outra ação que precise controlar contagem ou acumulação. Quase sempre é o jeito errado de fazer, mas tem por aí.
Uma obviedade é que classes estáticas possuem métodos estáticos, mas acredito que não é o caso da dificuldade de entendimento.
É bom notar também que os mais radicais proponentes de OOP dizem que nada deveria ser estático e isso é uma violação do paradigma. Eu já penso exatamente o contrário, ou seja, por padrão tudo deveria ser estático, até que se prove que não deveria. Veja bem, quase tudo não será estático, mas estático, quando usado adequadamente, é melhor, é mais eficiente e dá menos enrosco (evitando estado mutável). Lembre-se que um método estático tende a ser mais puro que um de instância que por padrão tem efeito colateral.
O default não deveria ser o que mais usa, mas sim o que deveria usar se não pensar sobre o assunto e adotar de qualquer jeito. É mais ou menos como devemos pensar sobre segurança, sabe, quando tudo deve ser considerado inconfiável, até que se prove confiável? A maioria das coisas serão confiáveis, mas você não pode pensar assim.
Por fim, quero te dizer que aprendeu um termo errado, já que a maioria das pessoas aprenderam errado e ensinam errado. Pelo menos em certo contexto, de Java, por exemplo, onde mais as pessoas usam ele errado. Para saber mais: https://pt.stackoverflow.com/q/269089/101.
Faz sentido para você?
Espero ter ajudado.
Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente. Para saber quando, me segue nas suas plataformas preferidas. Quase não as uso, não terá infindas notificações (links aqui).
De forma bem simplificada, se um método não depende de nenhuma informação de uma instância, então ele pode ser estático. Uma regra geral seria: "Faz sentido chamar este método, mesmo se eu não tiver criado nenhuma instância?" - se a resposta for "sim", provavelmente o método deveria ser estático.
Um exemplo são os métodos da classe java.lang.Math
, que basicamente servem para fazer operações matemáticas. Por exemplo, para arredondar um número para baixo vc usa Math.floor(numero)
. Faz sentido eu precisar criar uma instância de Math
para fazer tal cálculo? Imagine se eu precisasse fazer Math m = new Math()
para só depois chamar m.floor(numero)
. Neste caso não é necessário, porque a operação floor
não precisa de nenhum estado associado à uma hipotética instância de Math
(aliás, eu nem consigo criar uma instância, já que o construtor da classe é privado - isso foi proposital, justamente para indicar que não é para ninguém ficar criando instâncias desnecessárias).
Um outro exemplo é quando você quer controlar a forma como as instâncias são criadas, e em vez de criar vários construtores, cria factory methods (como já citado pelo Maniero), que por sua vez delegam para o construtor. Um exemplo disso é a classe java.time.LocalDate
, que possui vários métodos estáticos para criar datas de diferentes maneiras (now
para criar a cada atual, of(ano, mes, dia)
para uma data específica, etc). Internamente todos esses métodos validam os dados e repassam para o construtor da classe, que é privado (ou seja, a única forma de criar instâncias é usando os métodos estáticos). Assim, cada método cuida da sua parte específica (now
chama o relógio do sistema e extrai o dia, mês e ano; of
só precisa validar os valores do dia, mês e ano, etc) e no final eles usam o construtor para criar a instância.
Atributos estáticos de uma classe podem conservar características globais do domínio do problema. Uma classe de Pessoa pode ter constantes, por exemplo, chamadas PF = 1 e PJ = 2. Isso modela no domínio que só podem haver dois tipos de pessoas: física e jurídica.
Você também pode ter também um método estático chamado find, que retorna uma lista de pessoas com determinados critérios de busca.
Os dois exemplos que eu dei extrapolam as características de determinada instância, mas ainda se concentram no domínio do assunto de pessoas. É justo estar modelado na classe Pessoa.
Diante de atributos e métodos estáticos, encare a classe como sendo um grupo de constantes e funções similares, com a classe servindo pra classificar o atributo ou o método.
Pense na classe Math
do Java (ou JavaScript).
Nela os atributos estáticos são constantes matemáticas (por ex.: Math.PI
) e os métodos são funções matemáticas (por ex.: Math.pow(x, y)
).
Faz sentido criar um novo objeto do tipo "Matemática" pra fazer um cálculo direto? Na minha cabeça não.
Vamos lá. Existem informações fixas na classe. Ou então seu método só processa os argumentos e devolve um valor.
Então para quê criar uma instância da Classe? É para isso que existem.
Sem método estático, teríamos algo + ou - assim, sim eu sei, a sintaxe tá errada, mas quero só passar uma ideia.
Calculo objCalculo = new new Calculo(); resposta = objCalculo.dobro(80);
Com método estático, note que usamos a classe diretamente sem precisar instanciar resposta = Calculo.dobro(80);
O método dobro() não depende de nenhum valor que está nas propriedades do objeto, então ele pode sim ser estático.
Se precisasse de algum valor que está na propriedade da instância, não daria. Lembre-se que vários objetos da mesma classe podem ter valores diferentes nas sua propriedades.
Outra vantagem. Como seu método é estático, isso economiza memória, você não vai ter várias copias dele para cada instância, mas apenas uma cópia por Classe.