单例模式的底层实现

枚举单例可以防止反射和序列化的破解。

-------------------------------------01---------------------------------

反射技术使用场景

1、jdbc加载驱动 2、SpringIOC容器 3、初始化对象 4.提供扩展功能

使用反射技术初始化无参对象

package com.mayikt.singleton.v9;

/**
 * @author 
 * @title: UserEntity
 * @description: 
 * @date 2019/6/120:43
 */
public class UserEntity {
    private String userName;
    private Integer age;

    //private UserEntity() {
    //System.out.println("无参构造函数执行。。");
    //}
    private UserEntity(String userName, Integer age) {
        this.userName = userName;
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

    public String getUserName() {
        return userName;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}
public static UserEntity reflexUser() throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
        Class<?> classInfo = Class.forName("com.mayikt.singleton.v9.UserEntity");
        //1.使用java的反射技术初始化对象 默认执行无参构造函数.. 执行无参构造函数..
        //也可以这么写
        //Constructor<?> declaredConstructor = UserEntity.class.getDeclaredConstructor();
        //Constructor<?> declaredConstructor = classInfo.getDeclaredConstructor();
        Constructor<?> declaredConstructor = classInfo.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        UserEntity userEntity = (UserEntity) declaredConstructor.newInstance();
        return userEntity;
    }

 上面是无参的

public static UserEntity getReflexUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    Class<?> classInfo = Class.forName("com.mayikt.singleton.v8.UserEntity");
    UserEntity userEntity = (UserEntity) classInfo.newInstance();
    return userEntity;
}

这个是无参的。构造函数是私有的话要设置权限。

-----------

有参的话

public static UserEntity reflexUser(String userName, Integer age) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
        Class<?> classInfo = Class.forName("com.mayikt.singleton.v9.UserEntity");
        // 1.使用java的反射技术初始化对象 默认执行无参构造函数.. 执行无参构造函数..
        //Constructor<?> declaredConstructor = classInfo.getDeclaredConstructor();
        Constructor<?> declaredConstructor = classInfo.getDeclaredConstructor(String.class, Integer.class);
        declaredConstructor.setAccessible(true);
        UserEntity userEntity = (UserEntity) declaredConstructor.newInstance(userName, age);
        return userEntity;
    }

  mian函数

public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//        UserEntity userEntity = ReflexUtils.reflexUser("zhangsan", 278);
//        System.out.println(userEntity.getAge() + "," + userEntity.getUserName());
        Class<?> classInfo = Class.forName("com.mayikt.singleton.v9.UserEntity");
        //java的反射技术可以给对象设置 执行方法
        Field[] fields = classInfo.getFields();


    }

  调试注意这个classInfo是可以拿到很多东西的。

  

  

 注意getFielsd()和getMethods()拿到所有的属性和方法。

-----------------------------------------------------02---------------------------

利用反射破解枚举单例:

枚举类:

package com.mayikt.singleton.v10;

public enum EnumSingleton {
    INSTANCE, MAYIKT;
    // 枚举能够绝对有效的防止实例化多次,和防止反射和序列化破解
    public void add() {
        System.out.println("add方法...");
    }
    // 枚举是如何初始化的? 反序列化底层是如何解决防止单例被破解。
     EnumSingleton() {
    }
}

  INSTANCE, MAYIKT都是对象。

  通过枚举去拿对象都是单例的:

 EnumSingleton instance1 = EnumSingleton.INSTANCE;
 EnumSingleton instance2 = EnumSingleton.INSTANCE;
 System.out.println(instance1 == instance2);

   结果是true。

Class<EnumSingleton> enumSingletonClass = EnumSingleton.class;
// 没有无参构造函数...
Constructor<EnumSingleton> declaredConstructor = enumSingletonClass.getDeclaredConstructor();
EnumSingleton enumSingleton = declaredConstructor.newInstance();
enumSingleton.add();

  这个会报错,无参构造函数。

  ------------------------------03------分析枚举的底层实现-----------------

EnumSingleton.INSTANCE.add();

  这行代码可以直接执行枚举的方法。可知EnumSingleton.INSTANCE是一个对象。

  加入这行代码:

 EnumSingleton instance = EnumSingleton.INSTANCE;

  我们定的枚举在底层肯定会转化为类。

  反编译去看:

javap -p XXXX.class的路径地址

  用工具:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   EnumSingleton.java

package com.mayikt.singleton.v10;

import java.io.PrintStream;

public final class EnumSingleton extends Enum
{

    public static EnumSingleton[] values()
    {
        return (EnumSingleton[])$VALUES.clone();
    }

    public static EnumSingleton valueOf(String name)
    {
        return (EnumSingleton)Enum.valueOf(com/mayikt/singleton/v10/EnumSingleton, name);
    }

    public void add()
    {
        System.out.println("add\u65B9\u6CD5...");
    }

    private EnumSingleton(String s, int i)
    {
        super(s, i);
    }

    public static final EnumSingleton INSTANCE;
    public static final EnumSingleton MAYIKT;
    private static final EnumSingleton $VALUES[];

    static 
    {
        INSTANCE = new EnumSingleton("INSTANCE", 0);
        MAYIKT = new EnumSingleton("MAYIKT", 1);
        $VALUES = (new EnumSingleton[] {
            INSTANCE, MAYIKT
        });
    }
}

  枚举中定义的对象都是在静态代码块初始化的。没有无参构造函数的,默认是有参的。

 static 
    {
        INSTANCE = new EnumSingleton("INSTANCE", 0);
        MAYIKT = new EnumSingleton("MAYIKT", 1);
        $VALUES = (new EnumSingleton[] {
            INSTANCE, MAYIKT
        });
    }

   

  

         获取所有的对象:  

EnumSingleton[] values = EnumSingleton.values();

--------------------04----------------------------------------------------

虽然只有有参构造,但是不可以通过有参构造函数初始化枚举。

        Class<EnumSingleton> enumSingletonClass = EnumSingleton.class;
        // 2.查找当前类是否有该构造函数..
        Constructor<EnumSingleton> declaredConstructor = enumSingletonClass.getDeclaredConstructor(String.class, int.class);
        declaredConstructor.setAccessible(true);
        // 3.调用反射方法初始化对象
        EnumSingleton enumSingleton = declaredConstructor.newInstance("zhangsan", 20);
        enumSingleton.add();

  此时会报错:

  

点进去这个方法

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;
    }

当前是枚举就会抛出异常的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值