java中的单例

我只需要在某处阅读以下代码:
public class SingletonObjectDemo {

    private static SingletonObjectDemo singletonObject;
    // Note that the constructor is private
    private SingletonObjectDemo() {
        // Optional Code
    }
    public static SingletonObjectDemo getSingletonObject() {
        if (singletonObject == null) {
            singletonObject = new SingletonObjectDemo();
       }
       return singletonObject;
    }
}
我需要知道这部分需要什么:
if (singletonObject == null) {
    singletonObject = new SingletonObjectDemo();
}
如果我们不使用这部分代码怎么办?仍然会有一个
SingletonObjectDemo
的副本,为什么我们需要这个代码呢?     
已邀请:
该类有一个字段
SingletonObjectDemo singletonObject
,用于保存单例实例。现在有两种可能的策略 - 1 - 您使用声明急切初始化对象 -
private static SingletonObjectDemo singletonObject = new SingletonObjectDemo();
这将导致您的单例对象在加载类时被初始化。这个策略的缺点是,如果你有很多单身人士,他们都会被初始化并占用记忆,即使他们还不需要。 2 - 你做对象的延迟初始化,即在第一次调用
getSingletonObject()
时初始化它 -
// note that this initializes the object to null by default
private static SingletonObjectDemo singletonObject;
...
if (singletonObject == null) {
        singletonObject = new SingletonObjectDemo();
    }
这样可以节省内存,直到真正需要单例。这种策略的缺点是方法的第一次调用可能会看到稍微差一点的响应时间,因为它必须在返回之前初始化obejct。     
在懒惰与急切初始化
if
语句是延迟初始化技术的实现。 更明确的版本如下:
private boolean firstTime = true;
private Stuff stuff;

public Stuff gimmeStuff() {
   if (firstTime) {
      firstTime = false;
      stuff = new Stuff();
   }
   return stuff;
}
会发生的事情是,第一次调用
gimmeStuff()
firstTime
将是
true
,所以
stuff
将被初始化为
new Stuff()
。在随后的调用中,
firstTime
将是
false
,因此
new Stuff()
将不再被调用。 因此,
stuff
被“懒惰地”初始化。直到它第一次需要它才真正初始化。 也可以看看 维基百科/懒惰初始化 维基百科/初始化按需持有人的习惯用语 关于线程安全 需要说的是,代码片段不是线程安全的。如果有多个线程,那么在某些竞争条件下,可以多次调用
new SingletonObjectDemo()
。 一种解决方案是制作
synchronized getSingletonObject()
方法。但是,这对所有对ѭ5的调用都有同步开销。然后使用所谓的双重检查锁定习惯来试图解决这个问题,但在Java中,这个习惯用法在J2SE 5.0中实际上不起作用,在新的内存模型中引入了
volatile
关键字。 毋庸置疑,单身模式的正确执行并非易事。 也可以看看 developerWorks / Java:双重检查锁定和Singleton模式 - 全面了解这种破解的编程习惯用法 维基百科/双重检查锁定 相关问题  synchronized block vs synchronized方法? 有效的Java第二版 以下是本书对这些主题的看法: 第71项:明智地使用延迟初始化   与大多数优化一样,延迟初始化的最佳建议是“除非你需要,否则不要这样做”。懒惰的初始化是一把双刃剑。它降低了初始化类或创建实例的成本,但代价是增加了访问延迟初始化字段的成本。根据延迟初始化字段最终需要初始化的部分,初始化它们的成本以及访问每个字段的频率,延迟初始化(就像许多“优化”实际上会损害性能)。      在存在多个线程的情况下,延迟初始化很棘手。如果两个或多个线程共享一个延迟初始化的字段,则必须采用某种形式的同步,否则可能导致严重的错误。      在大多数情况下,正常初始化优于延迟初始化。 第3项:使用私有构造函数或
enum
类型强制执行单例属性   截至1.5发布。实施单例的第三种方法。只需使用一个元素创建一个枚举类型。 [...]这种方法在功能上等同于
public
字段方法,除了它更简洁,提供免费的序列化机制,并提供针对多个实例化的铁定保证,即使面对复杂的序列化或基于反射的攻击。      [...]单元素枚举类型是实现单例的最佳方式。 相关问题 在
enum
单例/ Java实现:  在Java中实现单例模式的有效方法  Java Enum Singleton  比较Java枚举成员:==或equals()? Singleton中的线程安全性 关于单身模式的优点和替代方案: 关于设计模式:何时使用Singleton? 编程中单例的目的  单身人士真是太糟糕了  单身人士:好的设计还是拐杖?  什么是单身人士的替代品  Singleton:如何使用它     
如果我们不使用这部分代码怎么办?仍然会有SingletonObjectDemo的单个副本,为什么我们需要这个代码呢? 想法是懒惰加载单例,即仅在实际需要时加载实例。你为什么想这么做?好吧,Bob Lee在Lazy Loading Singletons中很好地总结了这个:   在生产中,您通常需要急切地加载所有单例,以便及早发现错误并预先考虑任何性能,但在测试和开发过程中,您只想加载您绝对需要的内容,以免浪费时间。 但是你显示的实现被破坏了,它不是线程安全的,两个并发线程实际上可以创建两个实例。使延迟加载单例线程安全的最佳方法是使用Initialization on Demand Holder(IODH)习语,这非常简单并且没有同步开销。引用有效的Java,第71项:明智地使用延迟初始化(强调不是我的):   如果你需要使用延迟初始化来提高性能   静态字段,使用懒惰   初始化持有者类成语。   这个成语(也称为   初始化按需持有者类成语)利用a的保证   class直到它才会被初始化   使用[JLS,12.4.1]。这是怎么回事   外观:
// Lazy initialization holder class idiom for static fields
private static class FieldHolder {
    static final FieldType field = computeFieldValue();
}
static FieldType getField() { return FieldHolder.field; }
     调用
