上一篇文章中。我们列出了计算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语言提供了更底层的功能。

最新文章

  1. Maven-通过命令操作maven项目
  2. springmvc学习第四天
  3. Access-Control-Allow-Origin: Dealing with CORS Errors in Angular
  4. Gradle用户指南(1)-Gradle安装
  5. 13行代碼開發出来的PHP框架[转]
  6. 高性能网络I/O框架-netmap源码分析
  7. java获得url里面所带参数的值
  8. ajax上传文件进度条
  9. 30种IT技能让你年薪过10万美元!
  10. android——字体颜色跟随状态改变
  11. SaltStack 部署案例 02
  12. x86 处理器开机顺序
  13. Linux内核异常处理体系结构详解(一)【转】
  14. canvas画小叮当
  15. css文本超出隐藏显示省略号
  16. IPerf——网络测试工具介绍与源码解析(1)
  17. Pandas 合并merge
  18. [转] Haproxy、Keepalived双主高可用负载均衡
  19. Python3 str去除空格
  20. cglib动态代理是通过继承父类的方式进行代理的 不是通过接口方式进行动态代理的 因此可以对普通的类进行代理

热门文章

  1. C指针
  2. C语言 EOF是什么?
  3. android 拍照 onCreate() 调用两次的问题
  4. linux下如何产生core,调试core
  5. 使用javascript oop开发滑动(slide) 菜单控件
  6. C#(VS2008)服务编写-安装和部署
  7. C# 2 闰年平年 老狼几点了
  8. Collections类方法详解
  9. git使用前配置
  10. 当tomcat有两个链接数据库的应用同时运行可能冲突