Есть ли деструктор для Java?

Есть ли деструктор для Java? Кажется, я не могу найти никакой документации по этому поводу. Если нет, как я могу добиться такого же эффекта?

Чтобы сделать мой вопрос более конкретным, я пишу приложение, которое имеет дело с данными, и в спецификации говорится, что должна быть кнопка «сброса», которая возвращает приложение в исходное, только что запущенное состояние. Однако все данные должны быть «живыми», если приложение не закрыто или не нажата кнопка сброса.

Как обычно, программист на C / C++, я подумал, что реализовать это будет тривиально. (И поэтому я планировал реализовать это последним.) Я структурировал свою программу таким образом, чтобы все «сбрасываемые» объекты находились в одном классе, чтобы я мог просто уничтожить все «живые» объекты при нажатии кнопки сброса.

Я подумал, что если бы все, что я делал, было просто разыменовать данные и ждать, пока сборщик мусора их соберет, не возникнет ли утечка памяти, если бы мой пользователь несколько раз вводил данные и нажимал кнопку сброса? Я также думал, что, поскольку Java достаточно зрелый язык, должен быть способ предотвратить это или изящно решить эту проблему.

Утечка памяти возникает только в том случае, если вы храните ссылки на ненужные вам объекты. т.е. в вашей программе есть ошибка. Сборщик мусора будет работать по мере необходимости (иногда раньше)

Peter Lawrey 21.05.2009 03:01

Виртуальная машина не будет запускать сборщик мусора достаточно скоро, если вы быстро обрабатываете данные через объекты. Идея о том, что GC всегда может идти в ногу или принимать правильные решения, является ошибкой.

Kieveli 13.10.2011 16:32

@Kieveli Разве JVM не запускает сборщик мусора, прежде чем выдаст ошибку?

WVrock 12.11.2014 15:42

Да, было бы неплохо, если бы для Java был деструктор, который уничтожил бы его раз и навсегда.

Tomáš Zato - Reinstate Monica 17.05.2016 17:04
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
618
4
601 691
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Нет, java.lang.Object#finalize - самое близкое из возможных.

Однако, когда (и если) он вызывается, не гарантируется. См .: java.lang.Runtime#runFinalizersOnExit(boolean)

Метод, который может или не может быть вызван, в моей книге по сути бесполезен. Было бы лучше не загрязнять язык бесполезным специальным методом, который в лучшем случае дает ложное чувство безопасности. Я никогда не пойму, почему разработчики языка Java посчитали, что финализация - хорошая идея.

antred 20.02.2015 23:43

@antred Разработчики языка Java соглашаются. Думаю, тогда для некоторых из них это был первый раз, когда они разработали язык программирования и среду выполнения со сборкой мусора. Что менее понятно, так это то, почему этот другой управляемый язык скопировал эту концепцию в то время, когда уже было понято, что эта концепция - плохая идея.

Holger 07.06.2019 14:25

Функция finalize() является деструктором.

Однако его обычно не следует использовать, потому что он вызывается после GC, и вы не можете сказать, когда это произойдет (если когда-либо).

Более того, для освобождения объектов с finalize() требуется более одного сборщика мусора.

Вы должны попытаться очистить логические места в вашем коде с помощью операторов try{...} finally{...}!

Ответ принят как подходящий

Поскольку Java - это язык со сборкой мусора, вы не можете предсказать, когда (или даже если) объект будет уничтожен. Следовательно, нет прямого эквивалента деструктора.

Существует унаследованный метод finalize, но он вызывается полностью по усмотрению сборщика мусора. Итак, для классов, которые необходимо явно привести в порядок, соглашение состоит в том, чтобы определить метод Закрыть и использовать finalize только для проверки работоспособности (т.е. если Закрыть не был вызван, сделайте это сейчас и запишите ошибку).

Недавно был вопрос, который вызвал всестороннее обсуждение финализации, так что при необходимости он должен обеспечить большую глубину ...

Обращается ли «close ()» в этом контексте к методу в java.lang.Autocloseable?

Sridhar Sarnobat 26.11.2013 22:49

Нет, AutoCloseable был введен в Java 7, но соглашение close () существует гораздо дольше.

Jon Onstott 02.01.2014 20:38

почему вы не можете предсказать, когда (или даже если) объект будет уничтожен. какой примерный другой способ предсказать это?

user1270589 28.08.2016 03:06

Уничтожение объекта @dctremblay выполняется сборщиком мусора, и сборщик мусора может никогда не запускаться за время существования приложения.

