De acordo com o Effective Java de Joshua Bloch (Segunda Edição), há dois cenários em que finalize()
é útil:
Uma é agir como uma "rede de segurança", caso o proprietário de um objeto esqueça de chamar seu método explícito de terminação. Embora não haja garantia de que o finalizador seja chamado imediatamente, pode ser melhor liberar o recurso mais tarde do que nunca, naqueles casos (provavelmente raros) em que o cliente falha em chamar o método de encerramento explícito. Mas o finalizador deve registrar um aviso se descobrir que o recurso não foi finalizado
Um segundo uso legítimo de finalizadores diz respeito a objetos com pares nativos. Um par nativo é um objeto nativo ao qual um objeto normal delega por métodos nativos. Como um par nativo não é um objeto normal, o coletor de lixo não o conhece e não pode recuperá-lo quando seu par Java é recuperado. Um finalizador é um veículo apropriado para executar esta tarefa, assumindo que o par nativo não possua recursos críticos. Se o par nativo reter recursos que devem ser finalizados imediatamente, a classe deverá ter um método de finalização explícito, conforme descrito acima. O método de encerramento deve fazer o que for necessário para liberar o recurso crítico.
Para uma leitura mais detalhada, consulte o Item 7, página 27.
Os finalizadores são importantes para o gerenciamento de recursos nativos. Por exemplo, seu objeto pode precisar alocar um WidgetHandle do sistema operacional usando uma API não Java. Se você não liberar esse WidgetHandle quando seu objeto estiver no GC, estará vazando WidgetHandles.
O importante é que os casos "finalizador nunca são chamados" sejam divididos de maneira simples:
Nos três casos, você não possui um vazamento nativo (devido ao fato de seu programa não estar mais sendo executado) ou já possui um vazamento não nativo (se continuar alocando objetos gerenciados sem que eles sejam GC'd).
O aviso "não confie no finalizador que está sendo chamado" é realmente sobre não usar finalizadores para a lógica do programa. Por exemplo, você não deseja acompanhar quantos objetos existem em todas as instâncias do seu programa, incrementando um contador em um arquivo em algum lugar durante a construção e diminuindo-o em um finalizador - porque não há garantia de que seus objetos serão Ao finalizar, esse contador de arquivos provavelmente nunca voltará a 0. Esse é realmente um caso especial do princípio mais geral de que você não deve depender do término normal do programa (falhas de energia, etc.).
Para o gerenciamento de recursos nativos, os casos em que o finalizador não é executado correspondem aos casos em que você não se importa se não for executado.
fonte
close()
nunca é chamado antes que se torne inacessível)O objetivo deste método é explicado na documentação da API da seguinte maneira:
Se você também estiver interessado em razões pelas quais os designers de linguagem optaram por "o objeto é irrevogavelmente descartado" ( coleta de lixo ) da maneira que está além do controle do programador de aplicativos ("nunca devemos confiar"), isso foi explicado em uma resposta a pergunta :
A citação acima, por sua vez, foi tirada da documentação oficial sobre os objetivos do projeto Java , ou seja, pode ser considerada uma referência autorizada, explicando por que os designers da linguagem Java decidiram dessa maneira.
Para uma discussão mais detalhada e independente do idioma sobre essa preferência, consulte a seção 9.6 da OOSC . Gerenciamento automático de memória (na verdade, não apenas esta seção, mas todo o capítulo 9 vale muito a pena ler se você estiver interessado em coisas desse tipo). Esta seção é aberta com uma declaração inequívoca:
fonte
Os finalizadores existem porque se espera que eles sejam um meio eficaz de garantir que as coisas sejam limpas (embora na prática não sejam) e porque quando foram inventados, melhores meios de garantir a limpeza (como referências fantasmas e tentativa de -resources) ainda não existia. Em retrospectiva, o Java provavelmente seria melhor se o esforço despendido na implementação de sua instalação "finalize" tivesse sido gasto em outros meios de limpeza, mas isso não ficou claro durante o período em que o Java estava sendo desenvolvido inicialmente.
fonte
CAVEAT: Posso estar desatualizado, mas esse é o meu entendimento a alguns anos atrás:
Em geral, não há garantia de quando um finalizador é executado - ou mesmo que seja executado, embora algumas JVMs permitam solicitar um GC e uma finalização completos antes da saída do programa (o que, é claro, significa que o programa leva mais tempo sair e que não é o modo padrão de operação).
E sabia-se que alguns GCs atrasavam explicitamente ou evitavam objetos de GC que tinham finalizadores, na esperança de que isso produzisse melhor desempenho nos benchmarks.
Infelizmente, esses comportamentos conflitam com os motivos originais pelos quais os finalizadores foram recomendados e, em vez disso, incentivaram o uso de métodos de desligamento chamados explicitamente.
Se você tem um objeto que realmente precisa ser limpo antes de ser descartado e se não pode confiar nos usuários, um finalizador ainda pode ser considerado. Mas, em geral, existem boas razões para que você não as veja com tanta frequência no código Java moderno como em alguns dos primeiros exemplos.
fonte
O Google Java Style Guide tem alguns sábios conselhos sobre o assunto:
fonte
PhantomReference
e emReferenceQueue
vez disso.PhantomReference
é uma solução melhor. Os finalizadores são uma verruga que sobrou dos primeiros dias de Java, eObject.clone()
tipos like e raw, são parte da linguagem mais esquecida.A Especificação de Linguagem Java (Java SE 7) declara:
fonte