日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关于Unsafe类的一点研究

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于Unsafe类的一点研究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自??關于Unsafe類的一點研究

Unsafe類是java中非常特別的一個類。它名字就叫做“不安全”,提供的操作可以直接讀寫內存、獲得地址偏移值、鎖定或釋放線程。

通過正常途徑是無法獲得Unsafe實例的,首先它的構造方法是私有的,然后,即使你調用它的getUnsafe方法,也會拋出SecurityException。

A collection of methods for performing low-level, unsafe operations. Although the class and all methods are public, use of this class islimited because only trusted code can obtain instances of it.

任何關于Unsafe類的文章都不會推薦我們在代碼中使用它,但這并不妨礙我們了解它可以做什么。下面我們來看下利用Unsafe類我們是否可以做點有趣的事情。

獲取Unsafe實例

public static Unsafe getUnsafeInstance() throws Exception{Field unsafeStaticField = Unsafe.class.getDeclaredField("theUnsafe");unsafeStaticField.setAccessible(true);return (Unsafe) unsafeStaticField.get(Unsafe.class); }

通過java反射機制,我們跳過了安全檢測,拿到了一個unsafe類的實例。

我找遍了Unsafe類的API,沒有發現可以直接獲取對象地址的方法,Unsafe中操作地址相關的方法都要求提供一個Object類型的參數,用來獲取對象的初始地址。

修改和讀取數組中的值

Unsafe u = getUnsafeInstance();int[] arr = {1,2,3,4,5,6,7,8,9,10};int b = u.arrayBaseOffset(int[].class);int s = u.arrayIndexScale(int[].class);u.putInt(arr, (long)b+s*9, 1);for(int i=0;i<10;i++){int v = u.getInt(arr, (long)b+s*i);System.out.print(v+“ ”);}

打印結果:1 2 3 4 5 6 7 8 9 1 ,可以看到,成功讀出了數組中的值,而且最后一個值由10改為了1。

  • arrayBaseOffset: 返回當前數組第一個元素地址相對于數組起始地址的偏移值,在本例中返回6。

  • arrayIndexScale: 返回當前數組一個元素占用的字節數,在本例中返回4。

  • putInt(obj,offset,intval): 獲取數組對象obj的起始地址,加上偏移值,得到對應元素的地址,將intval寫入內存。

  • getInt(obj,offset): 獲取數組對象obj的起始地址,加上偏移值,得到對應元素的地址,從而獲得元素的值。

  • 偏移值: 數組元素偏移值 = arrayBaseOffset + arrayIndexScalse * i。

獲取對象實例

/** Allocate an instance but do not run any constructor. Initializes the class if it has not yet been. */ public native Object allocateInstance(Class cls) throws InstantiationException;

allocateInstance: 在不執行構造方法的前提下,獲取一個類的實例,即使這個類的構造方法是私有的。

修改靜態變量和實例變量的值

先定義一個Test類

public class Test {public int intfield ;public static int staticIntField;public static int[] arr;private Test(){System.out.println("constructor called");} }

修改Test類的實例變量

Unsafe u = getUnsafeInstance();Test t = (Test) u.allocateInstance(Test.class);long b1 = u.objectFieldOffset(Test.class.getDeclaredField("intfield"));u.putInt(t, b1, 2);System.out.println("intfield:"+t.intfield);

這里使用allocateInstance方法獲取了一個Test類的實例,并且沒有打印“constructor called”,說明構造方法沒有調用。
修改實例變量與修改數組的值類似,同樣要獲取地址偏移值,然后調用putInt方法。

  • objectFieldOffset: 獲取對象某個屬性的地址偏移值。

我們通過Unsafe類修改了Java堆中的數據。

修改Test類的靜態變量

Field staticIntField = Test.class.getDeclaredField("staticIntField");Object o = u.staticFieldBase(staticIntField);System.out.prinln(o==Test.class);Long b4 = u.staticFieldOffset(staticIntField); //因為是靜態變量,傳入的Object參數應為class對象 u.putInt(o, b4, 10);System.out.println("staticIntField:"+u.getInt(Test.class, b4));

打印結果:

true

staticIntField:10

靜態變量與實例變量不同之處在于,靜態變量位于于方法區中,它的地址偏移值與Test類在方法區的地址相關,與Test類的實例無關。

  • staticFieldBase: 獲取靜態變量所屬的類在方法區的首地址。可以看到,返回的對象就是Test.class。

  • staticFieldOffset: 獲取靜態變量地址偏移值。

我們通過Unsafe類修改了方法區中的信息。

調戲String.intern

在jdk7中,String.intern不再拷貝string對象實例,而是保存第一次出現的對象的引用。在下面的代碼中,通過Unsafe修改被引用對象s的私有屬性value達到間接修改s1的效果!

String s = "abc";//保存s的引用 s.intern();//此時s1==s,地址相同 String s1 = "abc";Unsafe u = getUnsafeInstance();//獲取s的實例變量value Field valueInString = String.class.getDeclaredField("value");//獲取value的變量偏移值 long offset = u.objectFieldOffset(valueInString);//value本身是一個char[],要修改它元素的值,仍要獲取baseOffset和indexScale long base = u.arrayBaseOffset(char[].class);long scale = u.arrayIndexScale(char[].class);//獲取value char[] values = (char[]) u.getObject(s, offset);//為value賦值 u.putChar(values, base + scale, 'c');System.out.println("s:"+s+" s1:"+s1);//將s的值改為 abc s = "abc";String s2 = "abc";String s3 = "abc";System.out.println("s:"+s+" s1:"+s1);

打印結果:

s:acc s1:acc

s:acc s1:acc s2:acc s3:acc

我們發現了什么?所有值為“abc”的字符串都變成了“acc”!!!

Unsafe類果然不安全!!!

?

總結

以上是生活随笔為你收集整理的关于Unsafe类的一点研究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。