Piro says Reinstate Monica 03.10.2017 14:18

Обратите внимание, что метод finalizeустарел в Java 9.

Lii 07.02.2019 17:31

Мы также можем использовать WeakReference - объекты, хранящиеся там, будут удалены до того, как сборщик мусора начнет поиск мусора.

neoexpert 14.02.2019 01:01

@dctremblay разрушение объектов - это не вещь. В какой-то момент память неиспользуемого объекта может быть перезаписана, когда она используется для другого объекта. Вся работа, связанная со сборкой мусора, будет отложена до тех пор, пока память действительно не понадобится для другого объекта. Этого может быть никогда, если а) нет последующих выделений или б) памяти достаточно для всех последующих выделений. Даже когда сборщик мусора работает, он обычно не касается мусора. Его основная задача - гарантировать, что все еще используемые объекты не будут перезаписаны. Он не идентифицирует мертвые объекты.

Holger 07.06.2019 12:51

Ближайшим эквивалентом деструктора в Java является метод финализировать (). Большое отличие от традиционного деструктора заключается в том, что вы не можете быть уверены, когда он будет вызван, поскольку за это отвечает сборщик мусора. Я настоятельно рекомендую внимательно прочитать это, прежде чем использовать его, поскольку ваши типичные шаблоны RAIA для дескрипторов файлов и т. д. Не будут надежно работать с finalize ().

Нет, деструкторов здесь нет. Причина в том, что все объекты Java выделяются в куче и собираются мусором. Без явного освобождения (т.е. оператора удаления в C++) нет разумного способа реализовать реальные деструкторы.

Java поддерживает финализаторы, но они предназначены для использования только в качестве защиты для объектов, содержащих дескриптор собственных ресурсов, таких как сокеты, дескрипторы файлов, дескрипторы окон и т. д. Когда сборщик мусора собирает объект без финализатора, он просто помечает память регион как свободный и все тут. Когда у объекта есть финализатор, он сначала копируется во временное место (помните, мы здесь собираем мусор), затем он помещается в очередь ожидания финализации, а затем поток финализатора опрашивает очередь с очень низким приоритетом. и запускает финализатор.

Когда приложение завершает работу, JVM останавливается, не дожидаясь завершения работы над ожидающими объектами, поэтому практически нет никаких гарантий, что ваши финализаторы когда-либо будут запущены.

Спасибо за упоминание собственных ресурсов - это одна из областей, где полезен «деструкторный» метод.

Nathan Osman 08.03.2013 07:24

да, прямо сейчас я сталкиваюсь с той же проблемой с освобождением ресурсов / дескрипторов, выделенных через собственные вызовы C++.

nikk 04.07.2016 06:17

@ddimitrov, теоретически может ли Java реализовать явное освобождение? Или это логическое противоречие?

mils 15.08.2017 03:52

@mils, наивная реализация явного освобождения, либо нарушит предположение Java, что любая ссылка указывает на живой объект. Вы можете перебирать все указатели и обнулять псевдонимы, но это дороже, чем сборщик мусора. Или вы можете попробовать использовать какую-нибудь систему линейных типов (см. «Владение» в Rust), но это серьезное изменение языка. Есть и другие варианты (см. Память с областью видимости JavaRT и т. д.), Но в целом явное освобождение не соответствует языку Java.

ddimitrov 28.08.2017 07:14

Следует избегать использования методов финализировать (). Они не являются надежным механизмом очистки ресурсов, и злоупотребление ими может вызвать проблемы в сборщике мусора.

Если вам требуется вызов освобождения вашего объекта, например, для освобождения ресурсов, используйте явный вызов метода. Это соглашение можно увидеть в существующих API (например, Закрывающийся, Graphics.dispose (), Widget.dispose ()) и обычно вызывается через try / finally.

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

Попытки использовать удаленный объект должны вызывать исключение времени выполнения (см. IllegalStateException).


Обновлено:

I was thinking, if all I did was just to dereference the data and wait for the garbage collector to collect them, wouldn't there be a memory leak if my user repeatedly entered data and pressed the reset button?

Как правило, все, что вам нужно сделать, это разыменовать объекты - по крайней мере, так это должно работать. Если вас беспокоит сборка мусора, ознакомьтесь с Java SE 6 HotSpot [tm] Настройка сборки мусора виртуальной машины (или аналогичным документом для вашей версии JVM).

