Почему был бы, Вы когда-нибудь реализовывать завершаете ()?

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


Общее правило для размещения typename в основном, когда вы используете параметр шаблона, и хотите получить доступ к вложенному typedef или с использованием псевдонима, например:

template
struct test {
    using type = T; // no typename required
    using underlying_type = typename T::type // typename required
};

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

template
struct test {
    // typename required
    using type = typename std::conditional::type;
    // no typename required
    using integer = std::conditional::type;
};

Общие правила добавления определителя template в основном аналогичны, за исключением они обычно включают шаблонные функции-члены (статические или другие) структуры / класса, которые сами шаблоны, например:

Учитывая эту структуру и функцию:

template
struct test {
    template
    void get() const {
        std::cout << "get\n";
    }
};

template
void func(const test& t) {
    t.get(); // error
}

Попытка доступа t.get() изнутри функции приведет к ошибке:

main.cpp:13:11: error: expected primary-expression before 'int'
     t.get();
           ^
main.cpp:13:11: error: expected ';' before 'int'

Таким образом, в этом контексте вам понадобится ключевое слово template заранее и вызвать его так:

t.template get()

Таким образом, компилятор будет анализировать это правильно, а не t.get < int.

362
задан Spencer Kormos 27 April 2019 в 10:58
поделиться

15 ответов

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

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

Это обеспечивает дополнительную безопасность в исключительной/ошибочной ситуации. Не каждая вызывающая сторона собирается сделать, корректные try {} finally {} наполняют каждый раз. Неудачный, но верный в большинстве сред.

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

я вижу, что с Java 9, Object.finalize() удерживается от использования! Они указывают на нас на java.lang.ref.Cleaner и java.lang.ref.PhantomReference как альтернативы.

221
ответ дан Hearen 23 November 2019 в 00:11
поделиться

Будьте осторожны относительно того, что Вы делаете в finalize(). Особенно при использовании его для вещей как вызов близко (), чтобы гарантировать, что ресурсы очищены. Мы столкнулись с несколькими ситуациями, где нам связали библиотеки JNI в к рабочему коду Java, и при любых обстоятельствах, где мы использовали, завершают () для вызова методов JNI, мы получили бы очень плохое повреждение "кучи" Java. Повреждение не было вызвано самим базовым кодом JNI, все трассировки памяти были прекрасны в собственных библиотеках. Это было просто то, что мы называли методы JNI от завершения () вообще.

Это было с JDK 1.5, который все еще находится в широком употреблении.

Мы не узнали бы, что что-то значительно позже шло не так, как надо, но в конце преступник всегда был завершением () метод, использующий вызовы JNI.

4
ответ дан Hearen 23 November 2019 в 00:11
поделиться

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

драйверы базы данных Many делают это в своих реализациях Оператора и Соединения для обеспечения небольшой безопасности против разработчиков, которые забывают звонить близко на них.

3
ответ дан John Meagher 23 November 2019 в 00:11
поделиться

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

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

4
ответ дан Hearen 23 November 2019 в 00:11
поделиться

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

6
ответ дан Bill the Lizard 23 November 2019 в 00:11
поделиться

finalize() может быть полезным для ловли утечек ресурсов. Если ресурс должен быть закрыт, но не является записью то, что это не было закрыто для файла журнала, и закройте его. Тем путем Вы удаляете утечку ресурсов и даете себе способ знать, что это произошло так, можно зафиксировать его.

я программировал в Java начиная с 1,0 альф 3 (1995), и я должен все же переопределить, завершают для чего-либо...

10
ответ дан Hearen 23 November 2019 в 00:11
поделиться

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

Взгляд на "Ссылочные" классы. Слабая ссылка, Фантомная Ссылка & Мягкая Ссылка.

можно использовать их для хранения ссылки на все объекты, но ОДНА только эта ссылка не остановит GC. Аккуратная вещь об этом - Вы, может иметь его, называют метод, когда это будет удалено, и этот метод может быть , гарантировал , чтобы быть названным.

Что касается завершите: Я использовал, завершают однажды для понимания, какие объекты освобождались. Можно играть в некоторые аккуратные игры с помехами, подсчетом ссылок и таким - но это было только для анализа, но не упустите код как это (не только в, завершают, но и это - то, где Вы, скорее всего, будете видеть его):

public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}

Это - знак, что кто-то не знал то, что они делали. "Чистка" как это никогда не фактически необходима. Когда класс является GC'd, это сделано автоматически.

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

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

Это никогда не должно использоваться для чистки "Более быстрых" вещей.

27
ответ дан Bill K 23 November 2019 в 00:11
поделиться

Я не уверен, что можно сделать из этого, но...

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

, Таким образом, я предполагаю, что Sun нашел [приблизительно 113] случаи, где (они думают), он должен использоваться.

26
ответ дан Hearen 23 November 2019 в 00:11
поделиться

Я делал Java профессионально с 1998, и я никогда не реализовывал finalize(). Не однажды.

