Java枚举实现单例模式原理

单例的枚举实现在《Effective Java》中有提到,因为其功能完整、使用简洁、无偿地提供了序列化机制、在面对复杂的序列化或者反射攻击时仍然可以绝对防止多次实例化等优点,单例的枚举类型被作者认为是实现Singleton的最佳方法。

其实现非常简单,如下:

public enum Singleton {
    INSTANCE;
    private Singleton() {}
}

举例

我们用一个枚举实现单个数据源例子来简单验证一下:声明一个枚举,用于获取数据库连接。

public enum DataSourceEnum {
    DATASOURCE;
    private DBConnection connection = null;
    private DataSourceEnum() {
        connection = new DBConnection();
    }
    public DBConnection getConnection() {
        return connection;
    }
}  

模拟一个数据库连接类:

public class DBConnection {} 

测试通过枚举获取的实例是否相同:

 public class Main {
    public static void main(String[] args) {
        DBConnection con1 = DataSourceEnum.DATASOURCE.getConnection();
        DBConnection con2 = DataSourceEnum.DATASOURCE.getConnection();
        System.out.println(con1 == con2);
    }
}

输出结果为:true  结果表明两次获取返回了相同的实例。

分析

下面深入了解一下为什么枚举会满足线程安全、序列化等标准。

在JDK5 中提供了大量的语法糖,枚举就是其中一种。
所谓 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是但是更方便程序员使用。只是在编译器上做了手脚,却没有提供对应的指令集来处理它。

// 首先

public enum SingletonEnum{
                SINGLETON;
            }  

// 的实质是:

public enum SingletonEnum{
                SINGLETON;
                ......
                private SingletonEnum(){......}
            }  

Enum其实就是一个普通的类,它继承自java.lang.Enum类。

public enum DataSourceEnum {
    DATASOURCE;
}  

把上面枚举编译后的字节码反编译,得到的代码如下:

public final class DataSourceEnum extends Enum<DataSourceEnum> {
      public static final DataSourceEnum DATASOURCE;
      public static DataSourceEnum[] values();
      public static DataSourceEnum valueOf(String s);
      static {};
}

由反编译后的代码可知,DATASOURCE 被声明为 static 的,根据在 单例模式-饿汉式与类加载 中所描述的类加载过程,可以知道虚拟机会保证一个类的<clinit>() 方法在多线程环境中被正确的加锁、同步。所以,枚举实现是在实例化时是线程安全。

接下来看看序列化问题:

Java规范中规定,每一个枚举类型及其定义的枚举变量在JVM中都是唯一的,因此在枚举类型的序列化和反序列化上,Java做了特殊的规定。

在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过 java.lang.Enum 的 valueOf() 方法来根据名字查找枚举对象。

也就是说,以下面枚举为例,序列化的时候只将 DATASOURCE 这个名称输出,反序列化的时候再通过这个名称,查找对于的枚举类型,因此反序列化后的实例也会和之前被序列化的对象实例相同。

public enum DataSourceEnum {
    DATASOURCE;
}  

由此可知,枚举天生保证序列化单例。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Java实现Elasticsearch的简单应用,你需要先添加Elasticsearch的Java客户端库(例如Elasticsearch Java High Level REST Client)到你的项目中。然后,你可以使用该客户端库来连接到Elasticsearch集群并执行索引、搜索和聚合等操作。 以下是一个简单的示例,展示了如何使用Java High Level REST Client来实现Elasticsearch的基本操作: 1. 添加Maven依赖: ```xml <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.15.1</version> </dependency> ``` 2. 创建Elasticsearch客户端: ```java RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); ``` 3. 创建索引: ```java CreateIndexRequest request = new CreateIndexRequest("my_index"); request.mapping("_doc", " {\n" + " \"properties\": {\n" + " \"title\": {\n" + " \"type\": \"text\"\n" + " },\n" + " \"content\": {\n" + " \"type\": \"text\"\n" + " }\n" + " }\n" + " }", XContentType.JSON); CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); ``` 4. 索引文档: ```java IndexRequest request = new IndexRequest("my_index"); request.id("1"); request.source( " {\n" + " \"title\": \"Elasticsearch Introduction\",\n" + " \"content\": \"Elasticsearch is a distributed search engine.\"\n" + " }", XContentType.JSON); IndexResponse response = client.index(request, RequestOptions.DEFAULT); ``` 5. 搜索文档: ```java SearchRequest request = new SearchRequest("my_index"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.matchQuery("content", "distributed")); request.source(sourceBuilder); SearchResponse response = client.search(request, RequestOptions.DEFAULT); ``` 以上是一个简单的Java示例,演示了如何使用Java High Level REST Client来实现Elasticsearch的索引和搜索操作。你可以根据自己的需求进一步学习和了解Elasticsearch的其他功能和用法。 关于枚举实现单例模式的问题,以下是一个Java中使用枚举实现单例模式的示例: ```java public enum Singleton { INSTANCE; // 添加其他成员变量和方法 public void doSomething() { // 单例对象的操作 } } ``` 在这个示例中,我们定义了一个枚举类Singleton,它只有一个枚举实例INSTANCE。你可以在枚举类中添加其他成员变量和方法来实现单例对象的操作。通过访问Singleton.INSTANCE,你可以获取到单例对象的实例,并调用其方法。 这种方式是Java中推荐的实现单例模式的方式之一,它保证了线程安全和唯一实例性质。同时,枚举类还提供了序列化和反序列化的支持,避免了反射和反序列化创建新的实例。因此,使用枚举实现单例模式是一种简洁、安全且可靠的方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值