definicion - usar codigo html en java




¿Hay un destructor para Java? (14)

Aunque ha habido avances considerables en la tecnología GC de Java, aún debe tener en cuenta sus referencias. Se me ocurren numerosos casos de patrones de referencia aparentemente triviales que en realidad son nidos de ratas debajo de la capucha.

Desde su publicación, no parece que esté intentando implementar un método de restablecimiento con el fin de reutilizar objetos (¿verdad?). ¿Sus objetos tienen algún otro tipo de recursos que deben limpiarse (es decir, las corrientes que deben cerrarse, los objetos agrupados o prestados que deben devolverse)? Si lo único que le preocupa es el desajuste de memoria, entonces reconsideraría mi estructura de objetos e intentaría verificar que mis objetos son estructuras independientes que se limpiarán en el momento de GC.

¿Hay un destructor para Java? Parece que no puedo encontrar ninguna documentación sobre esto. Si no hay, ¿cómo puedo lograr el mismo efecto?

Para que mi pregunta sea 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 de "reinicio" que devuelva la aplicación a su estado original recién lanzado. Sin embargo, todos los datos deben estar 'en vivo' a menos que la aplicación se cierre o se presione el botón de reinicio.

Siendo usualmente un programador de C / C ++, pensé que esto sería trivial de implementar. (Y, por lo tanto, planifiqué implementarlo en último lugar). Estructuré mi programa de tal manera que todos los objetos "reiniciables" estuvieran en la misma clase, de modo que pueda destruir todos los objetos "vivos" cuando se presiona un botón de reinicio.

Estaba pensando que si todo lo que hacía era solo para eliminar la referencia a los datos y esperar a que el recolector de basura los recolectara, ¿no habría una pérdida de memoria si mi usuario ingresara los datos repetidamente y presionara el botón de reinicio? También pensaba que, como Java es bastante maduro como lenguaje, debería haber una manera de evitar que esto suceda o enfrentarlo con gracia.


Con Java 1.7 lanzado, ahora tiene la opción adicional de usar el bloque try-with-resources . Por ejemplo,

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing..."); 
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying..."); 
            throw new Exception("throwing..."); 
        }
        catch (Exception e) {
            System.out.println("catching..."); 
        }
        finally {
            System.out.println("finalizing..."); 
        } 
    }
}

Si ejecuta esta clase, c.close() se ejecutará cuando se deje el bloque try , y antes de que se ejecuten los bloques catch y finally . A diferencia de en el caso del método finalize() , se garantiza que se ejecute close() . Sin embargo, no hay necesidad de ejecutarlo explícitamente en la cláusula finally .


Debido a que Java es un lenguaje de recolección 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.

Existe un método heredado llamado finalize , pero esto se llama completamente a discreción del recolector de basura. Por lo tanto, para las clases que necesitan una ordenación explícita, la convención es definir un método de cierre y usar la finalización solo para verificar la validez (es decir, si no se ha llamado a cerrar, hágalo ahora y registre un error).

Hubo una pregunta que generó una discusión profunda sobre la finalización recientemente, por lo que debería proporcionar más profundidad si es necesario ...


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 se llamará, ya que eso es responsabilidad del recolector de basura. Recomiendo encarecidamente leer detenidamente esto antes de usarlo, ya que sus patrones RAIA típicos para los manejadores de archivos, etc., no funcionarán de manera confiable con finalize ().


Estoy completamente de acuerdo con otras respuestas, diciendo que no confíe en la ejecución de finalize.

Además de los bloques try-catch-finally, puede usar Runtime#addShutdownHook (introducido en Java 1.6) para realizar limpiezas finales en su programa.

Eso no es lo mismo que lo son 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 las conexiones persistentes de la base de datos, eliminar bloqueos de archivos, etc.), cosas que normalmente se harían en destructores Nuevamente, esto no reemplaza a los constructores, pero en algunos casos, puede acercarse a la funcionalidad deseada con esto.

La ventaja de esto es que el comportamiento de deconstrucción se ha acoplado libremente con el resto de su programa.


Estoy de acuerdo con la mayoría de las respuestas.

No debes depender completamente de finalize o ShutdownHook

finalize

  1. JVM no garantiza cuándo se invocará este método finalize() .

  2. finalize() es llamado una sola vez por el subproceso GC si el objeto se revive a sí mismo a partir del método de finalización que el de finalización, no se volverá a llamar.

  3. En su aplicación, puede tener algunos objetos vivos, en los que nunca se invoca la recolección de basura.

  4. Cualquier excepción es lanzada por el método de finalización es ignorada por el hilo GC

  5. System.runFinalization(true) y Runtime.getRuntime().runFinalization(true) aumentan la probabilidad de invocar el método finalize() , pero ahora estos dos métodos han quedado en desuso. Estos métodos son muy peligrosos debido a la falta de seguridad de subprocesos y la posible creación de interbloqueo.

shutdownHooks

public void addShutdownHook(Thread hook)

Registra un nuevo gancho de apagado de máquina virtual.

