基于Unsafe类的对象属性操作工具类
该工具提供的功能:
1. 提供读取对象的任意类属性和实例化成员的任意属性的值(如直接读取private声明的成员变量值)
2. 提供修改对象任意类属性和实例化成员的任意属性的值(如直接修改final声明的成员变量值)
PS:由于该操作是直接操作内存数据,跳过了Java语法的条框限制,具备一定的危险性,该工具仅做学习和交流使用!
工具代码:
package com.msl.util;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
* @Discription: 强制读取和操作对象属性工具类
* @Author Zaki Chen
* @date 2019/9/30 14:15
**/
public class ObjectManipulationUtil {
private static volatile ObjectManipulationUtil util;
private Unsafe unsafe;
private ObjectManipulationUtil() {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
unsafe = (Unsafe) theUnsafeField.get(null);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static ObjectManipulationUtil getInstance() {
if (util == null) {
synchronized (ObjectManipulationUtil.class) {
util = new ObjectManipulationUtil();
}
}
return util;
}
/**
* 获取对象的成员变量属性值
*
* @param object 对象实例
* @param propertyName 对象声明的属性名
* @param dataType 获取的对象属性的声明类型
* @return
* @throws NoSuchFieldException
*/
public Object getInstanceFieldValue(Object object, String propertyName, Type dataType) throws NoSuchFieldException {
Field field = object.getClass().getDeclaredField(propertyName);
long offset = unsafe.objectFieldOffset(field);
return getValue(object, offset, dataType);
}
/**
* 更新对象实例属性的值
*
* @param object 实例对象
* @param propertyName 实例属性名 非static关键字声明的属性
* @param val 要修改的值
* @return
*/
public void setInstanceFieldValue(Object object, String propertyName, Object val) throws NoSuchFieldException {
Field propNameField = object.getClass().getDeclaredField(propertyName);
long offset = unsafe.objectFieldOffset(propNameField);
Type dataType = getType(val);
setValue(object, offset, val, dataType);
}
/**
* 修改类属性变量的值
*
* @param clazz 类
* @param propertyName 类属性 static关键字声明的属性
* @param val 值
* @throws NoSuchFieldException
*/
public void setStaticFieldValue(Class clazz, String propertyName, Object val) throws NoSuchFieldException {
Field propNameField = clazz.getDeclaredField(propertyName);
long offset = unsafe.staticFieldOffset(propNameField);
Type dataType = getType(val);
setValue(clazz, offset, val, dataType);
}
/**
* 获取对象的类变量属性值
*
* @param clazz Class对象
* @param propertyName 对象类声明的属性名
* @param dataType 获取的对象类属性的声明类型
* @return
* @throws NoSuchFieldException
*/
public Object getStaticFieldValue(Class clazz, String propertyName, Type dataType) throws NoSuchFieldException {
Field field = clazz.getDeclaredField(propertyName);
long offset = unsafe.staticFieldOffset(field);
return getValue(clazz, offset, dataType);
}
/**
* 数据值类型枚举
*/
public enum Type {
/**
* 引用类型 如String
*/
Object,
/**
* Char类型
*/
Char,
/**
* Byte类型
*/
Byte,
/**
* Integer类型
*/
Integer,
/**
* Double类型
*/
Double,
/**
* Float类型
*/
Float,
/**
* Long类型
*/
Long,
/**
* Boolean类型
*/
Boolean
}
private Type getType(Object val) {
Type dataType = Type.Object;
if (val instanceof Character) {
dataType = Type.Char;
} else if (val instanceof Byte) {
dataType = Type.Byte;
} else if (val instanceof Integer) {
dataType = Type.Integer;
} else if (val instanceof Double) {
dataType = Type.Double;
} else if (val instanceof Float) {
dataType = Type.Float;
} else if (val instanceof Long) {
dataType = Type.Long;
} else if (val instanceof Boolean) {
dataType = Type.Boolean;
}
return dataType;
}
/**
* 取对象数据
*
* @param object 对象:可以是一个实例对象,也可以是一个类对象
* @param offset 内存偏移地址
* @param type 返回数据的类型
* @return
*/
private Object getValue(Object object, long offset, Type type) {
switch (type) {
case Char:
return unsafe.getChar(object, offset);
case Byte:
return unsafe.getByte(object, offset);
case Integer:
return unsafe.getInt(object, offset);
case Double:
return unsafe.getDouble(object, offset);
case Float:
return unsafe.getFloat(object, offset);
case Long:
return unsafe.getLong(object, offset);
case Boolean:
return unsafe.getBoolean(object, offset);
default:
return unsafe.getObject(object, offset);
}
}
/**
* 放对象数据
*
* @param object 对象:可以是一个实例对象,也可以是一个类对象
* @param offset 内存偏移地址
* @param val 修改后的值
* @param type 被修改属性的声明类型
*/
private void setValue(Object object, long offset, Object val, Type type) {
switch (type) {
case Char:
unsafe.putCharVolatile(object, offset, (Character) val);
break;
case Byte:
unsafe.putByteVolatile(object, offset, (Byte) val);
break;
case Integer:
unsafe.putIntVolatile(object, offset, (Integer) val);
break;
case Double:
unsafe.putDoubleVolatile(object, offset, (Double) val);
break;
case Float:
unsafe.putFloatVolatile(object, offset, (Float) val);
break;
case Long:
unsafe.putLongVolatile(object, offset, (Long) val);
break;
case Boolean:
unsafe.putBooleanVolatile(object, offset, (Boolean) val);
break;
default:
unsafe.putObjectVolatile(object, offset, val);
}
}
}
测试代码:
package com.msl.test01;
import com.msl.util.ObjectManipulationUtil;
/**
* @Discription:
* @Author Zaki Chen
* @date 2019/9/30 14:35
**/
public class UtilTest01 {
public static void main(String[] args) {
Inner inner = new Inner();
try {
ObjectManipulationUtil util = ObjectManipulationUtil.getInstance();
Object value = util.getInstanceFieldValue(inner, "name", ObjectManipulationUtil.Type.Object);
System.out.println("直接读取到对象的private属性name的值:" + value.toString());
System.out.println("修改inner对象的name属性值为 ‘叼俊_被修改’");
util.setInstanceFieldValue(inner, "name", "叼俊_被修改");
System.out.println("修改后的inner对象的name属性的值为:" + inner.getName());
System.out.println("----------------------------------------------------");
Object value2 = util.getStaticFieldValue(Inner.class, "name_static", ObjectManipulationUtil.Type.Object);
System.out.println("直接读取到类的private属性name_static的值:" + value2.toString());
util.setStaticFieldValue(Inner.class, "name_static", "叼俊static_被修改");
System.out.println("修改Inner类的name_static属性的值为:" + Inner.getName_static());
System.out.println("----------------------------------------------------");
System.out.println("直接读取Inner对象的name_final属性的值为:"+util.getStaticFieldValue(Inner.class, "name_final", ObjectManipulationUtil.Type.Object));
util.setStaticFieldValue(Inner.class, "name_final", "叼俊final_被修改");
System.out.println("修改后Inner对象的name_final属性的值为:"+util.getStaticFieldValue(Inner.class, "name_final", ObjectManipulationUtil.Type.Object));
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
class Inner {
private String name = "叼俊";
private static String name_static = "叼俊static";
private static final String name_final = "叼俊final";
public String getName() {
return name;
}
public static String getName_static() {
return name_static;
}
}
测试结果:
"C:\Program Files\Java\jdk1.8.0_51\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.1\lib\idea_rt.jar=5777:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_51\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\rt.jar;F:\IntellijProjects\concurrent_java\out\production\mima-concurrent" com.msl.test01.UtilTest01
直接读取到对象的private属性name的值:叼俊
修改inner对象的name属性值为 ‘叼俊_被修改’
修改后的inner对象的name属性的值为:叼俊_被修改
----------------------------------------------------
直接读取到类的private属性name_static的值:叼俊static
修改Inner类的name_static属性的值为:叼俊static_被修改
----------------------------------------------------
直接读取Inner对象的name_final属性的值为:叼俊final
修改后Inner对象的name_final属性的值为:叼俊final_被修改
Process finished with exit code 0