Это не то, что означает разыменование. Он не «устанавливает для последней ссылки объекта значение null», а скорее получает (считывает) значение из ссылки, чтобы вы могли использовать его для последующих операций.

user146043 15.09.2015 15:53

Попытка .. наконец-то все еще действующий и рекомендуемый подход? Предположим, я ранее вызывал собственный метод в finalize (), могу ли я переместить вызов в предложение finally? class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }

aashima 24.09.2019 13:13

r не будет ограничен блоком finally. Следовательно, на этом этапе вы не можете вызывать уничтожение. Теперь, если вы исправите область видимости, чтобы объект был создан до блока try, вы получите уродливый случай «до попытки с ресурсами».

userAsh 24.09.2019 15:27

Возможно, вы можете использовать блок try ... finally для завершения объекта в потоке управления, в котором вы используете этот объект. Конечно, это не происходит автоматически, но и разрушение не происходит в C++. Вы часто видите закрытие ресурсов в блоке finally.

Это правильный ответ, когда у рассматриваемого ресурса есть единственный владелец и никогда не бывает ссылок на него, «украденных» другим кодом.

Steve Jessop 05.10.2008 19:45

Я полностью согласен с другими ответами, говоря, что не следует полагаться на выполнение finalize.

В дополнение к блокам try-catch-finally вы можете использовать Время выполнения # addShutdownHook (представленный в Java 1.3) для выполнения окончательной очистки в вашей программе.

Это не то же самое, что деструкторы, но можно реализовать ловушку выключения, имеющую зарегистрированные объекты слушателя, на которых могут быть вызваны методы очистки (закрытие постоянных соединений с базой данных, снятие блокировки файлов и т. д.) - вещи, которые обычно выполняется в деструкторах. Опять же - это не замена деструкторам, но в некоторых случаях вы можете достичь желаемой функциональности с помощью этого.

Преимущество этого заключается в том, что у остальной части вашей программы есть поведение деконструкции слабо связанный.

addShutdownHook был явно представлен в Java 1.3. Во всяком случае, он доступен мне в 1.5. :) Смотрите это: stackoverflow.com/questions/727151/…

skiphoppy 07.04.2009 23:40

К вашему сведению, по моему опыту, хуки выключения не будут вызываться, если вы используете красную кнопку «завершить» в Eclipse - вся JVM немедленно уничтожается, хуки выключения не вызываются изящно. Это означает, что вы можете увидеть другое поведение во время разработки и производства, если вы разрабатываете с использованием eclipse.

Hamy 06.10.2015 21:15

Во-первых, обратите внимание, что, поскольку Java собирает мусор, редко нужно что-либо делать для уничтожения объекта. Во-первых, потому что у вас обычно нет управляемых ресурсов для освобождения, а во-вторых, потому что вы не можете предсказать, когда или если это произойдет, поэтому это неуместно для вещей, которые вам нужно произойти, «как только никто больше не будет использовать мой объект. ".

Вы можете получить уведомление после того, как объект был уничтожен с помощью java.lang.ref.PhantomReference (на самом деле, сообщение о том, что объект был уничтожен, может быть немного неточным, но если фантомная ссылка на него поставлена ​​в очередь, то он больше не подлежит восстановлению, что обычно составляет тоже самое). Обычное использование:

  • Выделите ресурсы в своем классе, которые необходимо уничтожить, в другой вспомогательный объект (обратите внимание, что если все, что вы делаете, закрывает соединение, что является обычным случаем, вам не нужно писать новый класс: в этом случае соединение, которое нужно закрыть, будет «вспомогательным объектом»).
  • Когда вы создаете свой основной объект, создайте также PhantomReference для него. Либо сделайте ссылку на новый вспомогательный объект, либо настройте карту от объектов PhantomReference к их соответствующим вспомогательным объектам.
  • После того, как основной объект собран, PhantomReference ставится в очередь (или, скорее, он может быть поставлен в очередь - как и у финализаторов, нет никакой гарантии, что это когда-либо будет, например, если виртуальная машина выйдет, она не будет ждать). Убедитесь, что вы обрабатываете его очередь (либо в специальном потоке, либо время от времени). Из-за жесткой ссылки на вспомогательный объект вспомогательный объект еще не был собран. Так что сделайте любую очистку вспомогательного объекта, которая вам нравится, затем отбросьте PhantomReference, и помощник в конечном итоге будет собран.

Также есть finalize (), который выглядит как деструктор, но не ведет себя как деструктор. Обычно это не лучший вариант.

Почему PhantomReference вместо WeakReference?

