Existe um destruidor para Java? Parece que não consigo encontrar nenhuma documentação sobre isso. Se não houver, como posso obter o mesmo efeito?
Para tornar minha pergunta mais específica, estou escrevendo um aplicativo que lida com dados e as especificações dizem que deve haver um botão 'redefinir' que traga o aplicativo de volta ao seu estado original recém-lançado. No entanto, todos os dados precisam estar "ativos", a menos que o aplicativo seja fechado ou o botão de redefinição seja pressionado.
Sendo geralmente um programador de C / C ++, achei que isso seria trivial de implementar. (E, portanto, planejei implementá-lo por último.) Estruturei meu programa de forma que todos os objetos 'redefiníveis' estivessem na mesma classe para que eu pudesse destruir todos os objetos 'ativos' quando um botão de redefinição foi pressionado.
Eu estava pensando se tudo o que fiz foi apenas desreferenciar os dados e aguardar o coletor de lixo coletá-los. Não haveria vazamento de memória se meu usuário digitasse repetidamente os dados e pressionasse o botão de reset? Eu também estava pensando que, como o Java é bastante maduro como linguagem, deve haver uma maneira de impedir que isso aconteça ou resolver isso com graça.
Respostas:
Como Java é uma linguagem de coleta de lixo, não é possível prever quando (ou mesmo se) um objeto será destruído. Portanto, não há equivalente direto de um destruidor.
Existe um método herdado chamado
finalize
, mas é chamado inteiramente a critério do coletor de lixo. Portanto, para as classes que precisam explicitamente arrumar, a convenção é definir um método close e usar finalize apenas para verificação de integridade (ou seja, se close não tiver sido chamado, faça isso agora e registre um erro).Houve uma pergunta que gerou uma discussão aprofundada sobre finalizar recentemente, para fornecer mais profundidade, se necessário ...
fonte
finalize
método foi descontinuado no Java 9. #Veja a instrução try-with-resources . Por exemplo:
Aqui, o recurso que não é mais necessário é liberado no
BufferedReader.close()
método Você pode criar sua própria classe que implementaAutoCloseable
e usa-a de maneira semelhante.Essa declaração é mais limitada do que
finalize
em termos de estrutura de código, mas ao mesmo tempo, torna o código mais simples de entender e manter. Além disso, não há garantia de que umfinalize
método seja chamado durante o tempo de vida do aplicativo.fonte
try
efinally
usados para forçar uma chamada paraobj.finalize()
. E mesmo essa configuração não resolve o problema do OP: destruição de objeto no meio do programa, acionada por um botão "redefinir".Não, não há destruidores aqui. O motivo é que todos os objetos Java são alocados no heap e coletados como lixo. Sem desalocação explícita (ou seja, operador de exclusão do C ++), não há maneira sensata de implementar destruidores reais.
Java suporta finalizadores, mas eles devem ser usados apenas como uma proteção para objetos que mantêm um identificador de recursos nativos, como soquetes, identificadores de arquivo, identificadores de janela etc. Quando o coletor de lixo coleta um objeto sem um finalizador, simplesmente marca a memória. região tão livre e é isso. Quando o objeto tem um finalizador, ele é copiado primeiro para um local temporário (lembre-se, estamos coletando lixo aqui), depois é enfileirado em uma fila de espera para finalização e, em seguida, um encadeamento do Finalizador controla a fila com prioridade muito baixa e executa o finalizador.
Quando o aplicativo sai, a JVM para sem aguardar a finalização dos objetos pendentes, portanto, praticamente não há garantias de que seus finalizadores serão executados.
fonte
Uso de finalize () métodos deve ser evitado. Eles não são um mecanismo confiável para a limpeza de recursos e é possível causar problemas no coletor de lixo abusando deles.
Se você precisar de uma chamada de desalocação em seu objeto, diga para liberar recursos, use uma chamada de método explícita. Essa convenção pode ser vista nas APIs existentes (por exemplo , Closeable , Graphics.dispose () , Widget.dispose () ) e geralmente é chamada via try / finalmente.
As tentativas de usar um objeto descartado devem gerar uma exceção de tempo de execução (consulte IllegalStateException ).
EDITAR:
Geralmente, tudo que você precisa fazer é desreferenciar os objetos - pelo menos, é assim que deve funcionar. Se você estiver preocupado com a coleta de lixo, consulte o Ajuste de coleta de lixo da máquina virtual Java SE 6 HotSpot [tm] (ou o documento equivalente para sua versão da JVM).
fonte
class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
Com o Java 1.7 lançado, agora você tem a opção adicional de usar o
try-with-resources
bloco. Por exemplo,Se você executar esta classe,
c.close()
será executado quando otry
bloco for deixado e antes que os blocoscatch
efinally
sejam executados. Ao contrário do caso dofinalize()
método,close()
é garantido que seja executado. No entanto, não há necessidade de executá-lo explicitamente nafinally
cláusula.fonte
finalize()
execuçãoConcordo plenamente com outras respostas, dizendo para não confiar na execução de finalize.
Além dos blocos try-catch-finalmente, você pode usar o tempo de execução # addShutdownHook (introduzido no Java 1.3) para executar as limpezas finais no seu programa.
Isso não é o mesmo que os destruidores , mas pode-se implementar um gancho de desligamento com objetos ouvintes registrados nos quais métodos de limpeza (fechar conexões persistentes com o banco de dados, remover bloqueios de arquivos etc.) podem ser chamados - coisas que normalmente seriam feitas em destruidores . Novamente - isso não substitui os destruidores, mas em alguns casos, você pode abordar a funcionalidade desejada com isso.
A vantagem disso é ter um comportamento de desconstrução fracamente acoplado ao restante do seu programa.
fonte
Não,
java.lang.Object#finalize
é o mais próximo que você pode chegar.No entanto, quando (e se) é chamado, não é garantido.
Vejo:
java.lang.Runtime#runFinalizersOnExit(boolean)
fonte
Primeiro, observe que, como o Java é coletado pelo lixo, é raro precisar fazer algo sobre a destruição de objetos. Em primeiro lugar, porque você normalmente não possui recursos gerenciados para liberar e, em segundo lugar, porque não pode prever quando ou se isso acontecerá, por isso é inapropriado para coisas que você precisa ocorrer "assim que ninguém mais estiver usando meu objeto "
Você pode ser notificado após a destruição de um objeto usando java.lang.ref.PhantomReference (na verdade, dizer que foi destruído pode ser um pouco impreciso, mas se uma referência fantasma a ele estiver na fila, ela não será mais recuperável, o que geralmente equivale a a mesma coisa). Um uso comum é:
Também existe finalize (), que parece um destruidor, mas não se comporta como um. Geralmente não é uma boa opção.
fonte
o
finalize()
função é o destruidor.No entanto, ele não deve ser usado normalmente porque é invocado após o GC e você não pode dizer quando isso acontecerá (se é que alguma vez).
Além disso, são necessários mais de um GC para desalocar objetos que tenham
finalize()
.Você deve tentar limpar nos locais lógicos do seu código usando as
try{...} finally{...}
instruções!fonte
Eu concordo com a maioria das respostas.
Você não deve depender totalmente de ambos
finalize
ouShutdownHook
finalizar
A JVM não garante quando este
finalize()
método será chamado.finalize()
é chamado apenas uma vez pelo encadeamento do GC. Se um objeto se recuperar do método de finalização,finalize
não será chamado novamente.No seu aplicativo, você pode ter alguns objetos ativos, nos quais a coleta de lixo nunca é chamada.
Qualquer coisa
Exception
lançada pelo método de finalização é ignorada pelo encadeamento do GCSystem.runFinalization(true)
eRuntime.getRuntime().runFinalization(true)
métodos aumentam a probabilidade de chamar ofinalize()
método, mas agora esses dois métodos foram preteridos. Esses métodos são muito perigosos devido à falta de segurança do encadeamento e possível criação de deadlock.shutdownHooks
A máquina virtual Java é encerrada em resposta a dois tipos de eventos:
System.exit
método ) é invocado, ouOs ganchos de desligamento também devem terminar seu trabalho rapidamente. Quando um programa chama sair, a expectativa é que a máquina virtual seja desligada e saia prontamente.
Mas mesmo a documentação da Oracle citou que
Isso ocorre quando a máquina virtual é finalizada externamente, por exemplo, com o
SIGKILL
sinal no Unix ou aTerminateProcess
chamada no Microsoft Windows. A máquina virtual também pode abortar se um método nativo der errado, por exemplo, corrompendo estruturas de dados internas ou tentando acessar memória inexistente. Se a máquina virtual abortar, não será possível garantir se algum gancho de desligamento será executado ou não.Conclusão : use os
try{} catch{} finally{}
blocos adequadamente e libere recursos críticos emfinally(}
bloco. Durante a liberação de recursos emfinally{}
bloco, pegueException
eThrowable
.fonte
Se é apenas com a memória que você está preocupado, não. Apenas confie no GC, ele faz um trabalho decente. Na verdade, vi algo tão eficiente que poderia ser melhor para o desempenho criar montes de objetos minúsculos do que utilizar matrizes grandes em alguns casos.
fonte
Talvez você possa usar um bloco try ... finalmente para finalizar o objeto no fluxo de controle no qual você está usando o objeto. Obviamente, isso não acontece automaticamente, mas a destruição em C ++ também não. Você costuma ver o fechamento de recursos no bloco final.
fonte
Há uma anotação @Cleanup no Lombok que se assemelha principalmente aos destruidores de C ++:
Ao processá-lo (no momento da compilação), o Lombok insere um
try-finally
bloco apropriado para queresource.close()
seja chamado, quando a execução sair do escopo da variável. Você também pode especificar explicitamente outro método para liberar o recurso, por exemploresource.dispose()
:fonte
@Cleanup
O equivalente mais próximo de um destruidor em Java é o método finalize () . A grande diferença para um destruidor tradicional é que você não pode ter certeza de quando será chamado, pois essa é a responsabilidade do coletor de lixo. É altamente recomendável ler atentamente isso antes de usá-lo, pois seus padrões típicos de RAIA para identificadores de arquivos e assim por diante não funcionarão de maneira confiável com finalize ().
fonte
Muitas ótimas respostas aqui, mas há algumas informações adicionais sobre por que você deve evitar o uso de finalize () .
Se a JVM sair devido a
System.exit()
ouRuntime.getRuntime().exit()
, os finalizadores não serão executados por padrão. No Javadoc for Runtime.exit () :Você pode ligar,
System.runFinalization()
mas apenas faz "o melhor esforço para concluir todas as finalizações pendentes" - não uma garantia.Existe um
System.runFinalizersOnExit()
método, mas não o use - é inseguro, obsoleto há muito tempo.fonte
Se você estiver escrevendo um Java Applet, poderá substituir o método Applet "destroy ()". Isto é...
Obviamente, não é o que você deseja, mas pode ser o que as outras pessoas estão procurando.
fonte
Pensando apenas na pergunta original ... que, acho que podemos concluir com todas as outras respostas aprendidas, e também com o Java eficaz eficaz de Bloch , o item 7, "Evite finalizadores", procura a solução para uma pergunta legítima de uma maneira que é inadequado para a linguagem Java ...:
... não seria uma solução óbvia fazer o que o OP realmente deseja ser para manter todos os seus objetos que precisam ser redefinidos em uma espécie de "cercadinho", para o qual todos os outros objetos não redefiníveis têm referências apenas através de algum tipo do objeto acessador ...
E então, quando você precisa "redefinir", desconecta o cercadinho existente e cria um novo: toda a teia de objetos no cercadinho é lançada à deriva, para nunca mais retornar e um dia para ser coletada pelo GC.
Se algum desses objetos for
Closeable
(ou não, mas tiver umclose
método), você poderá colocá-los em umBag
no cercadinho conforme eles forem criados (e possivelmente abertos), e o último ato do acessador antes de cortá-lo seria: através de todo oCloseables
fechamento deles ...?O código provavelmente seria algo como isto:
closeCloseables
provavelmente seria um método de bloqueio, provavelmente envolvendo uma trava (por exemploCountdownLatch
), para lidar com (e esperar conforme apropriado) qualquerRunnables
/Callables
em qualquer encadeamento específico para oPlaypen
final, conforme apropriado, em particular no encadeamento JavaFX.fonte
Embora tenha havido avanços consideráveis na tecnologia GC do Java, você ainda precisa estar atento às suas referências. Muitos casos de padrões de referência aparentemente triviais que são realmente ninhos de ratos sob o capô vêm à mente.
Na sua postagem, não parece que você está tentando implementar um método de redefinição para fins de reutilização de objetos (verdadeiro?). Seus objetos estão mantendo outro tipo de recurso que precisa ser limpo (por exemplo, fluxos que devem ser fechados, objetos agrupados ou emprestados que devem ser devolvidos)? Se a única coisa com a qual você está preocupado é com a desalocação de memória, eu reconsideraria minha estrutura de objetos e tentaria verificar se meus objetos são estruturas independentes que serão limpas no momento da GC.
fonte
Não existe exatamente uma classe destruidora em Java, classe destruída em java automaticamente pelo coletor de lixo. mas você pode fazer isso usando abaixo de um, mas não é exatamente a mesma coisa:
finalizar()
Houve uma pergunta que gerou uma discussão aprofundada sobre finalizar , para que você tenha mais profundidade, se necessário ...
fonte
Nenhum Java não possui destruidores. O principal motivo por trás dele em Java é o Garbage Collectors, que sempre trabalha passivamente em segundo plano e todos os objetos são criados na memória heap, que é o local em que o GC trabalha. É necessário chamar explicitamente a função de exclusão, pois não existe um coletor de lixo como esse.
fonte
Eu costumava lidar principalmente com C ++ e foi isso que me levou à busca de um destruidor também. Estou usando muito JAVA agora. O que eu fiz e pode não ser o melhor para todos, mas implementei meu próprio destruidor, redefinindo todos os valores para 0 ou para o padrão por meio de uma função.
Exemplo:
Idealmente, isso não funcionará para todas as situações, mas onde existem variáveis globais, ele funcionará desde que você não tenha uma tonelada delas.
Eu sei que não sou o melhor programador Java, mas parece estar funcionando para mim.
fonte