枚举单例可以防止反射和序列化的破解。
-------------------------------------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;
}
当前是枚举就会抛出异常的。