早上看到了文章关于Unsafe类的,就看了下根据文章看了下里面的一些操作,下面是实现的代码
public class Test {
public static void main(String[] args) throws Exception {
Field field111 = Unsafe.class.getDeclaredField("theUnsafe");
field111.setAccessible(true);
Unsafe unsafe = (Unsafe) field111.get(null);
Demo demo=new Demo();
Long nameadd = unsafe.objectFieldOffset(demo.getClass().getDeclaredField("name"));
// Long nameadd = unsafe.objectFieldOffset(Demo.class.getDeclaredField("name"));
Long ageadd = unsafe.objectFieldOffset(demo.getClass().getDeclaredField("age"));
/* nameadd=nameadd^ageadd;
ageadd=nameadd^ageadd;
nameadd=nameadd^ageadd;
Field field = Demo.class.getDeclaredField("name");
Class<?> type = field.getType();
System.out.println(type);*/
Integer integer=new Integer(1);
unsafe.putObject(demo,nameadd,"11");
System.out.println(demo.name);
Demo demo1=new Demo();
unsafe.putObject(demo1,nameadd,"11222");
System.out.println(demo1.name);
}
}
class Demo{
String name=new String("s");
Integer age=new Integer(1);
}
unsafe类是
private Unsafe() {
}
虽然有
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
但是这里就牵涉到了类加载机制的问题了
。如果是单纯的用静态方法取获取那么会报错,(bootstrap加载除了扩展包以外的所有,比如用object.classloader返回是null,双亲委派机制为了保证类的唯一(依赖加载器),)
因此必须要用反射
原本我看到能够获取字段的偏移量,我想到的是把2个不用类型的字段利用指针呼唤位置,所以第一次我互换的nameadd和ageadd ,但是一直会报错。我以为是我操作方式不对,然后就在网上看相关的操作教程,
就有了 unsafe.putObject(demo,nameadd,“11”); 这样是可以的。
然后我想更进一步,就把参数的“11”换为 Integer类型的发现还是报错,
那可能就是必须得同一类型把
最后就是我试了下 new 一个新的demo1 ,发现里面的name仍然是最初的“s”,这个好理解,因为参数里面有个demo的实例对象,后来对于unsafe.putObject(demo1,nameadd,“11”);我发现仍然有效,后来想想可能是因为nameadd获取的是整个class文件里的字段地址值(是不是因为class文件只加载一次)
感觉是时候去学习下class文件的内容代表的含义了。。。
//这个是unsafe可以通过allocateInstance方法直接生成对象的示例,不需要通过构造函数
class Test111 {
public static void main(String[] args) throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
UnsafeTest unsafeTest = (UnsafeTest) unsafe.allocateInstance(UnsafeTest.class);
unsafeTest.show();
}
}
class UnsafeTest{
static {
System.out.println("111");
}
private UnsafeTest(){}
void show(){
System.out.println("222");
}
}
补充下额外的:
在对象头里的markOop ,通常叫做markword,
kalssoop 又叫做元数据指针,就是类的实例可以通过这个确认
对于64位的指针压缩压缩的就是这个
接下来的实例数据其实就是类的field字段,里面又牵涉到了java的对齐规则
参考了这个: https://blog.csdn.net/reliveIT/article/details/101161173
https://www.jianshu.com/p/3d38cba67f8b
下面这个是网上的代码示例,,,,但是我一直看不懂,而且对于@Contended这个注解我自己也尝试了下发现和想象的不一样
import java.lang.reflect.Field;
import sun.misc.Contended;
import sun.misc.Unsafe;
public class TypeSequence {
@Contended
private boolean contended_boolean;
private volatile byte a;
private volatile boolean b;
@Contended
private int contended_short;
private volatile char d;
private volatile short c;
private volatile int e;
private volatile float f;
@Contended
private int contended_int;
@Contended
private double contended_double;
private volatile double g;
private volatile long h;
public static Unsafe UNSAFE;
static {
try {
@SuppressWarnings("ALL")
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws NoSuchFieldException, SecurityException{
System.out.println("e:int \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("e")));
System.out.println("g:double \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("g")));
System.out.println("h:long \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("h")));
System.out.println("f:float \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("f")));
System.out.println("c:short \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("c")));
System.out.println("d:char \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("d")));
System.out.println("a:byte \t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("a")));
System.out.println("b:boolean\t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("b")));
System.out.println("contended_boolean:boolean\t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("contended_boolean")));
System.out.println("contended_short:short\t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("contended_short")));
System.out.println("contended_int:int\t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("contended_int")));
System.out.println("contended_double:double\t"+UNSAFE.objectFieldOffset(TypeSequence.class.getDeclaredField("contended_double")));
}
}
我的是这个
e:int 40
g:double 24
h:long 32
f:float 44
c:short 54
d:char 52
a:byte 57
b:boolean 58
contended_boolean:boolean 56
contended_short:short 12
contended_int:int 48
contended_double:double 16