开发过程中,不少情况下都会遇到需要通过反射修改对象字段值的情况,但是很多情况下,直接反射效率比较低,而你如果读过jdk代码,可能多少会发现jdk里边经常闪现这UNSAFE的的身影,比如ConcurrentLinkedQueue里边到处都是。
为啥jdk里边到处都用这个东西呢?YY下,一方面是因为效率高,另一方面是因为它提供了很强大底层操作的功能,比如不用AtomicObject就可以直接支持cas操作修改对象字段,可以直接申请释放内存。
调用效率高,到底有多高呢?直接上代码:
import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * -Xcomp * @author tianmai.fh * @date 2014-03-12 16:43 */ public class FieldOffsetTest { static int COUNT = 50000000; static int LENGTH = 1024; static long BEAN_A_OFFSET; static Unsafe unsafe; static Field aField; static Field bField; static long BEAN_B_OFFSET; static { try { Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); Method objectFieldOffsetMethod = Unsafe.class.getDeclaredMethod("objectFieldOffset", new Class[]{Field.class}); objectFieldOffsetMethod.setAccessible(true); BEAN_A_OFFSET = unsafe.objectFieldOffset(Bean.class.getDeclaredField("a")); BEAN_B_OFFSET = unsafe.objectFieldOffset(Bean.class.getDeclaredField("b")); aField = Bean.class.getDeclaredField("a"); aField.setAccessible(true); bField = Bean.class.getDeclaredField("b"); bField.setAccessible(true); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } static class Bean { private int a; private int b; private int c[] = new int[LENGTH]; } public static void testFieldOffsetAssign() throws NoSuchFieldException, InvocationTargetException, IllegalAccessException { Bean bean = new Bean(); long start = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { unsafe.putInt(bean,BEAN_A_OFFSET,i); unsafe.putInt(bean,BEAN_B_OFFSET,i); } long end = System.currentTimeMillis(); System.out.println("Offset spend: " + (end - start) + " ms"); } public static void testReflectAssign() throws IllegalAccessException { Bean bean = new Bean(); long start = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { aField.set(bean, i); bField.set(bean, i); } long end = System.currentTimeMillis(); System.out.println("Reflect spend: " + (end - start) + " ms"); } public static void testDirectAssign() throws IllegalAccessException { Bean bean = new Bean(); long start = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { bean.a = i; bean.b = i; } long end = System.currentTimeMillis(); System.out.println("Direct spend: " + (end - start) + " ms"); } public static void main(String[] args) throws NoSuchFieldException, InvocationTargetException, IllegalAccessException { for (int i = 0; i < 5; i++) { testDirectAssign(); testReflectAssign(); testFieldOffsetAssign(); System.out.println(); } } }
看输出结果:
Direct spend: 8 ms Reflect spend: 2111 ms Offset spend: 84 ms Direct spend: 0 ms Reflect spend: 2163 ms Offset spend: 81 ms Direct spend: 0 ms Reflect spend: 2134 ms Offset spend: 83 ms Direct spend: 0 ms Reflect spend: 2097 ms Offset spend: 80 ms Direct spend: 0 ms Reflect spend: 2150 ms Offset spend: 79 ms
通过unsafe赋值耗费的时间是反射调用耗费时间的4%,一个数量级之差!当然在可以直接调用的时候呢,还是直接调用好了,效率更高!
细读下代码,应用代码不能直接获取Unsafe实例的:
public static Unsafe getUnsafe() { Class cc = sun.reflect.Reflection.getCallerClass(2); if (cc.getClassLoader() != null) throw new SecurityException("Unsafe"); return theUnsafe; }
这个类的注释上写只有信任代码才能获取这个类的实例,从源码看呢,就是BootstrapClassLoader加载的类才可以使用,也就是jdk的核心类库才可以使用它,所以我demo中就通过反射获取了。当然如果jdk升级,这个类消失或者接口变动,只有自己负责了。
A collection of methods for performing low-level, unsafe operations.Although the class and all methods are public, use of this class is limited because only trusted code can obtain instances of it.
通过Unsafe的接口可以获得字段在类中的偏移量,这个偏移量可以用来在对象上找到字段相对于对象地址的偏移量,对象在堆上也只是一块内存而已,有了对象地址作为起始地址,加上偏移量,很容易获取到字段在堆中的位置了,而且这个偏移量不会因为gc移动对象实例位置而变动:
public native long objectFieldOffset(Field f)
剩下的就只有使用了!enjoy it !
相关推荐
例如,我们可以通过类的全名获取Class对象,然后通过这个Class对象来创建实例,调用方法,读取或修改字段值。 在这个通用查询方法中,核心思想是利用反射机制将SQL查询结果映射到Java对象或者对象列表。通常,这个...
总之,实现对字段和方法的递归查找是软件开发中的一个重要技能,它涉及类层次结构、接口、注解、反射等多个方面。掌握这项技术有助于我们更好地理解和操作复杂的代码库,提高代码质量和可维护性。在实践中,我们可以...
5. **访问字段**: `Field`对象代表类的字段,通过`set(Object obj, Object value)`和`get(Object obj)`方法,可以在运行时修改或获取字段的值。 6. **在DAO模式中的应用**: 数据访问对象(DAO)模式是将业务逻辑与...
Java反射是Java编程语言中的一个强大特性,它允许在运行时检查类、接口、字段和方法的信息,并且能够在运行时动态地创建对象和...在理解和熟练掌握反射之后,开发者可以更高效地解决复杂问题,实现更灵活的代码设计。
在Java编程语言中,反射(Reflection)是一种强大的工具,它允许程序在运行时检查和操作类、接口、字段以及方法等对象。通过反射,开发者可以访问那些在编译时未知或者不可见的类和对象,增加了代码的灵活性和可扩展...
首先,Java反射机制允许我们在运行时检查类、接口、字段和方法的信息,甚至可以动态调用方法和修改字段值。在数据库操作中,反射可以帮助我们根据字符串形式的SQL语句来动态执行相应的方法,无需预先编写大量硬编码...
2. 字段操作:`field(String)`方法获取指定名称的字段,`get(Object)`和`set(Object, Object)`分别用于获取和设置字段值。 3. 方法调用:`method(String)`获取指定名称的方法,`invoke(Object, Object...)`执行方法...
反射是Java的一种强大特性,它允许我们在运行时检查类、接口、字段和方法的信息,甚至可以动态调用方法和修改字段值。这对于创建通用代码、元编程、单元测试等场景非常有用。 以下是一个简单的反射示例: ```java ...
总的来说,注解反射导出Excel自定义中文表头是一种高效且灵活的方法,它结合了Java的元数据功能和运行时检查的强大能力,使得数据导出更加便捷。在实际项目中,你可以根据具体需求调整和扩展这个过程,以满足更复杂...
args)`)以及访问和修改字段值。 在"ThreadMain"这个文件中,可能包含了一个演示如何使用线程池和反射机制的示例代码。通常,这个主程序会创建一个线程池,然后将一系列任务提交到线程池中,这些任务可能是通过...
`Field`类提供了这些功能,例如`getField()`用于获取字段,`set()`和`get()`用于修改和读取字段值。 4. **调用方法**:反射可以动态地调用对象的方法,包括静态方法和实例方法。`Method`类提供了`invoke()`方法来...
字段的特性如 readonly 和 static 也会影响其行为,前者在初始化后不可修改,后者则为类的所有实例共享同一值。 属性(Properties)是C#中一种封装字段的方法,提供了一种安全访问字段的方式。属性由getter和setter...
因此,只有在确实需要其功能时才应使用反射API,避免在已有更高效方法的情况下滥用。 #### 使用面向任务的方法学习反射API 为了更好地理解和掌握反射API,可以采用面向任务的学习方法,即针对特定需求进行学习和...
我们可以获取并调用Method对象表示的方法,或者通过Field对象访问或修改字段值。 将DOM4J与反射结合,我们可以实现XML到Java对象的映射。首先,解析XML文档得到Element对象,然后根据Element的标签名创建对应的Java...
反射是.NET Framework提供的一个强大工具,它允许运行时的代码分析、访问和修改程序集、类型、方法、属性等元数据。通过反射,我们可以动态地创建对象,调用方法,获取或设置属性值。例如,我们可以通过类型名称获取...
反射允许程序在运行时获取关于类、接口、字段和方法的信息,并能动态调用方法或修改字段值。在Java中,`java.lang.reflect`包提供了实现反射所需的所有类。例如,`Class`类代表一个Java类或接口,可以用来获取类的元...
通过反射,开发者可以在运行时动态地获取类的构造方法、字段和方法,以及类的父类、接口、属性和方法列表,从而实现动态编程和元编程。 总结来说,枚举提供了一种安全的方式来定义一组常量,而反射机制则赋予了Java...
在Java和.NET等面向对象的语言中,反射是强大的工具,可以用于实现元编程,即在程序运行时动态地创建对象、调用方法、访问字段等。 在动态调用WebService时,反射可以用来获取WebService的接口信息,动态地创建服务...
通过反射,我们可以在运行时动态地创建对象、调用方法、访问字段,甚至修改私有成员。在DWR与反射的结合中,我们可以利用反射来实现一些特定的需求,例如: 1. **动态对象映射**:如果我们的应用需要处理未知类型的...
在Java中,反射是一种强大的工具,它允许我们在运行时检查类、接口、字段和方法的信息,甚至可以在不知道对象具体类型的情况下调用其方法。在Android中,反射可以用于动态操作数据库,尤其是在处理不确定的数据模型...