2015-12-24 20 views
0

我對Android 6(ART)上的JNI本機代碼有點問題。我有一種方法可以接收jclass實例並存儲此類參考以供將來使用。要做到這一點,我需要創建這個jclass的引用,以便它不會成爲無效後:JNI:如何檢查兩個jclass實例是否實際引用相同的Java類?

std::set<jclass> storedClasses; 

void storeClass(jclass cls) 
{ 
    TraceLog << "Original jclass:" << cls; 
    jclass clsRef = (jclass)env.jniEnv()->NewGlobalRef(cls); 
    TraceLog << "New jclass global reference:" << cls; 

    storedClasses.insert(clsRef); 
} 

需要說明的是,我只需要存儲每個類一次(因此的std::set選擇對於容器 - 它保證所有項目都是唯一的),但實際上NewGlobalRef每次都創建一個新的,不同的jclass值。這很有道理,但直到最近我才相信。我不能再使用這個值(它只是一個指針)來確保唯一性。

我如何檢查兩個不同jclass實例是否指向相同或不同的Java類?將鑄造jclass返回到jobject並調用java.lang.Object.hashcode就會產生所需的結果?

更新:奇數,我可以調用hashcode()成功,但它總是返回-1
更新2:this也不管用,我得到的全部是java.lang.Class,無論我怎麼嘗試。

回答

2

NewGlobalRef創建一個新的引用,而不是類對象的一個​​新的對象也不實例。如果你調用它兩次,你會得到兩個不同的值,這兩個值都不會與你最初得到的本地參考值相同。 IsSameObject調用會告訴您它們都指向相同的東西,並且是確定兩個引用是否指向同一對象的唯一可靠方法。

不能平凡創造了一套具有引用,因爲引用不是唯一的。如果您的唯一要求是避免添加重複的對象,則可以在添加新成員時執行O(n)系列的IsSameObject調用。謹慎使用哈希碼 - 對象的哈希碼不會改變,所以如果哈希碼不匹配,您有兩個不同的對象,但兩個不同的對象可以具有相同的哈希碼。

另一種方法是使用JNI調用存儲在像HashSet的一個Java語言的數據結構中的類對象;這爲JNI調用增加了額外的開銷,但是如果您要存儲大量對象,改進的數據結構可能會有所幫助。(小問題:在ICS之前,Dalvik會簡單地返回一個指向被引用對象的指針,所以你可以實際創建一個本地集合,這種方法使得堆棧管理變得更加困難,所以ICS版本引入了「間接」引用,這是增強表索引而不是指針。)

+0

謝謝,現在我對JNI有了更多的瞭解!是的,我記得當ICS推出時,我的應用程序中出現了大量的JNI錯誤。一噸的樂趣,我已經將它們固定:) –

+0

P. S.能否請您澄清兩個不同的對象都可以有相同的散列碼?我的意思是,你指的哈希值的概率性質和事實,即碰撞是不可能的,還是你的意思是,它實際上可以在真正的應用程序發生具有統計學顯著概率是多少? –

+0

如果散列碼被計算(例如'java.lang.String'),兩個相等* *對象將總是具有相同的哈希值。對於簡單對象的哈希碼通常設置爲對象的32位地址,並「鎖定」第一次請求的東西它(所以如果對象移動它保持一致)。這避免了必須明確地將散列碼保存在永遠不會存儲在散列容器中的對象中。根據GC的特性,可能會在小範圍的地址中創建對象,從而造成碰撞的可能性。我不知道ART是如何工作的。 – fadden

0

我認爲這裏的問題是,你正在存儲clsRef,這是一個jobject你投給jclass。這不是一個真正的jclass,而是一個不同的對象,它是對原始類的引用。

您需要存儲的東西,充當您的商店的全球參考的關鍵。某件事必須唯一地確定班級。

你的商店是一套,我認爲你需要,例如一個哈希表。

如果FindClass()返回相同的值,每次那麼可以使用相同的參數,但我不能測試的時刻。我懷疑你需要做一個GetName(),但是,現在還不能發短信。

+0

我想'GetName'(請參見更新2在我的Q),並返回'lang.Class'即使是原來'cls',這是實際的原始類我的JNI方法收到。 –