Existe-t-il un destructeur pour Java?

594

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.

wai
la source
7
Il n'y a une fuite de mémoire que si vous détenez des références à des objets dont vous n'avez pas besoin. ie Il y a un bug dans votre programme. Le GC fonctionnera comme il le faut (parfois plus tôt)
Peter Lawrey
17
La machine virtuelle n'exécutera pas GC assez tôt si vous traitez rapidement des données via des objets. L'idée que le GC peut toujours suivre ou prendre les bonnes décisions est une erreur.
Kieveli
1
@Kieveli La JVM n'exécuterait-elle pas GC avant de donner une erreur?
WVrock
4
Ouais, ce serait bien s'il y avait un destructeur pour Java qui le détruirait une fois pour toutes.
Tomáš Zato - Réintègre Monica

Réponses:

526

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 ...

Garth Gilmour
la source
5
"Close ()" dans ce contexte fait-il référence à la méthode dans java.lang.Autocloseable?
Sridhar Sarnobat
21
Non, AutoCloseable a été introduit dans Java 7, mais la convention «close ()» existe depuis bien plus longtemps.
Jon Onstott
pourquoi vous ne pouvez pas prédire quand (ou même si) un objet sera détruit. quelle autre façon approximative de prédire cela?
dctremblay
La destruction des objets @dctremblay est effectuée par le garbage collector et le garbage collector peut ne jamais s'exécuter pendant la durée de vie de l'application.
Piro dit Réintégrer Monica
4
Notez que la finalizeméthode est déconseillée dans Java 9.
Lii
124

Jetez un œil à l' instruction try-with-resources . Par exemple:

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

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émente AutoCloseableet l'utiliser de manière similaire.

Cette déclaration est plus limitée qu'en finalizetermes de structuration de code, mais en même temps, elle rend le code plus simple à comprendre et à maintenir. En outre, rien ne garantit qu'une finalizeméthode est appelée du tout pendant la durée de vie de l'application.

Vitalii Fedorenko
la source
12
Je suis surpris que cela ait si peu de votes. C'est la vraie réponse.
nurettin
20
Je ne suis pas d'accord que c'est la vraie réponse. Si une instance a une ressource qu'elle gère sur une plus longue période de temps, sur plusieurs appels de méthode, alors essayer avec des ressources n'aidera pas. À moins qu'il ne soit autorisé de fermer et de rouvrir ladite ressource au rythme auquel lesdites méthodes sont appelées - ce n'est pas un fait général.
Eric
14
En effet, ce n'est pas la vraie réponse. Il est impossible d'utiliser cette structure pour gérer la destruction d'un objet à moins que la construction et l'utilisation de l'objet ne soient entièrement encapsulées par le tryet que le finallysoit 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".
7yl4r
1
D'autres utilisateurs ont montré que cela se faisait dans le point d'entrée de votre application. Définissez votre variable globalement. Initialisez-le dans la fonction d'entrée, avec try. Désinitialisez le enfin (lorsque votre application se ferme). C'est tout à fait possible.
TamusJRoyce
1
@nurettin Java 7 n'était sorti que depuis 3 mois lorsque la question a été posée, si cela aide à la comprendre davantage.
corsiKa
110

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.

ddimitrov
la source
4
Merci d'avoir mentionné les ressources natives - c'est un domaine où une méthode "semblable à un destructeur" est utile.
Nathan Osman
oui, je suis confronté au même problème en ce moment avec la libération de ressources / poignées allouées via des appels natifs à C ++.
nikk
@ddimitrov, en théorie, Java pourrait-il implémenter une désallocation explicite? Ou est-ce une contradiction logique?
mils
1
@mils implémentant naïvement une désallocation explicite briserait l'hypothèse Java selon laquelle toute référence pointe vers un objet vivant. Vous pouvez parcourir tous les pointeurs et annuler les alias, mais c'est plus cher que GC. Ou vous pouvez essayer d'utiliser un système de type linéaire (voir "propriété" dans Rust), mais c'est un changement de langue majeur. Il existe également d'autres options (voir la mémoire de portée JavaRT, etc.), mais en général, la désallocation explicite ne correspond pas bien au langage Java.
ddimitrov
31

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.

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

