Назначьте "this" частному полю в конструкторе - PullRequest
1 голос
/ 19 июня 2020

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

public class Foo {

    private static Foo INSTANCE;

    private Foo() {
        INSTANCE = this;
    }
}

Я предполагаю, что во время объявления this не полностью инициализирован, поэтому это небезопасно, как если бы любой другой вызов будет использовать поле static, он может найти экземпляр, который не полностью инициализирован.

Это правда? Этого следует избегать? Если да, то почему? Есть ли способ убедиться, что эти вызовы безопасны (поскольку мы больше не используем INSTANCE в конструкторе)?

Ответы [ 3 ]

6 голосов
/ 19 июня 2020

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

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

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

Реализации Singleton в Java уже подробно обсуждались. Не должно быть никаких реальных причин, по которым вы должны придумывать свои собственные, кроме как в качестве упражнения.

См. Пункт 3 Jo sh Bloch's Effective Java, выдержки из которого здесь: Каков эффективный способ реализации одноэлементного шаблона в Java? (хотя я бы посоветовал прочитать всю книгу)

0 голосов
/ 19 июня 2020

Один из способов избежать утечки this в конструкторе - использовать фабричный метод stati c. Кроме того, как указал Майкл, INSTANCE должен быть изменчивым.

public class Foo {

    private static volatile Foo INSTANCE;

    private Foo() {
        // ...
    }

    private static Foo create() {
        // This should probably be synchronized for atomicity
        // but that's for another question
        Foo newInstance = new Foo();
        INSTANCE = newInstance;
        return newInstance;
    }
}

Обратите внимание, что это не синглтон и не исходный код.

0 голосов
/ 19 июня 2020

Это определенно не классическая c ссылка на себя, потому что вы используете переменную stati c. Поэтому я пропущу формулировку classi c для ссылок на себя.

То, что вы делаете, - это то, что вы сохраняете ссылку на последний созданный объект. Одним из вариантов использования будет, например, что-то вроде этого:

public class Users {
   private static Users LAST_USER = null;
   ...
   private Users() {
       LAST_USER = this;
       ...
   }
}

Таким образом, в переменной stati c вы сохраняете ссылку на последнего пользователя и можете в конечном итоге напечатать его имя на странице (X только что зарегистрирован в) или что-то в этом роде. В качестве примера звучит неплохо?

Будет ли работать? Да, будет.

Но хорошо ли? Это действительно зависит от того, что вы делаете с этими объектами. Если он собирается жить «вечно», тогда хорошо. Но как насчет того, чтобы вы sh «удаляли» объекты (например, в моем примере последний пользователь выходит из системы сразу после входа в систему)? Он выйдет из строя сразу, как лог c и полезность - это создаст больше хлопот для решения таких простых случаев, чем поможет.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...