uckelman 01.04.2011 13:39

@uckelman: если все, что вам нужно, это уведомление, то PhantomReference выполняет свою работу, это в значительной степени то, для чего он предназначен. Дополнительная семантика WeakReference здесь не нужна, и в тот момент, когда ваш ReferenceQueue уведомлен, вы больше не можете восстановить объект через WeakReference, поэтому единственная причина для его использования - сохранить необходимость помнить о существовании PhantomReference. Любая дополнительная работа, которую выполняет WeakReference, вероятно, незначительна, но зачем с ней возиться?

Steve Jessop 03.04.2011 20:39

Спасибо, что намекнули на PhantomReference. Это не идеально, но все же лучше, чем ничего.

foo 16.03.2012 22:43

@SteveJessop, какая «дополнительная работа», по вашему мнению, имеет слабую ссылку по сравнению с фантомной ссылкой?

Holger 07.06.2019 14:38

Если вас беспокоит просто воспоминание, не надо. Просто поверьте, GC он делает достойную работу. Я действительно видел кое-что в том, что это настолько эффективно, что для производительности может быть лучше создавать кучи крошечных объектов, чем в некоторых случаях использовать большие массивы.

Хотя в технологии Java GC были достигнуты значительные успехи, вам все же нужно помнить о своих ссылках. На ум приходят многочисленные случаи, казалось бы, тривиальных эталонных шаблонов, которые на самом деле представляют собой крысиные гнезда под капотом.

Из вашего сообщения не похоже, что вы пытаетесь реализовать метод сброса с целью повторного использования объекта (правда?). Содержат ли ваши объекты какие-либо другие типы ресурсов, которые необходимо очистить (например, потоки, которые должны быть закрыты, любые объединенные или заимствованные объекты, которые необходимо вернуть)? Если вас беспокоит только освобождение памяти, я бы пересмотрел свою структуру объекта и попытался проверить, что мои объекты являются автономными структурами, которые будут очищены во время сборки мусора.

Если вы пишете Java-апплет, вы можете переопределить метод «destroy ()» апплета. Это...

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

Очевидно, это не то, что хочет ты, но может быть то, что ищут другие люди.

Взгляните на оператор попробовать с ресурсами. Например:

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

Здесь ресурс, который больше не нужен, освобождается методом BufferedReader.close(). Вы можете создать свой собственный класс, реализующий AutoCloseable, и использовать его аналогичным образом.

Этот оператор более ограничен, чем finalize, с точки зрения структурирования кода, но в то же время он упрощает понимание и сопровождение кода. Кроме того, нет гарантии, что метод finalize будет вызван вообще во время работы приложения.

Я удивлен, что у него так мало голосов. Это настоящий ответ.

nurettin 04.05.2013 13:03

Однако зависит от Java 7, и на Java 6 все еще есть множество систем (и несколько сотен миллионов устройств Android, ни одно из которых не имеет официальной поддержки Java 7.) Как конечный пользователь, я хочу иметь последнюю версию Java по соображениям безопасности. , но как разработчик я не хочу забивать себе голову пользователями. Это чужая работа. Тем не менее, +1 во многом напоминает мне Python with, который мне очень нравится.

Jonathan Baldwin 06.10.2013 05:30

Я не согласен с тем, что это реальный ответ. Если у экземпляра есть ресурс, который он обрабатывает в течение более длительного периода времени при нескольких вызовах методов, тогда try-with-resources не поможет. Если только нельзя закрыть и снова открыть указанный ресурс с той скоростью, с которой вызываются указанные методы - это не общий факт.

Eric 03.11.2015 20:36

В самом деле, это нет фактический ответ. Невозможно использовать эту структуру для управления разрушением объекта, если конструкция и использование объекта полностью не инкапсулированы try, а finally не используется для принудительного вызова obj.finalize(). И даже такая установка не решает проблемы, поставленной OP: разрушение объекта в середине программы, запускаемое кнопкой «сброс».

7yl4r 06.02.2016 08:16

Другие пользователи показали, что это делается в точке входа в ваше приложение. Определите вашу переменную глобально. Инициализируйте его во входной функции с помощью try. Деинициализируйте файл finally (когда ваше приложение закрывается). Вполне возможно.

TamusJRoyce 11.06.2018 18:04

@nurettin Java 7 вышла всего 3 месяца назад, когда был задан вопрос, помогает ли это лучше понять.

corsiKa 01.04.2019 18:51

@corsiKa, спасибо. Кроме того, за этот ответ больше не осталось мало голосов.

