Как убедиться, что в JVM есть только один экземпляр класса?
Я разрабатываю шаблон дизайна, и я хочу убедиться, что это всего лишь один экземпляр класса в виртуальной машине Java, чтобы направить все запросы на какой-либо ресурс через одну точку, но я не знаю, возможно.
Я могу только думать о способе подсчета экземпляров класса и уничтожить весь экземпляр после его создания.
Это правильный подход? Если нет, есть ли другой способ?
Ответы
Ответ 1
Используйте шаблон singleton. Простейшая реализация состоит из private constructor
и field
для хранения ее результата и метода доступа static
с таким именем, как getInstance()
.
Частное поле может быть назначено из статического блока инициализатора или, проще говоря, с помощью инициализатора. Метод getInstance()
(который должен быть общедоступным) затем просто возвращает этот экземпляр,
public class Singleton {
private static Singleton instance;
/**
* A private Constructor prevents any other class from
* instantiating.
*/
private Singleton() {
// nothing to do this time
}
/**
* The Static initializer constructs the instance at class
* loading time; this is to simulate a more involved
* construction process (it it were really simple, you'd just
* use an initializer)
*/
static {
instance = new Singleton();
}
/** Static 'instance' method */
public static Singleton getInstance() {
return instance;
}
// other methods protected by singleton-ness would be here...
/** A simple demo method */
public String demoMethod() {
return "demo";
}
}
Обратите внимание, что метод использования "ленивой оценки" в методе getInstance()
(который
пропагандируется в шаблонах проектирования), не требуется в Java, потому что Java уже использует "ленивый
загрузка. "Ваш одноэлементный класс, вероятно, не загрузится, если его getInstance()
, поэтому нет смысла пытаться отложить построение синглтона до его необходимого
с помощью getInstance()
проверить одиночную переменную для null
и создать синглтон
есть.
Использование этого класса одинаково просто: просто получите и сохраните ссылку и вызовите на ней методы:
public class SingletonDemo {
public static void main(String[] args) {
Singleton tmp = Singleton.getInstance();
tmp.demoMethod();
}
}
Некоторые комментаторы считают, что синглтон должен также предоставить публичный финал
clone()
, который просто генерирует исключение, чтобы избежать подклассов, которые "обманывают" и
clone()
синглтон. Однако ясно, что класс с только частным конструктором
не может быть подклассом, поэтому эта паранойя не представляется необходимой.
Ответ 2
Вам нужен шаблон Singleton
. Существует отличная дискуссия о том, как правильно это реализовать. Если вы сделаете это правильно, будет только один экземпляр класса.
По существу, вы должны создать класс, провести один экземпляр объекта этого класса на статическом уровне и предоставить статический аксессор для его получения (getInstance()
или аналогичный). Сделайте конструктор окончательным, чтобы люди не могли создавать свои собственные экземпляры из синего. Эта ссылка выше содержит множество замечательных советов о том, как это сделать.
Ответ 3
Существует школа мысли, которая рассматривает шаблон Singleton на самом деле как анти-шаблон.
Учитывая класс A, в котором вы только желаете, есть альтернатива - иметь класс builder или factory, который сам ограничивает создание числа объектов класса A, и это может быть простым счетчик.
Преимущество состоит в том, что классу A больше не нужно беспокоиться об этом, он концентрируется на своей реальной цели. Каждый класс, который его использует, больше не должен беспокоиться о том, что он является одним из них (не более вызовов getInstance()).
Ответ 4
Это хорошо известный шаблон Singleton: вы можете реализовать это следующим образом:
public class SingletonClass {
//this field contains the single instance every initialized.
private static final instance = new SingletonClass();
//constructor *must* be private, otherwise other classes can make an instance as well
private SingletonClass () {
//initialize
}
//this is the method to obtain the single instance
public static SingletonClass getInstance () {
return instance;
}
}
Затем вы вызываете экземпляр (например, вы создаете не одиночный элемент) с помощью:
SingletonClass.getInstance();
Но в литературе синглтон обычно считается плохой дизайнерской идеей. Конечно, это всегда зависит от ситуации, но большинство программистов советуют против этого. Только говоря это, не стреляй в посланника...
Ответ 5
Использовать перечисление. В Java перечисление - единственный верный способ создания singleton. Частные конструкторы могут быть все еще вызваны через отражение.
См. этот вопрос StackOverflow для получения дополнительной информации:
Реализация Singleton с Enum (на Java)
Обсуждение:
http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html
Ответ 6
Я могу только думать о способе подсчета экземпляров класса и уничтожить все экземпляры после их создания. Правильно ли это? Если нет, есть ли другой способ?
Правильный технический подход состоит в том, чтобы объявить все конструкторы для класса как private
, чтобы экземпляры класса могли создаваться только самим классом. Затем вы кодируете класс только когда-либо создаете один экземпляр.
Другие ответы показывают некоторые способы реализации этого, в соответствии с шаблоном проектирования "Singleton". Тем не менее, реализация такого сингла, как это имеет некоторые недостатки, в том числе сделать значительно сложнее писать модульные тесты.
Ответ 7
Я предпочитаю ленивый одноэлементный класс, который переопределяет метод readResolve.
Для классов Serializable и Externalizable метод readResolve позволяет классу заменять/разрешать объект, считанный из потока, прежде чем он будет возвращен вызывающему. Внедряя метод readResolve, класс может напрямую контролировать типы и экземпляры своих дескрипторов своих экземпляров.
Lazy singleton с помощью /Initialization-on-demand_holder_idiom:
public final class LazySingleton {
private LazySingleton() {}
public static LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
private Object readResolve() {
return LazyHolder.INSTANCE;
}
}
Ключевые примечания:
-
final
ключевое слово запрещает расширение этого класса путем подклассификации
Конструктор -
private
запрещает создание прямого объекта с помощью оператора new
в классах вызывающего абонента
-
readResolve
запрещает создание нескольких экземпляров класса во время де-сериализации объекта
Ответ 8
Для этого вам нужно использовать singleton pattern, я просто размещаю демо-код для того, что может быть полезно для вашего понимания.
Например: если мне нужен только один объект для этого класса Connect
:
public final class Connect {
private Connect() {}
private volatile static Connect connect = null;
public static Connect getinstance() {
if(connect == null) {
synchronized (Connect.class) {
connect = new Connect();
}
}
return connect;
}
}
Здесь конструктор является закрытым, поэтому никто не может использовать ключевое слово new
для создания нового экземпляра.
Ответ 9
class A{
private A(){
}
public static A creator(A obj){
A ob=new A();
return ob;
}
void test(){
System.out.println("The method is called");
}
}
class Demo{
public static void main(String[] args){
A ob=null;
ob=A.creator(ob);
ob.test();
}
}