En Java, el recolector de basura elimina automáticamente los objetos no utilizados para liberar la memoria. Los desarrolladores no tienen necesidad de marcar los objetos para su eliminación, lo que es propenso a errores y vulnerable a la fuga de memoria. Así que es lógico que Java no tenga destructores disponibles.
En caso de que los objetos contengan sockets abiertos, archivos abiertos o conexiones de base de datos, el recolector de basura no puede recuperar esos recursos. Podemos liberar los recursos en el método close y usar la sintaxis try-finally para llamar al método después antes de Java 7, como las clases de E/S FileInputStream y FileOutputStream. A partir de Java 7, podemos implementar la interfaz AutoCloseable y usar la instrucción try-with-resources para escribir código más corto y limpio. Pero es posible que los usuarios de la API olviden llamar al método close, por lo que el método finalize y la clase Cleaner surgen para actuar como red de seguridad. Pero tenga en cuenta que no son equivalentes al destructor.
No se garantiza que tanto el método finalize como la clase Cleaner se ejecuten rápidamente. Ni siquiera tienen oportunidad de correr antes de que salga el JVM. Aunque podríamos llamar al Sistema.runFinalization para sugerir que JVM ejecute los métodos de finalización de cualquier objeto pendiente de finalización, sigue siendo no determinista. Además, el método finalizar puede causar problemas de rendimiento, bloqueos, etc. Podemos encontrar más información en uno de nuestros artículos: Una guía para el método finalize en Java. A partir de Java 9, la clase Cleaner se agrega para reemplazar el método finalize debido a las desventajas que tiene. Como resultado, tenemos un mejor control sobre el hilo que realiza las acciones de limpieza. Pero la especificación de Java señala el comportamiento de los limpiadores durante el sistema.exit es una implementación específica y Java no ofrece garantías de si se invocarán o no las acciones de limpieza.