设计模式之单例模式(Java实现)(二)

简介: 设计模式之单例模式(Java实现)(二)

三、枚举类实现单例(解决反射安全问题)


查看源码


为什么我们通过使用枚举类能够实现单例呢?


通过看反射方法newInstance()(Constructor类)的源码。
@CallerSensitive
public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, null, modifiers);
        }
    }
    //如果是枚举类型直接,直接抛出异常,不让创建实例对象
    if ((clazz.getModifiers() & Modifier.ENUM) != 0)
        throw new IllegalArgumentException("Cannot reflectively create enum objects");
    ConstructorAccessor ca = constructorAccessor;   // read volatile
    if (ca == null) {
        ca = acquireConstructorAccessor();
    }
    @SuppressWarnings("unchecked")
    T inst = (T) ca.newInstance(initargs);
    return inst;
}


通过源码我们可以知道对于枚举类型无法使用newInstance来创建实例,也就能够解决单例在反射中的安全问题!



测试过程


见single目录下的OwnStudent:这是后来补上去的仅仅是类名不相同而已



自定义枚举类:


public enum Student {
    STUDENT;
}


我们来实验一下即可知道了,首先来若是想要通过反射来newInstance首先需要获取Constructor构造器实例,所以我们最起码得先知道其构造器的参数以及类型吧,我们通过反编译Student.class文件来查看一下:


①IDEA中的反编译


public enum Student {
    STUDENT;
    private Student() {
    }
}


②JDK工具javap进行反编译



③使用jad工具来进行反编译,获取一个java文件如下:


public final class Student extends Enum
{
    public static Student[] values()
    {
        return (Student[])$VALUES.clone();
    }
    public static Student valueOf(String name)
    {
        return (Student)Enum.valueOf(xyz/changlu/Student, name);
    }
    private Student(String s, int i)
    {
        super(s, i);
    }
    public static final Student STUDENT;
    private static final Student $VALUES[];
    static 
    {
        STUDENT = new Student("STUDENT", 0);
        $VALUES = (new Student[] {
            STUDENT
        });
    }
}



测试程序:


检测IDEA中的私有无参构造创建实例:


class Test1{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //通过Student的字节码类来获取构造器(空参)
        Constructor<Student> constructor = Student.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        System.out.println(constructor.newInstance());
    }
}



通过检验我们能够知道IDEA中的反编译结果并不正确的!

IDEA中反编译出来的实际上有问题的,在枚举类中创建实例并不是通过无参构造来创建的,我们以jad工具反编译出的结果为准,是通过一个私有的有参构造来创建实例的。


class Test1{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取单例
        System.out.println(Student.STUDENT);
        //传入参数获取无参构造
        Constructor<Student> constructor = Student.class.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        System.out.println(constructor.newInstance());
    }
}



这个报错结果才应该出现的情况,与我们之前在newInstance()源码中抛出的异常结果相同!



总结


1、单例模式优点是减少内存系统开销,保证单个类只有一个实例;缺点是扩展困难,并发测试不利于调试,容易违背单一职责原则。


2、实现单例主要有三种方式:①饿汉式(线程安全的);②懒汉式(双重加锁+volatile);③内部静态类。通过反射技术上面三种方式都容易出现安全问题!


3、通过枚举类实现单例来解决反射带来的安全问题,因为在反射技术中newInstance()方法对于枚举类是无法进行实例化的!!!

相关文章
|
11天前
|
设计模式 存储 前端开发
前端必须掌握的设计模式——单例模式
单例模式是一种简单的创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。适用于窗口对象、登录弹窗等场景,优点包括易于维护、访问和低消耗,但也有安全隐患、可能形成巨石对象及扩展性差等缺点。文中展示了JavaScript和TypeScript的实现方法。
|
17天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
21 2
|
20天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
1月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
36 4
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
1月前
|
设计模式 安全 Java
Java编程中的单例模式深入解析
【10月更文挑战第31天】在编程世界中,设计模式就像是建筑中的蓝图,它们定义了解决常见问题的最佳实践。本文将通过浅显易懂的语言带你深入了解Java中广泛应用的单例模式,并展示如何实现它。
|
22天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
27 0
|
1月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
下一篇
DataWorks