nurettin 01.04.2019 19:53

С выпуском Java 1.7 у вас появилась дополнительная возможность использовать блок try-with-resources. Например,

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..."); 
        } 
    }
}

Если вы выполните этот класс, c.close() будет выполнен, когда останется блок try, но до того, как будут выполнены блоки catch и finally. В отличие от метода finalize(), выполнение close() гарантировано. Однако нет необходимости выполнять его явно в разделе finally.

что, если бы мы не использовали блок try-with-resources? Я думаю, что мы можем вызвать close в finalize () просто для того, чтобы убедиться, что close был вызван.

shintoZ 12.12.2014 09:44

@shintoZ, как я читал в ответах выше, нет гарантии выполнения finalize()

Asif Mushtaq 19.09.2015 08:55

Раньше я в основном имел дело с C++, и это тоже привело меня к поиску деструктора. Сейчас я много использую JAVA. То, что я сделал, и это может быть не лучший случай для всех, но я реализовал свой собственный деструктор, сбросив все значения на 0 или по умолчанию через функцию.

Пример:

public myDestructor() {

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

}

В идеале это не будет работать для всех ситуаций, но там, где есть глобальные переменные, это будет работать, пока у вас их не будет тонны.

Я знаю, что я не лучший программист на Java, но, похоже, мне это помогает.

Старайтесь чаще использовать неизменяемые объекты, после того, как вы их «поймете», все станет более осмысленным :)

R. van Twisk 29.09.2013 07:50

Это не столько неправильно, сколько бессмысленно - т.е. ничего не достигает. Если ваша программа требует, чтобы необработанные типы были сброшены для правильной работы, тогда ваши экземпляры классов имеют неправильную область видимости, что означает, что вы, вероятно, переназначаете свойства существующего объекта на свойства нового объекта, не создавая новый Object ().

simo.3792 08.08.2014 05:01

За исключением того, что требуется множество сбросов переменных. Я выбрал деструктор имени, потому что он подходит для моей работы. Он чего-то добивается, вы ничего не понимаете

ChristianGLong 23.02.2019 19:43

Я согласен с большинством ответов.

Вы не должны полностью полагаться ни на finalize, ни на ShutdownHook.

завершить

  1. JVM не гарантирует, когда будет вызван этот метод finalize().

  2. finalize() вызывается только один раз потоком GC. Если объект восстанавливается после завершения метода, то finalize не будет вызываться снова.

  3. В вашем приложении могут быть некоторые живые объекты, для которых никогда не вызывается сборка мусора.

  4. Любой Exception, выданный методом финализации, игнорируется потоком GC.

  5. Методы System.runFinalization(true) и Runtime.getRuntime().runFinalization(true) увеличивают вероятность вызова метода finalize(), но теперь эти два метода устарели. Эти методы очень опасны из-за отсутствия безопасности потоков и возможного создания взаимоблокировок.

shutdownHooks

public void addShutdownHook(Thread hook)

Registers a new virtual-machine shutdown hook.

Виртуальная машина Java выключается в ответ на два типа событий:

  1. Программа завершается нормально, когда завершается последний поток, не являющийся демоном, или когда вызывается метод выхода (эквивалентно System.exit), или

  2. Виртуальная машина завершает работу в ответ на прерывание пользователя, такое как ввод ^ C, или общесистемное событие, такое как выход пользователя из системы или завершение работы системы.

  3. Ловушка выключения - это просто инициализированный, но не запущенный поток. Когда виртуальная машина начинает свою последовательность выключения, она запускает все зарегистрированные перехватчики выключения в некотором неопределенном порядке и позволяет им работать одновременно. Когда все перехватчики завершены, он запустит все неактивированные финализаторы, если финализация при выходе была включена.

  4. Наконец, виртуальная машина остановится. Обратите внимание, что потоки демона будут продолжать работать во время последовательности завершения работы, как и потоки, не являющиеся демонами, если завершение работы было инициировано вызовом метода выхода.

  5. Крюки отключения также должны быстро завершить свою работу. Когда программа вызывает exit, ожидается, что виртуальная машина сразу же выключится и выйдет.

    Но даже документация Oracle цитирует это

In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly

Это происходит, когда виртуальная машина завершается извне, например, с помощью сигнала SIGKILL в Unix или вызова TerminateProcess в Microsoft Windows. Виртуальная машина также может завершить работу, если собственный метод не работает, например, из-за повреждения внутренних структур данных или попытки доступа к несуществующей памяти. Если виртуальная машина прерывается, то нельзя гарантировать, будут ли запущены какие-либо обработчики завершения работы.