Les tentatives d'utilisation d'un objet supprimé doivent lever une exception d'exécution (voir IllegalStateException ).


ÉDITER:

Je me disais, si tout ce que je faisais était de déréférencer les données et d'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?

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).

McDowell
la source
1
Ce n'est pas ce que signifie la déférence. Il ne s'agit pas de "définir la dernière référence d'un objet sur null" mais plutôt d'obtenir (lire) la valeur d'une référence afin de pouvoir l'utiliser pour des opérations ultérieures.
1
Try..finally est-il toujours une approche valide et recommandée? Supposons que j'appelais auparavant une méthode native dans finalize (), puis-je déplacer l'appel vers la clause finally? class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
aashima
r ne serait pas limité au bloc finalement. Par conséquent, vous ne pouvez pas appeler destroy à ce stade. Maintenant, si vous corrigez la portée pour avoir la création d'objet avant le bloc try, vous vous retrouverez avec le cas laid "avant try-with-resources".
userAsh
21

Avec la sortie de Java 1.7, vous avez maintenant la possibilité supplémentaire d'utiliser le try-with-resourcesbloc. Par exemple,

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 vous exécutez cette classe, c.close()elle sera exécutée lorsque le trybloc sera laissé et avant l' exécution des blocs catchet finally. Contrairement au cas de la finalize()méthode, close()l'exécution est garantie. Cependant, il n'est pas nécessaire de l'exécuter explicitement dans la finallyclause.

waku
la source
que faire si nous n'avons pas utilisé le bloc try-with-resources? Je pense que nous pouvons appeler close dans finalize () juste pour nous assurer que close a bien été appelé.
shintoZ
3
@shintoZ comme je l'ai lu dans les réponses ci-dessus, il n'y a aucune garantie d' finalize()exécution
Asif Mushtaq
14

Je 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.

Markus
la source
addShutdownHook a apparemment été introduit dans Java 1.3. Quoi qu'il en soit, il est disponible pour moi en 1.5. :) Voir ceci: stackoverflow.com/questions/727151/…
skiphoppy
1
Pour info, d'après mon expérience, les hooks d'arrêt ne seront pas appelés si vous utilisez le bouton rouge "terminer" dans Eclipse - la JVM entière est détruite immédiatement, les hooks d'arrêt ne sont pas appelés avec grâce. Cela signifie que vous pouvez voir un comportement différent pendant le développement et la production si vous développez en utilisant Eclipse
Hamy
11

Non, java.lang.Object#finalizec'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)

flicken
la source
5
Une méthode qui peut ou non être appelée est essentiellement inutile dans mon livre. Il aurait été préférable de ne pas polluer la langue avec une méthode spéciale inutile qui, au mieux, donne un faux sentiment de sécurité. Je ne comprendrai jamais pourquoi les développeurs du langage Java ont pensé que finaliser était une bonne idée.
entrée le
@antred Les développeurs du langage Java sont d'accord . Je suppose qu'à l'époque, pour certains d'entre eux, c'était la première fois qu'ils concevaient un langage de programmation et un environnement d'exécution avec garbage collection. Ce qui est moins compréhensible, c'est pourquoi cet autre langage géré a copié ce concept à la fois, alors qu'il était déjà compris que ce concept était une mauvaise idée.
Holger
7

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:

  • Séparez les ressources de votre classe qui doivent être détruites dans un autre objet d'assistance (notez que si tout ce que vous faites est de fermer une connexion, ce qui est un cas courant, vous n'avez pas besoin d'écrire une nouvelle classe: la connexion à fermer serait l '"objet d'assistance" dans ce cas).
  • Lorsque vous créez votre objet principal, créez-lui également une référence fantôme. Soit que cela fasse référence au nouvel objet d'assistance, soit que vous configuriez une carte des objets PhantomReference vers leurs objets d'assistance correspondants.
  • Une fois l'objet principal collecté, la référence fantôme est mise en file d'attente (ou plutôt elle peut être mise en file d'attente - comme les finaliseurs, il n'y a aucune garantie qu'elle le sera jamais, par exemple si la machine virtuelle se termine, elle n'attendra pas). Assurez-vous de traiter sa file d'attente (soit dans un fil spécial, soit de temps en temps). En raison de la référence matérielle à l'objet d'assistance, l'objet d'assistance n'a pas encore été collecté. Faites donc le nettoyage que vous souhaitez sur l'objet d'assistance, puis jetez la référence fantôme et l'aide sera finalement collectée également.

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.

