Est-il destructeur pour Java?

y a-t-il un destructeur pour Java? Je ne semble pas être en mesure de trouver toute la documentation sur ce sujet. Si il n'y en a pas, comment puis-je obtenir le même effet?

pour rendre ma question plus spécifique, j'écris une application qui traite des données et la spécification dire qu'il devrait y avoir un bouton "reset" qui ramène l'application à son état initial vient de lancer. Cependant, toutes les données doivent être "live" à moins que l'application ne soit fermée ou que le bouton "reset" ne soit appuyé.

étant habituellement un programmeur C/C++, j'ai pensé que ce serait trivial à implémenter. (Et j'ai donc prévu de le mettre en œuvre en dernier.) J'ai structuré mon programme de manière à ce que tous les objets 'reset-able' soient dans la même classe, de sorte que je puisse simplement détruire tous les objets 'live' lorsqu'un bouton reset est appuyé.

je pensais que si tout ce que je faisais était de déréférencer les données et d'attendre le collecteur d'ordures pour les recueillir, ne serait-il pas une fuite de mémoire si mon l'Utilisateur a saisi des données à plusieurs reprises et appuyé sur le bouton de réinitialisation? Je pensais aussi depuis Java est assez mature comme un langage, il devrait y avoir un moyen d'empêcher que cela se produise ou gracieusement remédier.

501
demandé sur KIN 2008-10-05 17:12:25

20 réponses

comme Java est un langage collecté par les ordures, vous ne pouvez pas prédire quand (ou même si) un objet sera détruit. Donc il n'y a pas d'équivalent direct d'un destructeur.

