前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Effective Java 2.0_中文版_Item 3

Effective Java 2.0_中文版_Item 3

作者头像
Tyan
发布2022-05-09 08:29:11
2740
发布2022-05-09 08:29:11
举报
文章被收录于专栏:SnailTyanSnailTyan

文章作者:Tyan 博客:noahsnail.com  |  CSDN  |  简书

Item 3 用私有构造函数或枚举类型强化单例属性

单例简单来说就是一个类只被实例化一次[Gamma95, p. 127]。通常单例表示一个系统组件在本质上来说是唯一的,例如窗口管理或文件系统。一个类成为单例会使它的客户端测试变得很困难,因为不可能用伪实现来代替单例,除非它实现了一个接口,这个接口作为它的服务类型。

在1.5版本之前,有两种方式来实现单例。它们都是通过保持私有构造函数并输出一个公有静态成员来提供对类唯一实例的访问来实现的。在第一种方法中,公有静态成员被声明为final字段:

代码语言:javascript
复制
   // Singleton with public final field
   public class Elvis {
       public static final Elvis INSTANCE = new Elvis();
       private Elvis() { ... }
       public void leaveTheBuilding() { ... }
   }

为了初始化公有静态final变量Elvis.INSTANCE,私有构造函数只调用一次。公有或保护构造函数的缺失保证了全局唯一性:确切的说一旦Elvis类初始化,将只有一个Elvis实例存在——不会多也不会少。客户端不能改变这个情况,但要提醒一点:有特权的客户端可以借用AccessibleObject.setAccessible方法方法,通过反射机制(Item 53)的调用私有构造函数。如果你需要抵御这种攻击,修改构造函数使它在创建第二个实例时抛出异常。

代码语言:javascript
复制
// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis(); private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }
    public void leaveTheBuilding() { ... }
}

所有Elvis.getInstance方法的调用都会返回同一个对象实例,并且不会有其它的Elvis实例被创建(提醒同上)。

公有变量方法的主要优势在于更清晰的声明这个类是一个单例类:公有静态变量是final的,因此它总是包含同一个对象的引用。公有变量方法没有任何性能优势:现代Java虚拟机(JVM)的大多数实现都是将静态工厂方法当做内联函数来调用。

为了使上面方法实现的单例类可序列化(第11章),仅仅在它的声明中实现Serializable接口是不够的。为了保证单例性,你必须将所有的实例变量声明为transient并提供一个readResolve方法(Item 77)。否则,每次一个序列化的实例在反序列化时将会创建一个新的实例,在我们的例子中,会看到一个假的Elvis。为了防止这种情况发生,要在Elvis类中添加readResolve方法:

代码语言:javascript
复制
// readResolve method to preserve singleton property
   private Object readResolve() {
        // Return the one true Elvis and let the garbage collector
        // take care of the Elvis impersonator.
       return INSTANCE;
   }

在1.5版本中,有第三种实现单例的方法。简单声明一个只有一个元素的枚举类型:

代码语言:javascript
复制
// Enum singleton - the preferred approach
   public enum Elvis {
       INSTANCE;
       public void leaveTheBuilding() { ... }
   }

这个方法除了它更简洁之外,它在功能上等价于公有变量方法,免费提供了序列化机制,并且强有力的保证了不会被多次实例化,即使是在面临复杂的序列化或反射攻击时。虽然这个方法仍没有被广泛采用,但单元素的枚举类型是实现单例的最好方式

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Item 3 用私有构造函数或枚举类型强化单例属性
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档