Existe-t-il un destructeur pour Java? Je ne semble pas pouvoir trouver de documentation à ce sujet. S'il n'y en a pas, comment puis-je obtenir le même effet?
Pour rendre ma question plus précise, j'écris une application qui traite des données et la spécification dit qu'il devrait y avoir un bouton 'reset' qui ramène l'application à son état d'origine qui vient d'être lancé. Cependant, toutes les données doivent être «en direct» sauf si l'application est fermée ou si le bouton de réinitialisation est enfoncé.
Étant habituellement un programmeur C / C ++, j'ai pensé que ce serait trivial à implémenter. (Et donc j'ai prévu de l'implémenter en dernier.) J'ai structuré mon programme de telle sorte que tous les objets `` pouvant être réinitialisés '' soient dans la même classe afin que je puisse simplement détruire tous les objets `` vivants '' lorsqu'un bouton de réinitialisation est enfoncé.
Je pensais que si je ne faisais que déréférencer les données et attendre que le garbage collector les recueille, n'y aurait-il pas une fuite de mémoire si mon utilisateur saisissait des données à plusieurs reprises et appuyait sur le bouton de réinitialisation? Je pensais également que Java étant assez mature en tant que langage, il devrait y avoir un moyen d'empêcher cela de se produire ou de le résoudre avec élégance.
Réponses:
Parce que Java est un langage récupéré, vous ne pouvez pas prédire quand (ou même si) un objet sera détruit. Il n'y a donc pas d'équivalent direct d'un destructeur.
Il existe une méthode héritée appelée
finalize
, mais elle est appelée entièrement à la discrétion du garbage collector. Donc, pour les classes qui ont besoin de ranger explicitement, la convention est de définir une méthode close et d'utiliser finalize uniquement pour la vérification de la validité (c'est-à-dire si close n'a pas été appelé, faites-le maintenant et enregistrez une erreur).Il y avait une question qui a engendré une discussion approfondie sur la finalisation récemment, donc cela devrait fournir plus de profondeur si nécessaire ...
la source
finalize
méthode est déconseillée dans Java 9.Jetez un œil à l' instruction try-with-resources . Par exemple:
Ici, la ressource qui n'est plus nécessaire est libérée dans la
BufferedReader.close()
méthode. Vous pouvez créer votre propre classe qui implémenteAutoCloseable
et l'utiliser de manière similaire.Cette déclaration est plus limitée qu'en
finalize
termes de structuration de code, mais en même temps, elle rend le code plus simple à comprendre et à maintenir. En outre, rien ne garantit qu'unefinalize
méthode est appelée du tout pendant la durée de vie de l'application.la source
try
et que lefinally
soit utilisé pour forcer un appel àobj.finalize()
. Et même cette configuration ne résout pas le problème posé par OP: destruction en cours de programme déclenchée par un bouton "reset".Non, pas de destructeurs ici. La raison en est que tous les objets Java sont alloués en tas et récupérés. Sans désallocation explicite (c'est-à-dire l'opérateur de suppression de C ++), il n'y a aucun moyen raisonnable d'implémenter de vrais destructeurs.
Java prend en charge les finaliseurs, mais ils sont destinés à être utilisés uniquement comme protection pour les objets contenant une poignée vers des ressources natives comme les sockets, les poignées de fichier, les poignées de fenêtre, etc. Lorsque le garbage collector collecte un objet sans finaliseur, il marque simplement la mémoire région aussi libre et c'est tout. Lorsque l'objet a un finaliseur, il est d'abord copié dans un emplacement temporaire (rappelez-vous, nous collectons des ordures ici), puis il est mis en file d'attente dans une file d'attente en attente de finalisation, puis un thread de finaliseur interroge la file d'attente avec une priorité très faible et exécute le finaliseur.
Lorsque l'application se ferme, la JVM s'arrête sans attendre la finalisation des objets en attente, il n'y a donc pratiquement aucune garantie que vos finaliseurs s'exécuteront jamais.
la source
L'utilisation des méthodes finalize () doit être évitée. Ils ne sont pas un mécanisme fiable de nettoyage des ressources et il est possible de provoquer des problèmes dans le garbage collector en les abusant.
Si vous avez besoin d'un appel de désallocation dans votre objet, par exemple pour libérer des ressources, utilisez un appel de méthode explicite. Cette convention est visible dans les API existantes (par exemple Closeable , Graphics.dispose () , Widget.dispose () ) et est généralement appelée via try / finally.
Les tentatives d'utilisation d'un objet supprimé doivent lever une exception d'exécution (voir IllegalStateException ).
ÉDITER:
En général, tout ce que vous devez faire est de déréférencer les objets - du moins, c'est ainsi que cela est censé fonctionner. Si vous êtes inquiet au sujet du garbage collection, consultez Java SE 6 HotSpot [tm] Virtual Machine Garbage Collection Tuning (ou le document équivalent pour votre version JVM).
la source
class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
Avec la sortie de Java 1.7, vous avez maintenant la possibilité supplémentaire d'utiliser le
try-with-resources
bloc. Par exemple,Si vous exécutez cette classe,
c.close()
elle sera exécutée lorsque letry
bloc sera laissé et avant l' exécution des blocscatch
etfinally
. Contrairement au cas de lafinalize()
méthode,close()
l'exécution est garantie. Cependant, il n'est pas nécessaire de l'exécuter explicitement dans lafinally
clause.la source
finalize()
exécutionJe suis entièrement d'accord avec d'autres réponses, en disant de ne pas compter sur l'exécution de finaliser.
En plus des blocs try-catch-finally, vous pouvez utiliser Runtime # addShutdownHook (introduit dans Java 1.3) pour effectuer des nettoyages finaux dans votre programme.
Ce n'est pas la même chose que les destructeurs , mais on peut implémenter un hook d'arrêt ayant des objets d'écoute enregistrés sur lesquels des méthodes de nettoyage (fermer les connexions de base de données persistantes, supprimer les verrous de fichiers, etc.) peuvent être invoquées - des choses qui seraient normalement effectuées dans destructeurs . Encore une fois - ce n'est pas un remplacement pour les destructeurs mais dans certains cas, vous pouvez aborder la fonctionnalité souhaitée avec cela.
L'avantage de cela est d'avoir un comportement de déconstruction faiblement couplé au reste de votre programme.
la source
Non,
java.lang.Object#finalize
c'est le plus proche que vous pouvez obtenir.Cependant, quand (et si) il est appelé, il n'est pas garanti.
Voir:
java.lang.Runtime#runFinalizersOnExit(boolean)
la source
Tout d'abord, notez que comme Java est récupéré, il est rare de devoir faire quoi que ce soit à propos de la destruction d'objets. D'abord parce que vous n'avez généralement pas de ressources gérées à libérer, et ensuite parce que vous ne pouvez pas prédire quand ou si cela se produira, donc c'est inapproprié pour les choses que vous devez vous produire "dès que plus personne n'utilise mon objet ".
Vous pouvez être averti après qu'un objet a été détruit à l'aide de java.lang.ref.PhantomReference (en fait, dire qu'il a été détruit peut être légèrement inexact, mais si une référence fantôme à lui est mise en file d'attente, elle n'est plus récupérable, ce qui équivaut généralement à la même chose). Une utilisation courante est:
Il y a aussi finalize (), qui ressemble à un destructeur mais ne se comporte pas comme tel. Ce n'est généralement pas une bonne option.
la source
La
finalize()
fonction est le destructeur.Cependant, il ne doit pas être utilisé normalement car il est invoqué après le GC et vous ne pouvez pas dire quand cela se produira (si jamais).
De plus, il faut plus d'un GC pour désallouer les objets qui en ont
finalize()
.Vous devriez essayer de nettoyer dans les endroits logiques de votre code en utilisant les
try{...} finally{...}
instructions!la source
Je suis d'accord avec la plupart des réponses.
Vous ne devriez pas dépendre entièrement de chaque
finalize
ouShutdownHook
finaliser
La JVM ne garantit pas quand cette
finalize()
méthode sera invoquée.finalize()
est appelé une seule fois par le thread GC. Si un objet se rétablit de la méthode de finalisation, ilfinalize
ne sera plus appelé.Dans votre application, vous pouvez avoir des objets actifs sur lesquels la récupération de place n'est jamais invoquée.
Tout ce
Exception
qui est jeté par la méthode de finalisation est ignoré par le thread GCSystem.runFinalization(true)
et lesRuntime.getRuntime().runFinalization(true)
méthodes augmentent la probabilité d'invoquer lafinalize()
méthode mais maintenant ces deux méthodes sont obsolètes. Ces méthodes sont très dangereuses en raison du manque de sécurité des threads et de la création possible d'un blocage.shutdownHooks
La machine virtuelle Java s'arrête en réponse à deux types d'événements:
System.exit
méthode exit (de manière équivalente ) est invoquée, ouLes crochets d'arrêt devraient également terminer leur travail rapidement. Lorsqu'un programme appelle exit, on s'attend à ce que la machine virtuelle s'arrête et se ferme rapidement.
Mais même la documentation Oracle a indiqué que
Cela se produit lorsque la machine virtuelle est arrêtée en externe, par exemple avec le
SIGKILL
signal sur Unix ou l'TerminateProcess
appel sur Microsoft Windows. La machine virtuelle peut également abandonner si une méthode native tourne mal en corrompant, par exemple, les structures de données internes ou en tentant d'accéder à la mémoire inexistante. Si la machine virtuelle abandonne, aucune garantie ne peut être donnée quant à l'exécution ou non de hooks d'arrêt.Conclusion : utilisez les
try{} catch{} finally{}
blocs de manière appropriée et libérez les ressources critiques enfinally(}
bloc. Pendant la libération des ressources enfinally{}
bloc, captureException
etThrowable
.la source
Si ce n'est que de la mémoire qui vous inquiète, ne le faites pas. Faites confiance au GC, il fait un travail décent. En fait, j'ai vu quelque chose à ce sujet étant si efficace qu'il pourrait être préférable pour les performances de créer des tas d'objets minuscules que d'utiliser des tableaux de grande taille dans certains cas.
la source
Vous pouvez peut-être utiliser un bloc try ... finally pour finaliser l'objet dans le flux de contrôle auquel vous utilisez l'objet. Bien sûr, cela ne se produit pas automatiquement, mais la destruction en C ++ non plus. Vous voyez souvent la fermeture des ressources dans le bloc finalement.
la source
Il y a une annotation @Cleanup dans Lombok qui ressemble principalement à des destructeurs C ++:
Lors du traitement (au moment de la compilation), Lombok insère le
try-finally
bloc approprié afin qu'ilresource.close()
soit invoqué, lorsque l'exécution quitte la portée de la variable. Vous pouvez également spécifier explicitement une autre méthode pour libérer la ressource, par exempleresource.dispose()
:la source
@Cleanup
L'équivalent le plus proche d'un destructeur en Java est la méthode finalize () . La grande différence avec un destructeur traditionnel est que vous ne pouvez pas être sûr quand il sera appelé, car c'est la responsabilité du garbage collector. Je recommande fortement de lire attentivement ceci avant de l'utiliser, car vos modèles RAIA typiques pour les descripteurs de fichiers et ainsi de suite ne fonctionneront pas de manière fiable avec finalize ().
la source
Beaucoup de bonnes réponses ici, mais il y a des informations supplémentaires sur les raisons pour lesquelles vous devriez éviter d'utiliser finalize () .
Si la JVM se ferme à cause de
System.exit()
ouRuntime.getRuntime().exit()
, les finaliseurs ne seront pas exécutés par défaut. De Javadoc pour Runtime.exit () :Vous pouvez appeler
System.runFinalization()
mais cela ne fait que "le meilleur effort pour terminer toutes les finalisations en suspens" - pas une garantie.Il existe une
System.runFinalizersOnExit()
méthode, mais ne l'utilisez pas - elle est dangereuse, déconseillée depuis longtemps.la source
Si vous écrivez une applet Java, vous pouvez remplacer la méthode "destroy ()" de l'applet. C'est...
Évidemment, ce n'est pas ce que vous voulez, mais peut-être ce que les autres recherchent.
la source
En pensant simplement à la question originale ... qui, je pense que nous pouvons conclure de toutes les autres réponses apprises, et aussi du Java efficace essentiel de Bloch , le point 7, "Évitez les finaliseurs", cherche la solution à une question légitime d'une manière qui est inapproprié pour le langage Java ...:
... ne serait pas une solution assez évidente pour faire ce que l'OP veut réellement être de garder tous vos objets qui doivent être réinitialisés dans une sorte de "parc à bébé", auquel tous les autres objets non réinitialisables ont des références uniquement par une sorte de l'objet accesseur ...
Et puis, lorsque vous devez "réinitialiser", vous déconnectez le parc existant et en créez un nouveau: tout le tissu d'objets dans le parc est jeté à la dérive, pour ne jamais revenir, et un jour pour être collecté par le GC.
Si l'un de ces objets est
Closeable
(ou non, mais a uneclose
méthode), vous pouvez les placer dans unBag
parc de jeu au fur et à mesure qu'ils sont créés (et éventuellement ouverts), et le dernier acte de l'accesseur avant de couper le parc serait d'aller à travers toutes lesCloseables
fermetures ...?Le code ressemblerait probablement à ceci:
closeCloseables
serait probablement une méthode de blocage, impliquant probablement un verrou (par exempleCountdownLatch
), pour traiter (et attendre le cas échéant) toutRunnables
/Callables
dans tous les threads spécifiques à laPlaypen
fin, le cas échéant, en particulier dans le thread JavaFX.la source
Bien qu'il y ait eu des progrès considérables dans la technologie GC de Java, vous devez toujours être attentif à vos références. De nombreux cas de modèles de référence apparemment triviaux qui sont en fait des nids de rats sous le capot viennent à l'esprit.
De votre message, il ne semble pas que vous essayez d'implémenter une méthode de réinitialisation dans le but de réutiliser l'objet (vrai?). Vos objets contiennent-ils un autre type de ressources qui doivent être nettoyées (c.-à-d. Les flux qui doivent être fermés, les objets regroupés ou empruntés qui doivent être retournés)? Si la seule chose qui vous inquiète est la libération de mémoire, je reconsidérerais ma structure d'objet et tenterais de vérifier que mes objets sont des structures autonomes qui seront nettoyées au moment du GC.
la source
Il n'y a pas exactement de classe destructrice en Java, classe détruite automatiquement en Java par le garbage collector. mais vous pouvez le faire en utilisant ci-dessous mais ce n'est pas exactement la même chose:
finaliser()
Il y avait une question qui a engendré une discussion approfondie sur la finalisation , de sorte que vous devriez obtenir plus de profondeur si nécessaire ...
la source
Aucun Java n'a de destructeur. La principale raison derrière cela en Java est les Garbage Collectors qui fonctionnent passivement en arrière-plan et tous les objets sont créés dans la mémoire du tas, c'est l'endroit où GC fonctionne. En c ++ là, nous doivent appeler explicitement la fonction de suppression car il n'y a pas de chose comme Garbage collector.
la source
J'avais l'habitude de m'occuper principalement de C ++ et c'est ce qui m'a conduit à la recherche d'un destructeur également. J'utilise beaucoup JAVA maintenant. Ce que j'ai fait, et ce n'est peut-être pas le meilleur cas pour tout le monde, mais j'ai implémenté mon propre destructeur en réinitialisant toutes les valeurs à 0 ou par défaut via une fonction.
Exemple:
Idéalement, cela ne fonctionnera pas dans toutes les situations, mais lorsqu'il existe des variables globales, cela fonctionnera tant que vous n'en aurez pas une tonne.
Je sais que je ne suis pas le meilleur programmeur Java, mais cela semble fonctionner pour moi.
la source