34
ответ дан Hearen 23 November 2019 в 00:11
поделиться

Простое правило: никогда не используйте финализаторы.

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

От статья Brian Goetz:

Объекты с финализаторами (те, которые имеют нетривиальное, завершают () метод) имеют значительные издержки по сравнению с объектами без финализаторов и должны использоваться экономно. Объекты Finalizeable и медленнее чтобы выделить и медленнее собраться. Во время выделения JVM должна зарегистрировать любые finalizeable объекты в сборщике "мусора", и (по крайней мере, в реализации HotSpot JVM), finalizeable объекты должны следовать за более медленным путем выделения, чем большинство других объектов. Точно так же finalizeable объекты медленнее для сбора, также. Требуется по крайней мере два цикла сборки "мусора" (в лучшем случае), прежде чем finalizeable объект сможет быть исправлен, и сборщик "мусора" должен сделать дополнительную работу для вызова финализатора. Результатом является больше времени, проведенного, выделяя и собирая объекты и больше давления на сборщик "мусора", потому что память, используемая недостижимыми finalizeable объектами, сохраняется дольше. Объединение, что с тем, что финализаторы, как гарантируют, не будут работать ни в какой предсказуемый период времени, или даже вообще, и Вы видите, что существует относительно немного ситуаций, для которых завершение является правильным инструментом для использования.

54
ответ дан Hearen 23 November 2019 в 00:11
поделиться

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

43
ответ дан skaffman 23 November 2019 в 00:11
поделиться

finalize() подсказка к JVM, что могло бы быть хорошо выполнить Ваш код в неуказанное время. Это хорошо, когда Вы хотите, чтобы коду загадочно не удалось работать.

Выполнение чего-либо значительного в финализаторах (в основном что-либо кроме входа) также хорошо в трех ситуациях:

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

, Если Вы думаете, что Вы должны завершить (), иногда что Вы действительно хотите, фантомная ссылка (который в данном примере мог содержать твердую ссылку на соединение, используемое его referand, и закрыть его после того, как фантомная ссылка была поставлена в очередь). Это также имеет свойство, которое это никогда не может загадочно выполнять, но по крайней мере это не может обратиться к методам или возродить завершенные объекты. Таким образом, просто правильно для ситуаций, где Вы не должны абсолютно закрывать то соединение чисто, но вполне требуется, и клиенты класса не могут или не называть себя близко (который достаточно на самом деле справедлив - какой смысл того, чтобы иметь сборщик "мусора" вообще, если Вы разрабатываете интерфейсы, которые требуют , определенные меры приняты до набора? Это просто откладывает нас в эпоху malloc/free.)

Другие времена Вам нужен ресурс, Вы думаете, что Вам удается быть более устойчивыми. Например, почему необходимо закрыть то соединение? Это должно в конечном счете быть основано на некотором вводе-выводе, обеспеченном системой (сокет, файл, безотносительно), итак, почему Вы не можете полагаться на систему для закрытия его для Вас, когда самый низкий уровень ресурса является gced? Если сервер в другом конце абсолютно требует, чтобы Вы закрыли соединение чисто вместо того, чтобы просто отбросить сокет, то, что собирается произойти, когда кто-то спотыкается за силовой кабель машины, Ваш код работает, или прошедшая сеть выходит?

Правовая оговорка: я работал над реализацией JVM в прошлом. Я ненавижу финализаторы.

167
ответ дан Hearen 23 November 2019 в 00:11
поделиться

Выделить точку в вышеупомянутых ответах: финализаторы будут выполняться на одиноком потоке GC. Я услышал о главной демонстрации Sun, где разработчики добавили маленький сон к некоторым финализаторам и намеренно принесли в других отношениях необычную 3D демонстрацию к ее коленям.

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

Взгляды Eckel в Java имеют хороший раздел на этом.

5
ответ дан Michael Easter 23 November 2019 в 00:11
поделиться
class MyObject {
    Test main;

    public MyObject(Test t) {    
        main = t; 
    }

    protected void finalize() {
        main.ref = this; // let instance become reachable again
        System.out.println("This is finalize"); //test finalize run only once
    }
}

class Test {
    MyObject ref;

    public static void main(String[] args) {
        Test test = new Test();
        test.ref = new MyObject(test);
        test.ref = null; //MyObject become unreachable,finalize will be invoked
        System.gc(); 
        if (test.ref != null) System.out.println("MyObject still alive!");  
    }
}

======================================

результат :

This is finalize

MyObject still alive!

=====================================

Таким образом, вы можете сделать недоступным экземпляр доступен в методе finalize.

21
ответ дан 23 November 2019 в 00:11
поделиться

Редактировать: Хорошо, это действительно не работает. Я реализовал его и подумал, что если иногда он выходит из строя, это нормально для меня, но он даже не вызвал метод finalize ни разу.

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

@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}
2
ответ дан 23 November 2019 в 00:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: