利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值

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

[java] view plain copy

  1. public class VO
  2. {
  3. public int a = 0;
  4. public long b = 0;
  5. public static String c= "123";
  6. public static Object d= null;
  7. public static int e = 100;
  8. }

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

[java] view plain copy

  1. // 获取实例字段的偏移地址,偏移最小的那个字段(仅挨着头部)就是对象头的大小
  2. System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("a")));
  3. System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("b")));
  4. // fieldOffset与objectFieldOffset功能一样,fieldOffset是过时方法,最好不要再使用
  5. System.out.println(unsafe.fieldOffset(VO.class.getDeclaredField("b")));

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

[java] view plain copy

  1. // 数组第一个元素的偏移地址,即数组头占用的字节数
  2. int[] intarr = new int[0];
  3. System.out.println(unsafe.arrayBaseOffset(intarr.getClass()));
  4. // 数组中每个元素占用的大小
  5. 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.获取类的静态字段偏移

[java] view plain copy

  1. // 获取类的静态字段偏地址
  2. System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("c")));
  3. System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("d")));
  4. // 获取静态字段的起始地址,通过起始地址和偏移地址,就可以获取静态字段的值了
  5. // 只不过静态字段的起始地址,类型不是long,而是Object类型
  6. Object base1 = unsafe.staticFieldBase(VO.class);
  7. Object base2 = unsafe.staticFieldBase(VO.class.getDeclaredField("d"));
  8. System.out.println(base1==base2);//true

4.获取操作系统的位数

[java] view plain copy

  1. //  Report the size in bytes of a native pointer.
  2. //  返回4或8,代表是32位还是64位操作系统。
  3. System.out.println(unsafe.addressSize());
  4. // 返回32或64,获取操作系统是32位还是64位
  5. System.out.println(System.getProperty("sun.arch.data.model"));

通过上面的几段代码,我们可以成功获取类中各个字段的偏移地址,这跟jol工具的输出结果和我们的结论是一致的。有了字段的偏移地址,在加上对象的起始地,我们就能够通过Unsafe直接获取字段的值了。

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

[java] view plain copy

  1. //获取实例字段的属性值
  2. VO vo = new VO();
  3. vo.a = 10000;
  4. long aoffset = unsafe.objectFieldOffset(VO.class.getDeclaredField("a"));
  5. int va = unsafe.getInt(vo, aoffset);
  6. System.out.println("va="+va);

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

[java] view plain copy

  1. VO.e = 1024;
  2. Field sField = VO.class.getDeclaredField("e");
  3. Object base = unsafe.staticFieldBase(sField);
  4. long offset = unsafe.staticFieldOffset(sField);
  5. System.out.println(unsafe.getInt(base, offset));//1024

可以看到Unsafe功能是很强大的,位java语言提供了更底层的功能。

原文地址:https://www.cnblogs.com/hanguocai/p/8309406.html

时间: 2024-10-28 10:06:58

利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值的相关文章

java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值

在上一篇文章中.我们列出了计算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"; pub

java的sun.misc.Unsafe类

阅读目录 前言 Unsafe类的作用 获取Unsafe对象 Unsafe类中的API 前言 以下sun.misc.Unsafe源码和demo基于jdk1.7: 最近在看J.U.C里的源码,很多都用到了sun.misc.Unsafe这个类,一知半解,看起来总感觉有点不尽兴,所以打算对Unsafe的源码及使用做个分析: 另外,网上找了份c++的源代码natUnsafe.cc(可惜比较老,Copyright (C) 2006, 2007年的,没找到新的),也就是sun.misc.Unsafe的C++实

sun.misc.Unsafe的理解

以下sun.misc.Unsafe源码和demo基于jdk1.7: 最近在看J.U.C里的源码,很多都用到了sun.misc.Unsafe这个类,一知半解,看起来总感觉有点不尽兴,所以打算对Unsafe的源码及使用做个分析: 另外,网上找了份c++的源代码natUnsafe.cc(可惜比较老,Copyright (C) 2006, 2007年的,没找到新的),也就是sun.misc.Unsafe的C++实现,跟Unsafe类中的native方法对照起来看更加容易理解: Unsafe类的作用 可以

