博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java读出类的对象地址_java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值...
阅读量:5742 次
发布时间:2019-06-18

本文共 2322 字,大约阅读时间需要 7 分钟。

在上一篇文章中。我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下。如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证下之前文章中的结论,再则跟jol输出结果对照下。怎样获取sun.misc.Unsafe对象。能够參考这篇文章。

public class VO

{

public int a = 0;

public long b = 0;

public static String c= "123";

public static Object d= null;

public static int e = 100;

}

1.获取实例字段的偏移地址

// 获取实例字段的偏移地址,偏移最小的那个字段(仅挨着头部)就是对象头的大小

System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("a")));

System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("b")));

// fieldOffset与objectFieldOffset功能一样,fieldOffset是过时方法,最好不要再使用

System.out.println(unsafe.fieldOffset(VO.class.getDeclaredField("b")));

2.获取数组的头部大小和元素大小

// 数组第一个元素的偏移地址,即数组头占用的字节数

int[] intarr = new int[0];

System.out.println(unsafe.arrayBaseOffset(intarr.getClass()));

// 数组中每一个元素占用的大小

System.out.println(unsafe.arrayIndexScale(intarr.getClass()));Unsafe类中有非常多以BASE_OFFSET结尾的常量,比方ARRAY_INT_BASE_OFFSET等,这些常量值是通过arrayBaseOffset方法得到的。arrayBaseOffset方法是一个本地方法,能够获取数组第一个元素的偏移地址。Unsafe类中还有非常多以INDEX_SCALE结尾的常量,比方 ARRAY_INT_INDEX_SCALE 等。这些常量值是通过arrayIndexScale方法得到的。将arrayBaseOffset与arrayIndexScale配合使用,能够定位数组中每一个元素在内存中的位置。

3.获取类的静态字段偏移

// 获取类的静态字段偏地址

System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("c")));

System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("d")));

// 获取静态字段的起始地址,通过起始地址和偏移地址,就能够获取静态字段的值了

// 仅仅只是静态字段的起始地址,类型不是long,而是Object类型

Object base1 = unsafe.staticFieldBase(VO.class);

Object base2 = unsafe.staticFieldBase(VO.class.getDeclaredField("d"));

System.out.println(base1==base2);//true

4.获取操作系统的位数

// Report the size in bytes of a native pointer.

// 返回4或8,代表是32位还是64位操作系统。

System.out.println(unsafe.addressSize());

// 返回32或64,获取操作系统是32位还是64位

System.out.println(System.getProperty("sun.arch.data.model"));

通过上面的几段代码。我们可以成功获取类中各个字段的偏移地址,这跟jol工具的输出结果和我们的结论是一致的。

有了字段的偏移地址,在加上对象的起始地。我们就行通过Unsafe直接获取字段的值了。

5.读取对象实例字段的值

//获取实例字段的属性值

VO vo = new VO();

vo.a = 10000;

long aoffset = unsafe.objectFieldOffset(VO.class.getDeclaredField("a"));

int va = unsafe.getInt(vo, aoffset);

System.out.println("va="+va);

6.获取静态字段的属性值

VO.e = 1024;

Field sField = VO.class.getDeclaredField("e");

Object base = unsafe.staticFieldBase(sField);

long offset = unsafe.staticFieldOffset(sField);

System.out.println(unsafe.getInt(base, offset));//1024

能够看到Unsafe功能是非常强大的,位java语言提供了更底层的功能。

转载地址:http://mfnzx.baihongyu.com/

你可能感兴趣的文章
linux下使用过的命令总结(未整理完)
查看>>
时间助理 时之助
查看>>
英国征召前黑客组建“网络兵团”
查看>>
Silverlight 2.5D RPG游戏“.NET技术”技巧与特效处理:(十二)魔法系统
查看>>
PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)...
查看>>
pyjamas build AJAX apps in Python (like Google did for Java)
查看>>
LAMP环境搭建1-mysql5.5
查看>>
centos5.9使用RPM包搭建lamp平台
查看>>
Javascript String类的属性及方法
查看>>
[LeetCode] Merge Intervals
查看>>
Ubuntu 14.04 vsftp refusing to run with writable root inside chroot问题解决方法
查看>>
Intellij IDEA远程调试tomcat
查看>>
Struts2 学习小结
查看>>
烂泥:wordpress迁移到docker
查看>>
.扒渣机的性能及优势 
查看>>
测试工具综合
查看>>
asp.net中调用COM组件发布IIS时常见错误 80070005解决方案
查看>>
分享一段ios数据库代码,包括对表的创建、升级、增删查改
查看>>
如何书写高质量的jQuery代码
查看>>
Activity的生命周期整理
查看>>