¿Hay un destructor para Java? Parece que no puedo encontrar ninguna documentación sobre esto. Si no lo hay, ¿cómo puedo lograr el mismo efecto?
Para hacer mi pregunta más específica, estoy escribiendo una aplicación que trata con datos y la especificación dice que debería haber un botón 'restablecer' que devuelva la aplicación a su estado original recién lanzado. Sin embargo, todos los datos tienen que estar 'en vivo' a menos que la aplicación se cierre o se presione el botón de reinicio.
Siendo generalmente un programador de C / C ++, pensé que esto sería trivial de implementar. (Y, por lo tanto, planeé implementarlo en último lugar). Estructuré mi programa de manera que todos los objetos 'reiniciables' estarían en la misma clase para que pueda destruir todos los objetos 'vivos' cuando se presiona un botón de reinicio.
Estaba pensando si todo lo que hice fue simplemente desreferenciar los datos y esperar a que el recolector de basura los recolecte, ¿no habría una pérdida de memoria si mi usuario ingresara datos repetidamente y presiona el botón de reinicio? También estaba pensando que, dado que Java es bastante maduro como lenguaje, debería haber una manera de evitar que esto suceda o abordarlo con gracia.
Respuestas:
Debido a que Java es un lenguaje recolectado de basura, no puede predecir cuándo (o incluso si) se destruirá un objeto. Por lo tanto, no hay un equivalente directo de un destructor.
Hay un método heredado llamado
finalize
, pero esto se llama completamente a discreción del recolector de basura. Entonces, para las clases que necesitan un orden explícito, la convención es definir un método de cierre y usar finalizar solo para la verificación de la cordura (es decir, si no se ha llamado a cerrar, hágalo ahora y registre un error).Hubo una pregunta que generó una discusión en profundidad de finalizar recientemente, por lo que debería proporcionar más profundidad si es necesario ...
fuente
finalize
método ha quedado en desuso en Java 9.Eche un vistazo a la declaración de prueba con recursos . Por ejemplo:
Aquí el recurso que ya no se necesita se libera en el
BufferedReader.close()
método. Puede crear su propia clase que implementeAutoCloseable
y usarla de manera similar.Esta declaración es más limitada que
finalize
en términos de estructuración del código, pero al mismo tiempo hace que el código sea más simple de entender y mantener. Además, no hay garantía de quefinalize
se llame a un método durante el tiempo de vida de la aplicación.fuente
try
yfinally
se use para forzar una llamadaobj.finalize()
. E incluso esta configuración no resuelve el problema que plantea OP: destrucción de objetos a mitad del programa desencadenada por un botón de "reinicio".No, no hay destructores aquí. La razón es que todos los objetos de Java se asignan en montón y se recolecta basura. Sin la desasignación explícita (es decir, el operador de eliminación de C ++) no hay una forma sensata de implementar destructores reales.
Java admite finalizadores, pero están destinados a usarse solo como protección para los objetos que contienen un identificador de recursos nativos como sockets, identificadores de archivos, identificadores de ventanas, etc. Cuando el recolector de basura recolecta un objeto sin un finalizador, simplemente marca la memoria región como libre y eso es todo. Cuando el objeto tiene un finalizador, primero se copia en una ubicación temporal (recuerde, aquí estamos recolectando basura), luego se coloca en una cola de espera para ser finalizado y luego un hilo Finalizador sondea la cola con muy baja prioridad y ejecuta el finalizador.
Cuando se cierra la aplicación, la JVM se detiene sin esperar a que se finalicen los objetos pendientes, por lo que prácticamente no hay garantías de que sus finalizadores se ejecuten.
fuente
Se debe evitar el uso de los métodos finalize () . No son un mecanismo confiable para la limpieza de recursos y es posible causar problemas en el recolector de basura al abusar de ellos.
Si necesita una llamada de desasignación en su objeto, por ejemplo, para liberar recursos, use una llamada de método explícito. Esta convención se puede ver en las API existentes (por ejemplo, que se puede cerrar , Graphics.dispose () , Widget.dispose () ) y generalmente se llama a través de try / finalmente.
Los intentos de usar un objeto desechado deberían generar una excepción de tiempo de ejecución (consulte IllegalStateException ).
EDITAR:
En general, todo lo que necesita hacer es desreferenciar los objetos; al menos, esta es la forma en que se supone que funciona. Si le preocupa la recolección de basura, consulte Java SE 6 HotSpot [tm] Ajuste de recolección de basura de máquina virtual (o el documento equivalente para su versión JVM).
fuente
class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
Con Java 1.7 lanzado, ahora tiene la opción adicional de usar el
try-with-resources
bloque. Por ejemplo,Si ejecuta esta clase,
c.close()
se ejecutará cuandotry
se deje el bloque y antes de que se ejecuten los bloquescatch
yfinally
. A diferencia del caso delfinalize()
método,close()
se garantiza su ejecución. Sin embargo, no hay necesidad de ejecutarlo explícitamente en lafinally
cláusula.fuente
finalize()
ejecuciónEstoy totalmente de acuerdo con otras respuestas, diciendo que no confíe en la ejecución de finalizar.
Además de los bloques try-catch-finally, puede usar Runtime # addShutdownHook (introducido en Java 1.3) para realizar las limpiezas finales en su programa.
Eso no es lo mismo que los destructores , pero uno puede implementar un gancho de cierre con objetos de escucha registrados en los que se pueden invocar métodos de limpieza (cerrar conexiones de bases de datos persistentes, eliminar bloqueos de archivos, etc.), cosas que normalmente se harían en destructores . Nuevamente, esto no reemplaza a los destructores, pero en algunos casos, puede acercarse a la funcionalidad deseada con esto.
La ventaja de esto es tener un comportamiento de deconstrucción ligeramente acoplado del resto de su programa.
fuente
No,
java.lang.Object#finalize
es lo más cerca que puedes estar.Sin embargo, cuando (y si) se llama, no está garantizado.
Ver:
java.lang.Runtime#runFinalizersOnExit(boolean)
fuente
Primero, tenga en cuenta que dado que Java se recolecta basura, es raro que necesite hacer algo para destruir objetos. En primer lugar, porque normalmente no tiene ningún recurso administrado para liberar, y en segundo lugar, porque no puede predecir cuándo o si sucederá, por lo que no es apropiado para las cosas que necesita que ocurran "tan pronto como ya nadie use mi objeto. ".
Puede recibir una notificación después de que un objeto ha sido destruido usando java.lang.ref.PhantomReference (en realidad, decir que ha sido destruido puede ser ligeramente inexacto, pero si una referencia fantasma está en cola, entonces ya no es recuperable, lo que generalmente equivale a la misma cosa). Un uso común es:
También hay finalize (), que parece un destructor pero no se comporta como tal. Por lo general, no es una buena opción.
fuente
los
finalize()
función es el destructor.Sin embargo, no debe usarse normalmente porque se invoca después del GC y no se puede saber cuándo sucederá (si es que lo hace).
Además, se necesita más de un GC para desasignar objetos que tienen
finalize()
.¡Debería intentar limpiar en los lugares lógicos de su código usando las
try{...} finally{...}
declaraciones!fuente
Estoy de acuerdo con la mayoría de las respuestas.
No debe depender completamente de ninguno
finalize
oShutdownHook
finalizar
La JVM no garantiza cuándo
finalize()
se invocará este método.finalize()
se llama solo una vez por el hilo GC. Si un objeto se revive del método de finalización,finalize
no se volverá a llamar.En su aplicación, puede tener algunos objetos vivos, en los que nunca se invoca la recolección de basura.
El
Exception
subproceso GC ignora todo lo que arroje el método de finalización.System.runFinalization(true)
y losRuntime.getRuntime().runFinalization(true)
métodos aumentan la probabilidad de invocar elfinalize()
método, pero ahora estos dos métodos han quedado en desuso. Estos métodos son muy peligrosos debido a la falta de seguridad del hilo y la posible creación de puntos muertos.shutdownHooks
La máquina virtual Java se apaga en respuesta a dos tipos de eventos:
System.exit
se invoca el método de salida (equivalente ), oLos ganchos de cierre también deberían terminar su trabajo rápidamente. Cuando un programa invoca la salida, se espera que la máquina virtual se apague y salga rápidamente.
Pero incluso la documentación de Oracle citaba que
Esto ocurre cuando la máquina virtual se termina externamente, por ejemplo, con la
SIGKILL
señal en Unix o laTerminateProcess
llamada en Microsoft Windows. La máquina virtual también puede abortar si un método nativo falla, por ejemplo, corrompiendo las estructuras de datos internos o intentando acceder a la memoria inexistente. Si la máquina virtual aborta, no se puede garantizar si se ejecutarán o no ganchos de apagado.Conclusión : use los
try{} catch{} finally{}
bloques adecuadamente y libere recursos críticos enfinally(}
bloque. Durante la liberación de recursos enfinally{}
bloque, capturaException
yThrowable
.fuente
Si solo te preocupa la memoria, no lo hagas. Solo confíe en el GC, hace un trabajo decente. De hecho, vi algo acerca de que es tan eficiente que podría ser mejor para el rendimiento crear montones de objetos pequeños que utilizar matrices grandes en algunos casos.
fuente
Quizás pueda usar un intento ... finalmente bloquee para finalizar el objeto en el flujo de control en el que está usando el objeto. Por supuesto, no sucede automáticamente, pero tampoco lo hace la destrucción en C ++. A menudo ve el cierre de recursos en el bloque finalmente.
fuente
Hay una anotación @Cleanup en Lombok que se parece principalmente a los destructores de C ++:
Al procesarlo (en el momento de la compilación), Lombok inserta el
try-finally
bloque apropiado para queresource.close()
se invoque, cuando la ejecución abandona el alcance de la variable. También puede especificar explícitamente otro método para liberar el recurso, por ejemploresource.dispose()
:fuente
@Cleanup
El equivalente más cercano a un destructor en Java es el método finalize () . La gran diferencia con un destructor tradicional es que no puedes estar seguro de cuándo será llamado, ya que es responsabilidad del recolector de basura. Recomiendo leer detenidamente esto antes de usarlo, ya que sus patrones RAIA típicos para identificadores de archivos, etc., no funcionarán de manera confiable con finalize ().
fuente
Aquí hay muchas respuestas excelentes, pero hay información adicional sobre por qué debería evitar usar finalize () .
Si la JVM se cierra debido a
System.exit()
oRuntime.getRuntime().exit()
, los finalizadores no se ejecutarán de manera predeterminada. Desde Javadoc para Runtime.exit () :Puede llamar
System.runFinalization()
pero solo hace "un gran esfuerzo para completar todas las finalizaciones pendientes", no es una garantía.Hay un
System.runFinalizersOnExit()
método, pero no lo use, es inseguro, está en desuso hace mucho tiempo.fuente
Si está escribiendo un Applet Java, puede anular el método "destroy ()" del Applet. Está...
Obviamente no es lo que quieres, pero podría ser lo que otras personas están buscando.
fuente
Simplemente pensando en la pregunta original ... que, creo que podemos concluir de todas las otras respuestas aprendidas, y también de Java Efectivo esencial de Bloch , elemento 7, "Evitar finalizadores", busca la solución a una pregunta legítima de una manera que es inapropiado para el lenguaje Java ...:
... no sería una solución bastante obvia para hacer lo que realmente quiere el OP para mantener todos sus objetos que necesitan ser reiniciados en una especie de "corralito", al que todos los demás objetos no reiniciables tienen referencias solo a través de algún tipo del objeto de acceso ...
Y luego, cuando necesita "reiniciar", desconecta el corralito existente y crea uno nuevo: toda la red de objetos en el corralito se arroja a la deriva, nunca regresará, y un día será recogido por el GC.
Si alguno de estos objetos está
Closeable
(o no, pero tiene unclose
método), puede colocarlos en unBag
corralito a medida que se crean (y posiblemente se abren), y el último acto del descriptor de acceso antes de cortar el corralito sería ir a través de todo elCloseables
cierre de ellos ...?El código probablemente se vería así:
closeCloseables
probablemente sería un método de bloqueo, probablemente con un pestillo (pCountdownLatch
. ej. ), para tratar (y esperar según corresponda) cualquieraRunnables
/Callables
en cualquier subproceso específico paraPlaypen
que finalice según corresponda, en particular en el subproceso JavaFX.fuente
Aunque ha habido avances considerables en la tecnología GC de Java, aún debe tener en cuenta sus referencias. Me vienen a la mente numerosos casos de patrones de referencia aparentemente triviales que en realidad son nidos de ratas debajo del capó.
Desde su publicación, no parece que esté tratando de implementar un método de reinicio con el propósito de reutilizar objetos (¿verdad?). ¿Sus objetos contienen algún otro tipo de recursos que deben limpiarse (es decir, flujos que deben cerrarse, cualquier objeto agrupado o prestado que deba devolverse)? Si lo único que le preocupa es el acuerdo de memoria, entonces reconsideraría la estructura de mi objeto e intentaría verificar que mis objetos son estructuras autónomas que se limpiarán en el momento de la GC.
fuente
No existe una clase de destructor exactamente en Java, clase destruida en Java automáticamente por el recolector de basura. pero puedes hacerlo usando el siguiente, pero no es exactamente lo mismo:
finalizar()
Hubo una pregunta que generó una discusión profunda sobre finalizar , por lo que debería obtener más profundidad si es necesario ...
fuente
Ningún Java no tiene ningún destructor. La razón principal detrás de esto en Java son los recolectores de basura que siempre funcionan pasivamente en segundo plano y todos los objetos están hechos en la memoria de almacenamiento dinámico, ese es el lugar donde funciona GC. En C ++ allí tiene que llamar explícitamente a la función de eliminación, ya que no existe un recolector de basura similar.
fuente
Solía tratar principalmente con C ++ y eso es lo que también me llevó a buscar un destructor. Estoy usando mucho JAVA ahora. Lo que hice, y puede que no sea el mejor caso para todos, pero implementé mi propio destructor restableciendo todos los valores a 0 o por defecto a través de una función.
Ejemplo:
Idealmente, esto no funcionará para todas las situaciones, pero donde haya variables globales funcionará siempre que no tenga un montón de ellas.
Sé que no soy el mejor programador de Java, pero parece estar funcionando para mí.
fuente