Steve Jessop
la source
Pourquoi une référence fantôme au lieu d'une référence faible?
uckelman
2
@uckelman: si tout ce que vous voulez c'est une notification, alors PhantomReference fait le travail, c'est à peu près ce pour quoi il est conçu. La sémantique supplémentaire de WeakReference n'est pas nécessaire ici, et au moment où votre ReferenceQueue est notifiée, vous ne pouvez plus récupérer l'objet via WeakReference, donc la seule raison de l'utiliser est d'économiser en vous rappelant que PhantomReference existe. Tout travail supplémentaire effectué par WeakReference est probablement négligeable, mais pourquoi s'en soucier?
Steve Jessop
Merci d'avoir fait allusion à PhantomReference. Ce n'est pas parfait, mais toujours mieux que rien.
foo
@SteveJessop quel «travail supplémentaire», pensez-vous, a une référence faible par rapport à une référence fantôme?
Holger
6

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!

Shimi Bandiel
la source
5

Je suis d'accord avec la plupart des réponses.

Vous ne devriez pas dépendre entièrement de chaque finalizeouShutdownHook

finaliser

  1. La JVM ne garantit pas quand cette finalize()méthode sera invoquée.

  2. finalize()est appelé une seule fois par le thread GC. Si un objet se rétablit de la méthode de finalisation, il finalizene sera plus appelé.

  3. Dans votre application, vous pouvez avoir des objets actifs sur lesquels la récupération de place n'est jamais invoquée.

  4. Tout ce Exceptionqui est jeté par la méthode de finalisation est ignoré par le thread GC

  5. System.runFinalization(true)et les Runtime.getRuntime().runFinalization(true)méthodes augmentent la probabilité d'invoquer la finalize()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

public void addShutdownHook(Thread hook)

Enregistre un nouveau hook d'arrêt de machine virtuelle.

La machine virtuelle Java s'arrête en réponse à deux types d'événements:

  1. Le programme se ferme normalement, lorsque le dernier thread non démon se termine ou lorsque la System.exitméthode exit (de manière équivalente ) est invoquée, ou
  2. La machine virtuelle est arrêtée en réponse à une interruption utilisateur, telle que la saisie de ^ C, ou un événement à l'échelle du système, tel que la fermeture de session utilisateur ou l'arrêt du système.
  3. Un hook d'arrêt est simplement un thread initialisé mais non démarré. Lorsque la machine virtuelle commence sa séquence d'arrêt, elle démarre tous les hooks d'arrêt enregistrés dans un ordre non spécifié et les laisse s'exécuter simultanément. Une fois tous les hooks terminés, tous les finaliseurs non invoqués seront exécutés si la finalisation à la sortie a été activée.
  4. Enfin, la machine virtuelle s'arrêtera. Notez que les threads démons continueront de s'exécuter pendant la séquence d'arrêt, de même que les threads non démons si l'arrêt a été lancé en appelant la méthode exit.
  5. Les 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

Dans de rares circonstances, la machine virtuelle peut abandonner, c'est-à-dire arrêter de fonctionner sans s'arrêter proprement