getField
方法时   这是第一次   
FieldHolder.field
为第一个   时间,造成
FieldHolder
级   初始化。这个美丽   成语是
getField
方法   没有同步,只执行一个   字段访问,所以延迟初始化   几乎没有增加成本   访问。一个现代的VM将   仅对字段访问进行同步   初始化课程。一旦上课   初始化后,VM将修补   代码使后续访问   字段不涉及任何测试或   同步。 也可以看看 第66项:同步对共享可变数据的访问 - Effective Java 2nd edition 第71项:明智地使用延迟初始化 - 有效的Java第2版 新内存模型是否修复了“双重检查锁定”问题?     
2行检查是否创建了唯一的单例,如果不是,则创建单例实例。如果实例确实存在,则不会执行任何操作并返回该实例。单例实例是在第一次按需需要时创建的,而不是在应用程序初始化时创建的。 请注意,您的代码包含竞争条件错误。当2个线程同时进入时,单个对象可以被分配两次。这可以通过同步方法来解决,如下所示:
public static synchronized SingletonObjectDemo getSingletonObject() {
    if (singletonObject == null) {
        singletonObject = new SingletonObjectDemo();
    }
    return singletonObject;
}
顺便说一句,回到你的问题,行:
private static SingletonObjectDemo singletonObject;
声明一个静态引用,但它不会实际分配一个实例,Java编译器将引用设置为
null
。     
给定的类在请求之前不会创建对象的第一个实例。在第一个请求之前,
private static
字段是
null
,然后构造对象的实例并将其存储在那里。后续请求返回相同的对象。 如果你删除这两行代码,你将永远不会真正创建初始实例,所以你总是会返回
null
。     
这段代码 负责创建第一个对象 防止创建另一个     
首先,singletonObject设置为null。单例背后的想法是在有人调用getSingletonObject()时第一次初始化该对象。如果不在该部分中调用构造函数,则变量将始终为null。     

要回复问题请先登录注册