sun.misc.unsafe类的使用

这个帖子是关于JAVA中鲜为人知的特性的后续更新,如果想得到下次在线讨论的更新,请通过邮件订阅,并且不要忘了在评论区留下你的意见和建议. Java是一个安全的开发工具,它阻止开发人员犯很多低级的错误,而大部份的错误都是基于内存管理方面的.如果你想搞破坏,可以使用Unsafe这个类.这个类是属于sun.* API中的类,并且它不是J2SE中真正的一部份,因此你可能找不到任何的官方文档,更可悲的是,它也没有比较好的代码文档. 实例化sun.misc.Unsafe 如果你尝试创建Unsafe类的实例,

利用反射机制,获取类的字段、方法、并实现简单调用

这篇文章是为之后要介绍Android的ICO框架做预备的,所以,如果想最近学习Android的ICO框架的同学,可以稍微看一下. 首先,简单介绍一下Java里面的反射. JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 不知道这样的一段解释,你能否看懂.如果更简单的说,反射就是能够根据你给出类名实例化出一个实实在在的对象.所以,对象的实例

Java sun.misc.unsafe类的使用

Java是一个安全的开发工具,它阻止开发人员犯很多低级的错误,而大部份的错误都是基于内存管理方面的.如果你想搞破坏,可以使用Unsafe这个类.这个类是属于sun.*API中的类,并且它不是J2SE中真正的一部份,因此你可能找不到任何的官方文档,更可悲的是,它也没有比较好的代码文档. 1.实例化sun.misc.Unsafe 如果你尝试创建Unsafe类的实例,基于以下两种原因是不被允许的. 1).Unsafe类的构造函数是私有的: 2).虽然它有静态的getUnsafe()方法,但是如果你尝试

Java Magic. Part 4: sun.misc.Unsafe

原文地址 译文地址 译者:许巧辉 校对:梁海舰 Java是一门安全的编程语言,防止程序员犯很多愚蠢的错误,它们大部分是基于内存管理的.但是,有一种方式可以有意的执行一些不安全.容易犯错的操作,那就是使用Unsafe类. 本文是sun.misc.Unsafe公共API的简要概述,及其一些有趣的用法. Unsafe 实例 在使用Unsafe之前,我们需要创建Unsafe对象的实例.这并不像Unsafe unsafe = new Unsafe()这么简单,因为Unsafe的构造器是私有的.它也有一个静

使用sun.misc.Unsafe及反射对内存进行内省(introspection)

对于一个有经验的JAVA程序员来说,了解一个或者其它的JAVA对象占用了多少内存,这将会非常有用.你可能已经听说过我们所生活的世界,存储容量将不再是一个问题,这个对于你的文本编辑器来说可能是对的(不过,打开一个包含大量的图片以及图表的文档,看看你的编辑器会消耗多少内存),对于一个专用服务器软件来说也可能是对的(至少在你的企业成长到足够大或者是在同一台服务器运行其它的软件之前),对于基于云的软件来说也可能是对的,如果你足够的富有可以花足够的钱可以买顶级的服务器硬件. 然而,现实是你的软件如果是受到

sun.misc.Unsafe中一些常用方法记录

sun.misc.Unsafe中一些常用方法记录 前情摘要 sun公司提供了可以用于直接操作内存的类,这个类就是sun.misc.Unsafe.因为Java本身是不会涉及到直接操作内存的,Java API也没有提供这些操作,内存管理全部交给虚拟机来做.Sun之所以提供这个类,因为有些功能现有的Java API满足不了,如果没有这个类,可能就没有现在原子类,J.U.C包了,也许也没了各种Concurrent Collection类,可能也没了NIO的堆外内存,所以这个类十分的有用,并且很重要,Su