Não entendi completamente os construtores estáticos em Java. Se é permitido, por que é permitido? Em quais cenários você o usaria? Que finalidade isso serviria? Alguém pode me dar um exemplo simples, por favor?
Compartilhar sua pesquisa ajuda a todos. Conte-nos o que você tentou e por que ele não atendeu às suas necessidades. Isso demonstra que você dedicou um tempo para tentar ajudar a si mesmo, evita reiterar respostas óbvias e, acima de tudo, ajuda a obter uma resposta mais específica e relevante. Veja também How to Ask
gnat
3
Não existe um "construtor estático".
David Conrad
Respostas:
27
Estritamente falando, Java não possui construtores estáticos porque um construtor, por definição, não pode ser estático. O que você está se referindo é chamado de "bloco de inicialização estática". Um construtor implica que você está construindo um objeto. Você não pode ter construtor para uma classe porque uma classe não é uma instância em si. É simplesmente uma classe. O que "constrói" a classe é chamado de compilador (ou a máquina virtual, dependendo do significado de "construções") e, se você cria código dentro de outro código, entra na geração de código, o que é um animal completamente diferente.
Tirando todos os detalhes, um bloco de inicialização estático é usado para inicializar campos estáticos (ou em nível de classe) complexos para uma classe. Geralmente, eles são usados para inicializar coisas que não podem ser inicializadas em uma linha ou exigem que outro objeto (que pode ou não estar na classe em que o bloco estático é implementado) seja inicializado primeiro.
Basicamente, pode-se usá-los para dizer à classe "Ei, defina a variável A com esse valor PRIMEIRO, depois que isso for feito, use o valor de A para inicializar B." Como o Java exige que a inicialização do campo padrão seja feita dentro de um construtor ou método, ou através da chamada de um construtor ou método (a menos que seja literal), esse pode ser um método conveniente para inicializar objetos estáticos complexos.
Blocos de inicialização estática não são necessários com muita frequência e geralmente devem ser evitados, a menos que tenham um uso real . Não me interpretem mal, eles têm seu lugar no Java, mas, como muitas outras coisas (como instruções break, return, switch e goto), eles podem ser facilmente superutilizados, o que reduz a legibilidade e a manutenção do código -base em que são usados.
Um breve exemplo de um bloco de inicialização estática sendo usado seria o seguinte (conforme excelente explicação dos blocos de inicialização estática encontrados aqui ):
Código:
publicclassStaticExample{static{System.out.println("This is first static block");}publicStaticExample(){System.out.println("This is constructor");}publicstaticString staticString ="Static Variable";static{System.out.println("This is second static block and "+ staticString);}publicstaticvoid main(String[] args){StaticExample statEx =newStaticExample();StaticExample.staticMethod2();}static{
staticMethod();System.out.println("This is third static block");}publicstaticvoid staticMethod(){System.out.println("This is static method");}publicstaticvoid staticMethod2(){System.out.println("This is static method2");}}
Resultado:
This is first static block
This is second static block and Static Variable
This is static method
This is third static block
This is constructor
This is static method2
Algumas instâncias listam quando blocos estáticos podem ser úteis:
Se você estiver carregando drivers e outros itens no espaço para nome. Por exemplo, a classe Class possui um bloco estático no qual registra os nativos.
Se você precisar fazer cálculos para inicializar suas variáveis estáticas, poderá declarar um bloco estático que será executado exatamente uma vez, quando a classe for carregada pela primeira vez.
Problemas relacionados à segurança ou tarefas relacionadas ao log
Algumas razões para NÃO usar blocos estáticos (em outras situações):
Há uma limitação da JVM de que um bloco inicializador estático não deve exceder 64K.
Você não pode lançar exceções verificadas.
Você não pode usar a thispalavra - chave, pois não há instância.
Você não deve tentar acessar super, pois não existe tal coisa para blocos estáticos.
Você não deve devolver nada deste bloco.
Blocos estáticos tornam o teste um pesadelo.
Devo observar: Embora algumas linguagens (como C #) possam ter sintaxe para "construtores" que são estáticos, esses "construtores" funcionam da mesma maneira que os blocos de inicialização estática funcionam em Java e são vistos por muitos (inclusive eu) como equívocos na linguagem, dado o conceito básico de um construtor OOP .
não é possível preencher um mapa na inicialização (a menos que você use o hack da subclasse anônima), portanto, esta é a melhor maneira de garantir que ele seja preenchido antes do primeiro uso
Você também pode fazer isso para capturar exceções verificadas ao inicializar
Esse foi um dos principais usos que eu já vi, mas com a inclusão dos métodos de fábrica estáticos para a estrutura de coleções no Java 9, esse caso de uso foi realmente preterido de certa forma.
Hangman4358
2
A resposta de Gurgadurgen é provavelmente o que você está procurando, mas vou adicionar alguns outros pontos que às vezes são negligenciados quando alguém quer um "construtor estático".
Se você deseja um método estático que cria uma instância da sua classe, pode criar um método estático que simplesmente chama o construtor da classe.
publicclassExample{/** Static method to create an instance. */publicstaticExample build(){returnnewExample();}/** A field of each instance. */privateString stuff ;/** The class's actual constructor. */publicExample(){ stuff =newString();}publicString getStuff(){returnthis.stuff ;}/**
* Mutator for "stuff" property. By convention this returns "void"
* but you might want to return the object itself, to support the
* sort of chained invocations that are becoming trendy now. You'll
* see the stylistic benefits of chaining later in this example.
*/publicExample setStuff(String newStuff ){this.stuff = newStuff ;returnthis;}}publicclassExampleTest{publicstaticvoid main(String[] args ){// The usual instance model.Example first =newExample();System.out.println( first.setStuff("stuff").getStuff());// Using your static method to construct an instance:Example second =Example.build();System.out.println( second.setStuff("more stuff").getStuff());// Chaining all the invocations at once:System.out.println(Example.build().setStuff("even more stuff").getStuff());}}
Isso produz a saída:
stuff
more stuff
even more stuff
O outro motivo para criar um método estático para construir uma instância é o caso em que você deseja garantir que exista exatamente uma instância da sua classe a qualquer momento; isso é chamado de singleton . Por convenção, essa classe forneceria um método estático chamado getInstance()para obter a única instância que é tratada como um "singleton".
publicclassSingletonExampleextendsExample{// Note: This extends my previous example, which has a "stuff"// property, and a trivial constructor./** The singleton instance, statically initialized as null. */privatestaticSingletonExample singleton =null;/**
* The static accessor for the singleton. If no instance exists,
* then it will be created; otherwise, the one that already exists
* will be returned.
*/publicstaticSingletonExample getInstance(){if( singleton ==null)
singleton =newSingletonExample();return singleton ;}}publicclassSingletonExampleTest{publicstaticvoid main(String[] args ){System.out.println(SingletonExample.getInstance().setStuff("stuff").getStuff());// You could still create instances of this class normally if you want to.SingletonExample otherstuff =newSingletonExample();
otherstuff.setStuff("other stuff");// But watch what happens to this.System.out.println(SingletonExample.getInstance().getStuff());System.out.println( otherstuff.getStuff());// Now we show what happens when you start modifying the singleton.SingletonExample theoneandonly =SingletonExample.getInstance();
theoneandonly.setStuff("changed stuff");System.out.println(SingletonExample.getInstance().getStuff());}}
Isso produz o seguinte.
stuff
stuff
other stuff
changed stuff
Armazenando uma referência ao singleton e modificando-o, a próxima chamada para getInstance()obtém esse singleton modificado.
É tentador usar singletons como uma maneira de começar a criar variáveis globais para seu aplicativo. Em alguns contextos, isso pode ser útil, mas também pode causar problemas. Em particular, deparei-me com um bug interessante ao desenvolver um aplicativo Android, onde as instâncias singleton poderiam se perder. Ir de uma atividade para outra às vezes pode levar a JVM a usar um novo "carregador de classes" que não saberá sobre o singleton que foi armazenado estaticamente por um carregador de classes anterior.
Embora eu entenda que há muitos que veem a noção de um "construtor estático" como um nome impróprio, não acredito que seja esse o caso. O problema está no processo de construção de ambas as classes e seus objetos de instância . Já foi afirmado em outros threads que a construção da classe é o trabalho do compilador. Mesmo em Java, isso é apenas meia verdade.
O compilador constrói um andaime para cada definição de classe. O andaime contém metadados sobre a classe e quais instâncias devem ter neles no momento da construção. Se uma classe define um campo ao qual é atribuído um valor primitivo constante, esse valor é incluído no andaime pelo compilador. Para qualquer outro tipo de valor atribuído, o compilador gera uma rotina de inicialização que deve ser executada 1 vez, antes da criação da instância da primeira classe, que atualiza o andaime com os valores adequados. Esta atualização não pode ser feita pelo compilador.
Como essa atualização única para o andaime é frequentemente um pré-requisito crítico para o bom funcionamento dos construtores de instância, também é razoável chamá-lo de tipo de construtor. É por isso que nas linguagens OO comuns que suportam o conceito, é chamado de construtor estático. O conceito por trás dos blocos de inicialização estática em Java é pouco mais do que uma mudança semântica para manter a noção de que um programador Java deve ser independente de sistema e de implementação.
Como outras respostas disseram, você pode escrever métodos estáticos que constroem um objeto. Isso contorna a falta de construtores nomeados em Java (e muitas outras linguagens. O Delphi suporta construtores nomeados). Você pode jogar com os tipos e a ordem dos parâmetros, mas isso pode levar a um código pouco claro e frágil.
Por exemplo, poderíamos inventar um cenário em que seu objeto possa ser construído a partir de uma string XML ou JSON. Você pode escrever métodos como:
Enquanto leio a pergunta, trata-se de inicializadores estáticos, não de métodos estáticos normais.
CodesInChaos
-2
Você pode visualizar a seção "estática" como um construtor de nível de classe usado para inicializar propriedades da classe (estática em java). O mesmo que o construtor "normal" é usado para inicializar propriedades no nível da instância.
Respostas:
Estritamente falando, Java não possui construtores estáticos porque um construtor, por definição, não pode ser estático. O que você está se referindo é chamado de "bloco de inicialização estática". Um construtor implica que você está construindo um objeto. Você não pode ter construtor para uma classe porque uma classe não é uma instância em si. É simplesmente uma classe. O que "constrói" a classe é chamado de compilador (ou a máquina virtual, dependendo do significado de "construções") e, se você cria código dentro de outro código, entra na geração de código, o que é um animal completamente diferente.
Tirando todos os detalhes, um bloco de inicialização estático é usado para inicializar campos estáticos (ou em nível de classe) complexos para uma classe. Geralmente, eles são usados para inicializar coisas que não podem ser inicializadas em uma linha ou exigem que outro objeto (que pode ou não estar na classe em que o bloco estático é implementado) seja inicializado primeiro.
Basicamente, pode-se usá-los para dizer à classe "Ei, defina a variável A com esse valor PRIMEIRO, depois que isso for feito, use o valor de A para inicializar B." Como o Java exige que a inicialização do campo padrão seja feita dentro de um construtor ou método, ou através da chamada de um construtor ou método (a menos que seja literal), esse pode ser um método conveniente para inicializar objetos estáticos complexos.
Blocos de inicialização estática não são necessários com muita frequência e geralmente devem ser evitados, a menos que tenham um uso real . Não me interpretem mal, eles têm seu lugar no Java, mas, como muitas outras coisas (como instruções break, return, switch e goto), eles podem ser facilmente superutilizados, o que reduz a legibilidade e a manutenção do código -base em que são usados.
Um breve exemplo de um bloco de inicialização estática sendo usado seria o seguinte (conforme excelente explicação dos blocos de inicialização estática encontrados aqui ):
Código:
Resultado:
Algumas instâncias listam quando blocos estáticos podem ser úteis:
Algumas razões para NÃO usar blocos estáticos (em outras situações):
this
palavra - chave, pois não há instância.Devo observar: Embora algumas linguagens (como C #) possam ter sintaxe para "construtores" que são estáticos, esses "construtores" funcionam da mesma maneira que os blocos de inicialização estática funcionam em Java e são vistos por muitos (inclusive eu) como equívocos na linguagem, dado o conceito básico de um construtor OOP .
fonte
é usado para inicializar campos mais difíceis do que simplesmente atribuí-lo:
não é possível preencher um mapa na inicialização (a menos que você use o hack da subclasse anônima), portanto, esta é a melhor maneira de garantir que ele seja preenchido antes do primeiro uso
Você também pode fazer isso para capturar exceções verificadas ao inicializar
fonte
A resposta de Gurgadurgen é provavelmente o que você está procurando, mas vou adicionar alguns outros pontos que às vezes são negligenciados quando alguém quer um "construtor estático".
Se você deseja um método estático que cria uma instância da sua classe, pode criar um método estático que simplesmente chama o construtor da classe.
Isso produz a saída:
O outro motivo para criar um método estático para construir uma instância é o caso em que você deseja garantir que exista exatamente uma instância da sua classe a qualquer momento; isso é chamado de singleton . Por convenção, essa classe forneceria um método estático chamado
getInstance()
para obter a única instância que é tratada como um "singleton".Isso produz o seguinte.
Armazenando uma referência ao singleton e modificando-o, a próxima chamada para
getInstance()
obtém esse singleton modificado.É tentador usar singletons como uma maneira de começar a criar variáveis globais para seu aplicativo. Em alguns contextos, isso pode ser útil, mas também pode causar problemas. Em particular, deparei-me com um bug interessante ao desenvolver um aplicativo Android, onde as instâncias singleton poderiam se perder. Ir de uma atividade para outra às vezes pode levar a JVM a usar um novo "carregador de classes" que não saberá sobre o singleton que foi armazenado estaticamente por um carregador de classes anterior.
fonte
Embora eu entenda que há muitos que veem a noção de um "construtor estático" como um nome impróprio, não acredito que seja esse o caso. O problema está no processo de construção de ambas as classes e seus objetos de instância . Já foi afirmado em outros threads que a construção da classe é o trabalho do compilador. Mesmo em Java, isso é apenas meia verdade.
O compilador constrói um andaime para cada definição de classe. O andaime contém metadados sobre a classe e quais instâncias devem ter neles no momento da construção. Se uma classe define um campo ao qual é atribuído um valor primitivo constante, esse valor é incluído no andaime pelo compilador. Para qualquer outro tipo de valor atribuído, o compilador gera uma rotina de inicialização que deve ser executada 1 vez, antes da criação da instância da primeira classe, que atualiza o andaime com os valores adequados. Esta atualização não pode ser feita pelo compilador.
Como essa atualização única para o andaime é frequentemente um pré-requisito crítico para o bom funcionamento dos construtores de instância, também é razoável chamá-lo de tipo de construtor. É por isso que nas linguagens OO comuns que suportam o conceito, é chamado de construtor estático. O conceito por trás dos blocos de inicialização estática em Java é pouco mais do que uma mudança semântica para manter a noção de que um programador Java deve ser independente de sistema e de implementação.
fonte
Como outras respostas disseram, você pode escrever métodos estáticos que constroem um objeto. Isso contorna a falta de construtores nomeados em Java (e muitas outras linguagens. O Delphi suporta construtores nomeados). Você pode jogar com os tipos e a ordem dos parâmetros, mas isso pode levar a um código pouco claro e frágil.
Por exemplo, poderíamos inventar um cenário em que seu objeto possa ser construído a partir de uma string XML ou JSON. Você pode escrever métodos como:
Eu usei isso muito ocasionalmente como uma alternativa a um construtor sem parâmetros com métodos de inicialização nomeados:
Você pode considerar um método de criação estático como implementando o padrão do construtor dentro de sua classe.
fonte
Você pode visualizar a seção "estática" como um construtor de nível de classe usado para inicializar propriedades da classe (estática em java). O mesmo que o construtor "normal" é usado para inicializar propriedades no nível da instância.
fonte