Cela se produit lorsque la machine virtuelle est arrêtée en externe, par exemple avec le SIGKILLsignal sur Unix ou l' TerminateProcessappel 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 en finally(}bloc. Pendant la libération des ressources en finally{}bloc, capture Exceptionet Throwable.

Ravindra babu
la source
4

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.

John Nilsson
la source
3

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.

JE DONNE DES RÉPONSES CRAP
la source
1
C'est la bonne réponse lorsque la ressource en question a un seul propriétaire et n'a jamais de références à elle "volée" par un autre code.
Steve Jessop
3

Il y a une annotation @Cleanup dans Lombok qui ressemble principalement à des destructeurs C ++:

@Cleanup
ResourceClass resource = new ResourceClass();

Lors du traitement (au moment de la compilation), Lombok insère le try-finallybloc approprié afin qu'il resource.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 exemple resource.dispose():

@Cleanup("dispose")
ResourceClass resource = new ResourceClass();
Alexey
la source
2
L'avantage que je vois est qu'il y aura moins d'imbrication (ce qui peut être important si vous avez beaucoup d'objets qui nécessitent une "destruction").
Alexey
Un bloc try-with-resource peut avoir plusieurs ressources en une seule fois
Alexander - Reinstate Monica
1
Mais il ne peut pas avoir d'instructions entre eux.
Alexey
Juste. Je suppose que la recommandation est de préférer essayer avec des ressources, même pour plusieurs ressources, à moins qu'il n'y ait besoin d'instructions entre elles qui vous obligent à faire de nouveaux blocs d'essayer avec des ressources (augmentation de l'imbrication), puis utilisez@Cleanup
Alexander - Réinstallez Monica
2

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 ().

Nik
la source
2

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()ou Runtime.getRuntime().exit(), les finaliseurs ne seront pas exécutés par défaut. De Javadoc pour Runtime.exit () :

La séquence d'arrêt de la machine virtuelle se compose de deux phases. Dans la première phase, tous les hooks d'arrêt enregistrés, le cas échéant, sont démarrés dans un ordre non spécifié et autorisés à s'exécuter simultanément jusqu'à la fin. Dans la deuxième phase, tous les finaliseurs non invoqués sont exécutés si la finalisation à la sortie a été activée. Une fois cela fait, la machine virtuelle s'arrête.

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.

kaan
la source
1

Si vous écrivez une applet Java, vous pouvez remplacer la méthode "destroy ()" de l'applet. C'est...

 * 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().

Évidemment, ce n'est pas ce que vous voulez, mais peut-être ce que les autres recherchent.


la source
1

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 une closeméthode), vous pouvez les placer dans un Bagparc 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 les Closeablesfermetures ...?

Le code ressemblerait probablement à ceci:

accessor.getPlaypen().closeCloseables();
accessor.setPlaypen( new Playpen() );

closeCloseablesserait probablement une méthode de blocage, impliquant probablement un verrou (par exemple CountdownLatch), pour traiter (et attendre le cas échéant) tout Runnables/ Callablesdans tous les threads spécifiques à la Playpenfin, le cas échéant, en particulier dans le thread JavaFX.

Mike rongeur
la source
0

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.

tyler
la source
0

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.

Anubhav Mishra
la source
-3

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:

public myDestructor() {

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

}

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.

ChristianGLong
la source
Essayez d'utiliser davantage des objets immuables, une fois que vous l'aurez compris, cela aura plus de sens :)
R. van Twisk
5
Ce n'est pas tant faux qu'inutile - c'est-à-dire n'obtient rien. Si votre programme nécessite que les types bruts soient réinitialisés pour fonctionner correctement, les instances de vos classes ont une portée incorrecte, ce qui signifie que vous réaffectez probablement les propriétés d'un objet existant aux propriétés d'un nouvel objet, sans créer un nouvel objet ().
simo.3792
1
Sauf qu'il existe de nombreux besoins pour réinitialiser les variables. J'ai choisi le destructeur de nom car il correspond à ce que je fais. Il réalise quelque chose, rien que vous comprenez
ChristianGLong