Java финализатор Guardian, кажется, не работает? - PullRequest
5 голосов
/ 12 августа 2011

У меня есть суперкласс с телескопическими конструкторами с методом finalize (). Для защиты от подклассов, забывших вызывать super.finalize, я написал опекуна финализатора (EJ Item 7) примерно так:

public class Super {

    public Super() {}

    {
        Object finalizerGuardian = new Object() {
            @Override
            protected void finalize() {
                System.out.println("Finalizer guardian finalize");
                Super.this.finalize();
            }
        };
    }

    protected void finalize() {
        System.out.println("Super finalize");
    }

}

Вот пример подкласса -

public class Sub extends Super {

    public Sub() {}

    protected void finalize() {
        System.out.println("Sub finalize");
    }

    public static void main(String[] args)
            throws InterruptedException {
        if (1 == 1) {
            Sub s1 = new Sub();
        }
        Runtime.getRuntime().gc();
        Thread.sleep(10000);
    }
}

Когда объект s1 выходит из области видимости, вызывается finalize () хранителя финализатора, и я получаю SYSO из метода finalize подкласса, но никогда не получаю тот из финализатора super.

Я в замешательстве. Я неправильно понимаю что-то принципиально?

Отказ от ответственности : я понимаю, что финализаторы опасны и не рекомендуется, и т. Д. Все еще пытаюсь понять проблему здесь.

Ответы [ 4 ]

8 голосов
/ 12 августа 2011

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

Также обратите внимание, что хранителем финализатора должно быть поле класса:

public class Super {
    private final Object finalizerGuardian = new Object() {
            @Override
            protected void finalize() {
                Super.this.doFinalize();
            }
    };

    private void doFinalize() {
        System.out.println("Super finalize");
    }
}
2 голосов
/ 12 августа 2011

Super.finalize() не вызывается, потому что Sub переопределяет его.Попробуйте добавить метод Super._finalize() и вызвать его из Super.finalize() и хранителя финализатора.

Кроме того, я думаю, что finalizerGuardian должно быть полем Super.В противном случае он может собирать мусор, даже если объект Super по-прежнему доступен.

2 голосов
/ 12 августа 2011

Как уже говорили, динамическая отправка - ваша проблема здесь. НО, насколько я вижу, в вашем коде есть еще одна серьезная ошибка: ваш finalizerGuardian определяется только внутри блока инициализации, это означает, что как только объект инициализируется, объект выходит из области видимости и может быть GCed.

Т.е. даже если вы исправите свою первую проблему (определив последний метод в своем классе, который обрабатывает материал завершения), вам все равно нужно сохранить finalizerGuardian в переменной экземпляра.

2 голосов
/ 12 августа 2011

Вы перегружаете метод Super.finalize() в Sub.Вот почему это не называется.

Таким образом, когда вы звоните "finalizerGuardian" Super.this.finalize();, вы на самом деле звоните Sub.finalize().

...