La máquina virtual de Java se apaga en respuesta a dos tipos de eventos:

  1. El programa sale normalmente, cuando sale el último hilo no daemon o cuando se invoca el método exit (equivalentemente, System.exit), o
  2. La máquina virtual se termina en respuesta a una interrupción del usuario, como escribir ^ C, o un evento de todo el sistema, como el cierre de sesión del usuario o el cierre del sistema.
  3. Un gancho de apagado es simplemente un hilo inicializado pero no iniciado. Cuando la máquina virtual comience su secuencia de apagado, iniciará todos los enlaces de apagado registrados en un orden no especificado y los dejará funcionar simultáneamente. Cuando todos los ganchos hayan finalizado, se ejecutarán todos los finalizadores no invocados si se ha habilitado la finalización en la salida.
  4. Finalmente, la máquina virtual se detendrá. Tenga en cuenta que los subprocesos del daemon continuarán ejecutándose durante la secuencia de cierre, al igual que los subprocesos no daemon si el cierre se inició invocando el método de salida.
  5. Los ganchos de cierre también deben terminar su trabajo rápidamente. Cuando un programa invoca exit, la expectativa es que la máquina virtual se apague y salga rápidamente.

    Pero incluso la documentación de Oracle citó que

En raras ocasiones, la máquina virtual puede abortar, es decir, dejar de funcionar sin apagarse limpiamente

Esto ocurre cuando la máquina virtual se termina externamente, por ejemplo con la señal SIGKILL en Unix o la llamada TerminateProcess en Microsoft Windows. La máquina virtual también puede abortar si un método nativo falla, por ejemplo, al corromper las estructuras de datos internas o al intentar acceder a una memoria inexistente. Si la máquina virtual se interrumpe, no se puede garantizar si se ejecutarán o no los enganches de apagado.

Conclusión : use los bloques try{} catch{} finally{} adecuadamente y libere los recursos críticos en el bloque finally(} . Durante la liberación de los recursos en el bloque finally{} , capture Exception y Throwable .


La función finalize() es el destructor.

Sin embargo, no debe usarse normalmente porque se invoca después del GC y no se puede saber cuándo ocurrirá (si es que ocurre).

Además, se necesita más de un GC para desasignar objetos que tienen finalize() .

Debe intentar limpiar los lugares lógicos en su código usando las declaraciones try{...} finally{...} !


Lo siento si esto se aleja del tema principal, pero la documentación de java.util.Timer (SE6) dice:

"Después de que la última referencia en vivo a un objeto del temporizador desaparece y todas las tareas pendientes se han completado, el hilo de ejecución de la tarea del temporizador termina con gracia (y queda sujeto a la recolección de basura). Sin embargo, esto puede tomar un tiempo arbitrario. Por defecto, el el subproceso de ejecución de la tarea no se ejecuta como un subproceso de demonio, por lo que es capaz de evitar que una aplicación finalice. Si el llamante desea terminar el subproceso de ejecución de la tarea del temporizador rápidamente, el invocador debe invocar el método de cancelación del temporizador ... "

Me gustaría cancelar cuando la clase que posee el temporizador pierda su última referencia (o immeditalesky antes). Aquí un destructor confiable podría hacer eso por mí. Los comentarios anteriores indican que finalmente es una mala elección, pero ¿existe una solución elegante? Ese negocio de "... capaz de evitar que una aplicación termine ..." no es atractivo.



No, no hay destructores aquí. La razón es que todos los objetos Java se asignan en montón y se recolectan 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 los finalizadores, pero están diseñados para usarse solo como salvaguarda de los objetos que tienen un identificador para recursos nativos como sockets, identificadores de archivo, identificadores de ventana, etc. Cuando el recolector de basura recopila un objeto sin un finalizador, simplemente marca la memoria. Región tan libre y eso es todo. Cuando el objeto tiene un finalizador, primero se copia en una ubicación temporal (recuerde, estamos recolectando basura aquí), luego se pone en cola en una cola de espera para ser finalizado y luego un subproceso del 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.


Quizás pueda usar un bloque try ... finalmente para finalizar el objeto en el flujo de control en el que está usando el objeto. Por supuesto que no sucede automáticamente, pero tampoco la destrucción en C ++. A menudo se ve el cierre de recursos en el bloque finalmente.


Si está escribiendo un applet de Java, puede anular el método "destroy ()" del applet. Es...

 * Called by the browser or applet viewer to inform
 * this applet that it is being reclaimed and that it should destroy
 * any resources that it has allocated. The stop() method
 * will always be called before destroy().

Obviamente no es lo que quieres, pero podría ser lo que otras personas están buscando.


Si usa Java 7, eche un vistazo a la declaración try-with-resources . Por ejemplo:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

Aquí el recurso que ya no es necesario se libera en el método BufferedReader.close() . Puede crear su propia clase que implemente AutoCloseable y usarla de una manera similar.

Esta declaración es más limitada que la finalize en términos de estructuración de código, pero al mismo tiempo hace que el código sea más fácil de entender y mantener. Además, no hay garantía de que se llame a un método de finalize durante el tiempo de vida de la aplicación.


Solía ​​tratar principalmente con C ++ y eso es lo que me llevó también a la búsqueda de un destructor. Estoy usando mucho Java ahora. Lo que hice, y puede que no sea el mejor de los casos, pero implementé mi propio destructor al restablecer todos los valores a 0 o no por defecto a través de una función.

Ejemplo:

public myDestructor() {

variableA = 0; //INT
variableB = 0.0; //DOUBLE & FLOAT
variableC = "NO NAME ENTERED"; //TEXT & STRING
variableD = false; //BOOL

}

Idealmente, esto no funcionará para todas las situaciones, pero donde hay variables globales funcionará siempre y cuando no tengas un montón de ellas.

Sé que no soy el mejor programador de Java, pero parece estar funcionando para mí.





destructor