Заключение: используйте блоки try{} catch{} finally{} соответствующим образом и освободите критические ресурсы в блоке finally(}. При освобождении ресурсов в блоке finally{} ловите Exception и Throwable.

Просто подумайте об исходном вопросе ... который, я думаю, мы можем сделать вывод из всех других изученных ответов, а также из существенного Эффективная Java Блоха, пункт 7, «Избегайте финализаторов», ищет решение законного вопроса способом, который является не соответствует языку Java ...:

... не было бы довольно очевидным решением сделать то, что на самом деле хочет OP, - это сохранить все ваши объекты, которые необходимо сбросить, в своего рода «манеж», на который все другие не сбрасываемые объекты имеют ссылки только через какой-то объекта доступа ...

А затем, когда вам нужно «перезагрузить», вы отключаете существующий манеж и создаете новый: вся сеть объектов в манеже отбрасывается по течению, чтобы никогда не возвращаться, и однажды будет собрана сборщиком мусора.

Если какой-либо из этих объектов является Closeable (или нет, но имеет метод close), вы можете поместить их в Bag в манеж по мере их создания (и, возможно, открытия), и последнее действие аксессуара перед отключением манежа будет быть перебирать все закрывающие их Closeables ...?

Код, вероятно, будет выглядеть примерно так:

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

closeCloseables, вероятно, будет методом блокировки, вероятно, с использованием защелки (например, CountdownLatch), для обработки (и ожидания, если это необходимо) любого Runnables / Callables в любых потоках, специфичных для Playpen, которые должны быть завершены соответствующим образом, в частности, в потоке JavaFX .

В Lombok есть аннотация @Cleanup, которая больше всего напоминает деструкторы C++:

@Cleanup
ResourceClass resource = new ResourceClass();

При его обработке (во время компиляции) Lombok вставляет соответствующий блок try-finally, так что resource.close() вызывается, когда выполнение выходит из области видимости переменной. Вы также можете явно указать другой метод для освобождения ресурса, например resource.dispose():

@Cleanup("dispose")
ResourceClass resource = new ResourceClass();

Я вижу преимущество в том, что будет меньше вложенности (что может быть значительным, если у вас много объектов, требующих «разрушения»).

Alexey 30.01.2018 11:42

Блок try-with-resource может иметь несколько ресурсов за один снимок

Alexander 30.01.2018 18:36

Но между ними не может быть инструкций.

Alexey 31.01.2018 09:22

Справедливый. Я полагаю, тогда рекомендуется предпочесть try-with-resource, даже для нескольких ресурсов, если между ними не требуется инструкций, которые вынуждают вас создавать новые блоки try-with-resource (увеличивая вложенность), а затем использовать @Cleanup

Alexander 31.01.2018 18:04

В Java нет точно класса деструктора, класс уничтожается в Java автоматически сборщиком мусора. но вы можете сделать это, используя один ниже, но это не совсем то же самое:

финализировать ()

Был вопрос, который вызвал всестороннее обсуждение финализации, так что при необходимости можно получить больше глубины ...

Здесь много отличных ответов, но есть дополнительная информация о том, почему вам следует избегать использования финализировать ().

Если JVM завершает работу из-за System.exit() или Runtime.getRuntime().exit(), финализаторы не будут запускаться по умолчанию. От Документация Javadoc для Runtime.exit ():

The virtual machine's shutdown sequence consists of two phases. In the first phase all registered shutdown hooks, if any, are started in some unspecified order and allowed to run concurrently until they finish. In the second phase all uninvoked finalizers are run if finalization-on-exit has been enabled. Once this is done the virtual machine halts.

Вы можете вызвать System.runFinalization(), но он делает «все возможное, чтобы завершить все незавершенные финализации» - не гарантия.

Есть метод System.runFinalizersOnExit(), но не используйте его - он небезопасен, давно устарел.

В Java нет деструкторов. Основная причина этого в Java - это сборщики мусора, которые всегда пассивно работают в фоновом режиме, и все объекты создаются в памяти кучи, то есть в том месте, где работает сборщик мусора. должны явно вызывать функцию удаления, поскольку нет такой вещи, как сборщик мусора.

В Java сборщик мусора автоматически удаляет неиспользуемые объекты, чтобы освободить память. Так что разумно, что в Java нет доступных деструкторов.

Другие вопросы по теме