il y a une méthode héritée appelée finalize , mais cela est appelé entièrement à la discrétion du collecteur d'ordures. Ainsi, pour les classes qui ont besoin de nettoyer explicitement, la convention est de définir une méthode close et d'utiliser finaliser seulement pour la vérification de la santé (i.e. si fermer n'a pas été appelé faire maintenant et enregistrer une erreur).

il y avait une question qui a donné lieu à une discussion approfondie de la version finale de récemment, de sorte que cela devrait fournir plus de détails si nécessaire...

462
répondu Garth Gilmour 2017-05-23 12:02:46

non, pas de destructeurs ici. La raison en est que tous les objets Java sont alloués en tas et les déchets sont collectés. Sans une désallocation explicite (c'est-à-dire l'opérateur de suppression de C++), il n'y a pas de moyen raisonnable de mettre en œuvre de véritables destructeurs.

Java ne supporte pas les finaliseurs, mais ils sont destinés à être utilisés uniquement comme une sauvegarde pour les objets qui tiennent une poignée vers des ressources natives comme les sockets, les poignées de fichiers, les poignées de fenêtres, etc. Lorsque le collecteur d'ordures recueille un objet sans finaliseur il marque simplement la zone de mémoire libre et c'est tout. Quand l'objet a un finaliseur, il est d'abord copié dans un emplacement temporaire (rappelez-vous, nous sommes la collecte des ordures ici), puis il est enquêté dans une file d'attente-à-être-finalisé et puis un fil de finaliseur scrute la file d'attente avec une très faible priorité et exécute le finaliseur.

lorsque la demande est retirée, la JVM s'arrête sans attendre que les objets en attente soient finalisés, de sorte qu'il n'y a pratiquement aucune garantie que votre finaliseurs sera jamais exécuté.

106
répondu ddimitrov 2017-06-19 13:41:51

si vous utilisez Java 7, consultez la déclaration 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 méthode BufferedReader.close() . Vous pouvez créer votre propre classe qui implémente AutoCloseable et l'utiliser de la même manière.

cette déclaration est plus limitée que finalize en termes de structuration du code, mais en même temps elle rend le code plus simple à comprendre et maintenir. En outre, il n'y a aucune garantie qu'une méthode finalize est appelée du tout pendant le temps de l'application.

98
répondu Vitalii Fedorenko 2016-01-21 04:07:00

l'utilisation des méthodes finalize () doit être évitée. Ils ne sont pas un mécanisme fiable pour le nettoyage des ressources et il est possible de causer des problèmes dans le collecteur d'ordures en 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 peut être vue dans les API existantes (par exemple Closeable , graphiques.Eliminer() , Widget.dispose () ) et est généralement appelé via try/finally.

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

les tentatives d'utilisation d'un objet éliminé devraient donner lieu à une exception d'exécution (voir IllegalStateException ).


EDIT:

je me disais, si tout ce que je faisais était juste déréférencer les données et d'attendre le ramasseur d'ordures pour les ramasser, ne serait-il pas être un fuite de mémoire si mon l'Utilisateur a entré des données à plusieurs reprises et appuyé sur le bouton de réinitialisation?

généralement, tout ce que vous devez faire est de déréférence les objets - au moins, c'est la façon dont il est censé fonctionner. Si vous êtes inquiet au sujet de la collecte des ordures, consultez Java SE 6 HotSpot[tm] collecte des ordures de la Machine virtuelle Tuning (ou le document équivalent pour votre version JVM).

22
répondu McDowell 2008-10-05 23:18:41

avec Java 1.7 libéré, vous avez maintenant l'option supplémentaire d'utiliser le bloc try-with-resources . 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() sera exécuté lorsque le bloc try sera quitté, et avant que les blocs catch et finally soient exécutés. Contrairement à la méthode finalize() , la méthode close() est garantie d'exécution. Toutefois, il n'est pas nécessaire de l'exécuter explicitement dans le finally clause.

21
répondu waku 2016-11-14 10:22:23

je suis entièrement d'accord pour les 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 en Java 1.6) Pour effectuer des nettoyages finaux dans votre programme.

ce n'est pas la même chose que les destructeurs sont , mais on peut mettre en œuvre un crochet d'arrêt ayant des objets d'écoute enregistrés sur les méthodes de nettoyage (fermer les connexions de base de données persistantes, supprimer les verrous de fichier, et ainsi de suite) peuvent être invoquées - des choses que serait normalement fait dans les destructeurs . Encore une fois - ce n'est pas un remplacement pour les constructeurs, mais dans certains cas, vous pouvez aborder la fonctionnalité voulue avec cela.

l'avantage de ceci est d'avoir un comportement de déconstruction vaguement couplé du reste de votre programme.

12
répondu Markus Lux 2018-07-25 15:07:16

No, java.lang.Object#finalize c'est ce qui se rapproche le plus.

Toutefois, lorsque (et si) il est appelé, n'est pas garanti.

Voir: java.lang.Runtime#runFinalizersOnExit(boolean)

8
répondu flicken 2014-01-09 23:18:29

tout d'abord, notez que depuis Java est poubelle, il est rare de devoir faire quoi que ce soit à propos de la destruction d'objet. Tout d'abord parce que vous n'avez généralement pas de ressources gérées à libérer, et deuxièmement parce que vous ne pouvez pas prédire quand ou si cela se produira, donc c'est inapproprié pour les choses que vous devez se produire "dès que personne n'utilise mon objet plus".

vous pouvez être avisé après qu'un objet a été détruit en utilisant java.lang.réf.PhantomReference (en fait, dire qu'elle a été détruite peut être un peu inexact, mais si une référence fantôme à elle est mise en file d'attente alors elle n'est plus récupérable, ce qui revient 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 helper (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 le "helper" objet" dans ce cas).
  • Lorsque vous créez votre objet principal, créer un PhantomReference. Soit cela se réfère au nouvel objet helper, soit vous configurez une carte à partir des objets PhantomReference vers leurs objets helper correspondants.
  • après la collecte de l'objet principal, la référence Phantom est mise en file d'attente (ou plutôt elle peut être mise en file d'attente - comme les finalisateurs, il n'y a aucune garantie qu'elle le sera jamais, par exemple si la VM sort alors elle n'attendra pas). Assurez-vous que vous êtes traiter sa file d'attente (soit dans un thread spécial ou de temps en temps). En raison de la référence dure à l'objet helper, l'objet helper n'a pas encore été collecté. Alors faites le nettoyage que vous voulez sur l'objet helper, puis rejetez la référence fantôme et l'assistant sera éventuellement collecté aussi.

il y a aussi finalized(), qui ressemble à un destructeur mais ne se comporte pas comme tel. Il n'est généralement pas une bonne option.

5
répondu Steve Jessop 2008-10-05 15:49:16

je suis désolé si cela s'éloigne du sujet principal, mais java.util.La documentation de Timer (SE6) dit:

" lorsque la dernière référence en direct à un objet Timer disparaît et que toutes les tâches en suspens ont été exécutées, le fil d'exécution de la tâche de la minuterie se termine gracieusement (et devient sujet au ramassage des ordures). Toutefois, cela peut prendre arbitrairement longtemps à se produire. Par défaut, le thread d'exécution des tâches ne s'exécute pas comme un thread de démon, il est donc capable de garder demande de résiliation. Si un appelant veut terminer rapidement le thread d'exécution de tâche d'un minuteur, il doit invoquer la méthode d'annulation du minuteur..."

je voudrais appeler Annuler sur la classe possédant le minuteur perdre sa dernière référence(ou immeditalesky avant). Un destructeur fiable pourrait faire ça pour moi. Les commentaires ci-dessus indiquent qu'il s'agit finalement d'un mauvais choix, mais y a-t-il une solution élégante? Qu'une entreprise "...capable de conserver une demande de la résiliation..."n'est pas attrayant.

5
répondu 2009-05-20 21:56:23

si c'est juste de la mémoire qui vous inquiète, ne le faites pas. Il suffit de faire 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 la performance de créer des tas d'objets minuscules que d'utiliser de grands tableaux dans certains cas.

3
répondu John Nilsson 2008-10-05 16:04:31

la fonction finalize() est le destructeur.

cependant, il ne devrait pas être utilisé normalement parce qu'il est invoqué après la CG et vous ne pouvez pas dire quand cela se produira (si jamais).

de plus, il faut plus d'un CG pour désallouer les objets qui ont finalize() .

vous devriez essayer de nettoyer dans les endroits logiques de votre code en utilisant les instructions try{...} finally{...} !

3
répondu Shimi Bandiel 2018-02-08 10:33:36

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

vous ne devez pas dépendre entièrement de finalize ou ShutdownHook

finalisation

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

  2. finalize() est appelé seulement une fois par le fil GC si l'objet se réanime de la méthode de finalisation que finaliser ne sera pas appelé à nouveau.

  3. dans votre application, vous pouvez avoir des objets vivants, sur lesquels la collecte des ordures n'est jamais invoquée.

  4. toute Exception est lancée par la méthode de finalisation est ignorée par le fil GC

  5. Les méthodes
  6. System.runFinalization(true) et Runtime.getRuntime().runFinalization(true) augmentent la probabilité d'invoquer la méthode finalize() mais maintenant ces deux méthodes ont été dépréciés. Ces méthodes sont très dangereuses en raison du manque de sécurité du fil et de la création possible d'une impasse.

shutdownHooks

public void addShutdownHook(Thread hook)

enregistre un nouveau crochet d'arrêt de machine virtuelle.

la machine virtuelle Java s'éteint en réponse à deux types d'événements:

  1. le programme sort normalement, quand le dernier thread non-daemon sort ou quand la sortie (de manière équivalente, système.exit) la méthode est invoquée, ou
  2. la machine virtuelle est terminée en réponse à une interruption de l'utilisateur, telle que la saisie ^C, ou à un événement à l'échelle du système, tel que l'ouverture de session de l'utilisateur ou l'arrêt du système.
  3. un crochet d'arrêt est simplement un filetage initialisé mais non amorcé. Lorsque la machine virtuelle commence sa séquence d'arrêt, elle démarre tous les crochets d'arrêt enregistrés dans certains ordre non spécifié et laissez-les courir simultanément. Lorsque tous les crochets sont terminés, il exécute alors tous les finaliseurs non sollicités si la finalisation-sur-exit a été activée.
  4. enfin, la machine virtuelle va s'arrêter. Notez que les threads de démon continueront à fonctionner pendant la séquence d'arrêt, tout comme les threads non-démon si l'arrêt a été initié en invoquant la méthode de sortie.
  5. Les crochets D'arrêt
  6. devraient également terminer leur travail rapidement. Lorsque un programme invoque exit l'attente est que la machine virtuelle va rapidement arrêter et sortir.

    mais même la documentation D'Oracle a cité que

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

cela se produit lorsque la machine virtuelle est terminée extérieurement, par exemple avec le SIGKILL signal sur Unix ou l'appel TerminateProcess sur Microsoft Windows. La machine virtuelle peut aussi avorter si une méthode native dérape, par exemple en corrompant des structures de données internes ou en essayant d'accéder à une mémoire inexistante. Si la machine virtuelle échoue, aucune garantie ne peut être donnée quant à savoir si des crochets d'arrêt seront utilisés ou non.

Conclusion : utiliser try{} catch{} finally{} blocs correctement et libérer les ressources critiques dans le bloc finally(} . Pendant la libération des ressources dans le bloc finally{} , prendre Exception et Throwable .

3
répondu Ravindra babu 2018-07-25 14:47:39

peut-être Pouvez-vous essayer ... enfin, bloquez 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 final.

2
répondu I GIVE CRAP ANSWERS 2008-10-05 13:51:17

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é, puisque c'est la responsabilité du collecteur d'ordures. Je recommande fortement de lire attentivement sur ce point avant de l'utiliser, car vos modèles RAIA typiques pour les poignées de fichiers et ainsi de suite ne fonctionneront pas de manière fiable avec finalize().

1
répondu Nik 2008-10-05 13:20:01

il y a une @Cleanup annotation dans Lombok qui ressemble surtout aux destructeurs C++:

@Cleanup
ResourceClass resource = new ResourceClass();

lors du traitement (au moment de la compilation), Lombok insère le bloc approprié try-finally de sorte que resource.close() soit invoqué, lorsque l'exécution sort de 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();
1
répondu Alexey 2016-12-28 12:58:52

bien qu'il y ait eu des progrès considérables dans la technologie GC de Java, vous devez toujours être conscient de vos références. De nombreux cas de modèles de référence apparemment insignifiants qui sont en fait des rats nids sous le capot viennent à l'esprit.

de votre post, il ne semble pas que vous essayez de mettre en œuvre une méthode de réinitialisation dans le but de réutiliser un objet (vrai?). Vos objets contiennent-ils d'autres types de ressources qui doivent être nettoyées (c.-à-d. des flux)? qui doit être fermé, collectif ou d'objets empruntés doivent être retournés)? Si la seule chose qui vous inquiète est memory dealloc, alors 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.

0
répondu tyler 2008-10-05 17:39:56

si vous écrivez un Applet Java, vous pouvez outrepasser la méthode Applet" destroy ()". Il 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 pas ce que vous voulez, mais pourrait être ce que d'autres personnes sont à la recherche.

0
répondu 2009-08-25 14:54:00

je pense à la question originale... ce que, je pense que nous pouvons conclure de toutes les autres réponses apprises , et aussi de L'essentiel de Bloch Java efficace , point 7, "éviter les finaliseurs", cherche la solution à une question légitime d'une manière qui est inappropriée au 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 "playpen", auquel tous les autres objets non-resettable ont des références seulement à travers une sorte d'accessor objet...

et puis quand vous avez besoin de" réinitialiser " vous déconnectez le parc existant et en faire un nouveau: tout le réseau d'objets dans le parc est jeté à la dérive, ne jamais revenir, et un jour être collecté par le GC.

si l'un de ces objets est Closeable (ou non, mais ont une méthode close ) vous pouvez les mettre dans un Bag dans le parc comme ils sont créés (et éventuellement ouvert), et le dernier acte de l'accesseur avant de couper le parc serait de passer par tous les Closeables de clôture... ?

le code ressemblerait probablement à quelque chose comme ceci:

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

closeCloseables serait probablement une méthode de blocage, impliquant probablement un loquet (par exemple CountdownLatch ), pour traiter (et attendre comme approprié) n'importe quel Runnables / Callables dans n'importe quels fils spécifique au Playpen à terminer selon le cas, notamment dans le fil JavaFX.

0
répondu mike rodent 2016-12-21 18:25:50

il n'y a pas exactement de classe destructrice en Java, classe détruite en java automatiquement par le collecteur d'ordures . mais vous pouvez faire cela en utilisant un ci-dessous, mais ce n'est pas exactement la même chose :

finalize ()

il y avait une question qui a donné lieu à une discussion en profondeur de finaliser , de sorte que vous devriez obtenir plus de détails si nécessaire...

0
répondu Manas 2018-07-05 09:16:25

j'avais l'habitude de traiter principalement avec C++ et c'est ce qui m'a conduit à la recherche d'un destructeur aussi bien. 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établissant toutes les valeurs à 0 ou là par défaut à travers 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 pour toutes les situations, mais là où il y a des variables globales, cela fonctionnera aussi longtemps que vous ne avoir une tonne d'eux.

je sais que je ne suis pas le meilleur programmeur Java, mais il semble fonctionner pour moi.

-2
répondu user1718739 2013-05-17 16:14:28