Java单例模式的7种写法中,为何用Enum枚举实现被认为是最好的方式?【享学Java】(下)

简介: Java单例模式的7种写法中,为何用Enum枚举实现被认为是最好的方式?【享学Java】(下)

这个看起来是因为没有空的构造函数导致的,还并不能下定义说防御了反射攻击。那它有什么构造函数呢,可以看它的父类Enum类:


// @since   1.5  它是所有Enum类的父类,是个抽象类
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
  // 这是它的唯一构造函数,接收两个参数(若没有自己额外指定构造函数的话~)
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
    ...
}


既然它有这个构造函数,那我们就先拿到这个构造函数再创建对象试试:


public class Main {
    public static void main(String[] args) throws Exception {
        EnumSingleton s = EnumSingleton.INSTANCE;
        // 拿到所有的构造函数,包括非public的
        Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class);// 拿到有参的构造器
        constructor.setAccessible(true);
        // 使用空构造函数new一个实例。即使它是private的~~~
        System.out.println("拿到了构造器:" + constructor);
        EnumSingleton sReflection = constructor.newInstance("testInstance", 1);
        System.out.println(s); //com.fsx.bean.Singleton@1f32e575
        System.out.println(sReflection); //com.fsx.bean.Singleton@279f2327
        System.out.println(s == sReflection); // false
    }
}


运行打印:

拿到了构造器:private com.fsx.bean.EnumSingleton(java.lang.String,int)
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
  at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
  at com.fsx.maintest.Main.main(Main.java:22)


第一句输出了,表示我们是成功拿到了构造器Constructor对象的,只是在执行newInstance时候报错了。并且也提示报错在Constructor的417行,看看Constructor的源码处:


public final class Constructor<T> extends Executable {
  ...
    public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    ...
        if ((clazz.getModifiers() & Modifier.ENUM) != 0)
            throw new IllegalArgumentException("Cannot reflectively create enum objects");
    ...
  }
  ...
}


主要是这一句:(clazz.getModifiers() & Modifier.ENUM) != 0。说明:反射在通过newInstance创建对象时,会检查该类**是否ENUM修饰**,如果是则抛出异常,反射失败,因此枚举类型对反射是绝对安全的。


那么,枚举对序列化、反序列化是否安全?


public class Main {
    public static void main(String[] args) {
        EnumSingleton s = EnumSingleton.INSTANCE;
        byte[] serialize = SerializationUtils.serialize(s);
        Object deserialize = SerializationUtils.deserialize(serialize);
        System.out.println(s == deserialize); //true
    }
}


结果是:true。因此:枚举类型对序列化、反序列也是安全的。


综上,可以得出结论:枚举是实现单例模式的最佳实践。毕竟使用它全都是优点:


  1. 反射安全
  2. 序列化/反序列化安全
  3. 写法简单
  4. 没有一个更有信服力的原因不去使用枚举


附:局变量比单例模式差在哪里?

  1. 不可延迟实例化
  2. 不能保证全局只有一个实例(因为使用者都可以自己new对象)


总结



单例模式作为最为简单的一种设计模式,可以说是用到了everywhere,它不仅仅是我们撸码中肯定会用到的,更是面必问的一道题。我相信你理解了本文之后,以后不管使用和面试,都能轻松应对~

相关文章
|
22天前
|
设计模式 安全 Java
Java编程中的单例模式:理解与实践
【10月更文挑战第31天】在Java的世界里,单例模式是一种优雅的解决方案,它确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的实现方式、使用场景及其优缺点,同时提供代码示例以加深理解。无论你是Java新手还是有经验的开发者,掌握单例模式都将是你技能库中的宝贵财富。
30 2
|
2月前
|
设计模式 安全 Java
Java编程中的单例模式深入剖析
【10月更文挑战第21天】在Java的世界里,单例模式是设计模式中一个常见而又强大的存在。它确保了一个类只有一个实例,并提供一个全局访问点。本文将深入探讨如何正确实现单例模式,包括常见的实现方式、优缺点分析以及最佳实践,同时也会通过实际代码示例来加深理解。无论你是Java新手还是资深开发者,这篇文章都将为你提供宝贵的见解和技巧。
96 65
|
29天前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
104 60
|
22天前
|
设计模式 安全 Java
Java编程中的单例模式深入解析
【10月更文挑战第31天】在编程世界中,设计模式就像是建筑中的蓝图,它们定义了解决常见问题的最佳实践。本文将通过浅显易懂的语言带你深入了解Java中广泛应用的单例模式,并展示如何实现它。
|
3月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
66 9
Java——反射&枚举
|
29天前
|
设计模式 SQL 安全
Java编程中的单例模式深入解析
【10月更文挑战第24天】在软件工程中,单例模式是设计模式的一种,它确保一个类只有一个实例,并提供一个全局访问点。本文将探讨如何在Java中使用单例模式,并分析其优缺点以及适用场景。
14 0
|
2月前
|
SQL 设计模式 Java
[Java]单例模式
本文介绍了单例模式的概念及其实现方式,包括饿汉式和懒汉式两种形式,并详细探讨了懒汉式中可能出现的线程安全问题及其解决方案,如锁方法、锁代码块和双重检查锁(DCL)。文章通过示例代码帮助读者更好地理解和应用单例模式。
30 0
|
3月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
86 5
|
3月前
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
42 11
|
3月前
|
安全 Java 开发者
Java 枚举(enum)详解
Java 中的枚举(`enum`)是一种特殊的数据类型,用于定义一组固定的常量,提升代码的类型安全性和可读性。枚举使用 `enum` 关键字定义,支持方法和构造函数,具有类型安全、单例、自动序列化等特点,并且可以遍历和用于 `switch` 语句中。实际应用包括状态机、指令集、类型标识等场景。枚举使代码更加清晰易维护。