MethodHandles.Lookup 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。
[Android.Runtime.Register("java/lang/invoke/MethodHandles$Lookup", ApiSince=26, DoNotGenerateAcw=true)]
public sealed class MethodHandles.Lookup : Java.Lang.Object
[<Android.Runtime.Register("java/lang/invoke/MethodHandles$Lookup", ApiSince=26, DoNotGenerateAcw=true)>]
type MethodHandles.Lookup = class
inherit Object
- 繼承
- 屬性
備註
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 方法句柄不會在呼叫時執行存取檢查,而是在建立時執行存取檢查。 因此,建立方法句柄時,必須強制執行方法句柄存取限制。 強制執行這些限制的呼叫端類別稱為 #lookupClass 查閱類別。
需要建立方法句柄的查閱類別將會呼叫 #lookup MethodHandles.lookup
來建立本身的處理站。 Lookup
建立 Factory 物件時,會決定查閱類別的身分識別,並安全地儲存在物件中Lookup
。 查閱類別(或其委派)接著可以在 物件上使用 Lookup
Factory 方法,為存取檢查的成員建立方法句柄。 這包括允許查閱類別的所有方法、建構函式和欄位,甚至是私人方法。
<h1>“lookups<”>Lookup Factory 方法/h1> 物件上的 Lookup
Factory 方法會對應至方法、建構函式和字段的所有主要使用案例。 Factory 方法所建立的每個方法句柄都是特定 <em>bytecode 行為</em> 的功能對等專案。 (Java 虛擬機規格的第 5.4.3.5 節會說明 Bytecode 行為。以下是這些處理站方法與結果方法句柄行為之間的對應摘要:<表格框線=1 cellpadding=5 summary=“lookup method behaviors”><tr<>th“equiv”>lookup expression</<>th> th>member</<>th th>bytecode behavior</th></tr><tr><td>java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)
</td><>FT f;
<>< td/td<>(T) this.f;
/tr><><tr><td><java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)
/><td td><static
br>FT f;
</td><td>><(T) C.f;
</<<><java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)
>>tr td/FT f;
<><><<this.f = x;
>>><td/tr<<>><java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)
> td/static
><>>FT f;
<<td td br/><><C.f = arg;
td td/td>< td/tr tr><><td><java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)
/td><td>T m(A*);
</td><td>(T) this.m(arg*);
</>java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)
<>><<<>td/tr td/<>static
><td td br>T m(A*);
</><>(T) C.m(arg*);
<><td td/td/tr<<>>tdjava.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)
<>/<>>T m(A*);
<<<(T) super.m(arg*);
>>><td td/tr tr><><td>java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)
</td><td>C(A*);
</td><td><new C(arg*);
<>/tr<<>>tr td<java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)
>/td><td>(static
)?<br><FT f;
/td><td/td><>(FT) aField.get(thisOrNull);
</tr><tr><td>java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)
</td td><>(static
)?<br><FT f;
/td><td/td><>aField.set(thisOrNull, arg);
</tr><tr><td>java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)
</td td><>(static
)?<br>T m(A*);
</td><td/td><>(T) aMethod.invoke(thisOrNull, arg*);
</tr>><java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)
<>< td/td><><C(A*);
td/td<<><>>(C) aConstructor.newInstance(arg*);
td/tr<><>tr tdjava.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)
<>/td td<>>(static
)?<br>T m(A*);
</td><td/td><(T) aMethod.invoke(thisOrNull, arg*);
<>/tr></table>
在這裡,類型 C
是搜尋成員的類別或介面,記錄為查閱方法中名為 refc
的參數。 方法類型 MT
是由傳回型 T
別和自變數類型的 A*
序列所組成。 建構函式也有一連串的自變數類型 A*
,並被視為傳回 型 C
別 的新建立物件。 MT
和欄位類型FT
都會記錄為名為 type
的參數。 正式參數 this
代表 型 C
別的自我參考;如果存在,則一律是方法句柄調用的前置自變數。 (在某些成員的情況下 protected
, this
可能會限制在查閱類別的類型中;請參閱下方。名稱 arg
代表所有其他方法句柄自變數。 在核心反映 API 的程式代碼範例中,如果存取的方法或字段是靜態的,則名稱 thisOrNull
代表 Null 參考, this
否則為 Null 參考。 名稱 aMethod
、 aField
和 aConstructor
代表對應至指定成員的反光物件。
如果指定的成員是變數 arity(亦即方法或建構函式),傳回的方法句柄也會是 MethodHandle#asVarargsCollector 變數 arity。 在其他所有情況下,傳回的方法句柄將會是固定的arity。 <p style=“font-size:smaller;”><em>Discussion:</em> 查閱方法句柄與基礎類別成員與位元組程式代碼行為之間的等價,可以透過幾種方式細分: <ul style=“font-size:smaller;”><li>如果 C
無法從查閱類別的載入器以符號方式存取,則查閱仍然可以成功,即使沒有相等的 Java 表達式或位元組編碼常數也一樣。 <li>同樣地,如果 T
或 MT
無法透過符號方式從查閱類別的載入器存取,則查閱仍然可以成功。 例如,無論要求的類型為何,和 MethodHandle.invoke
的MethodHandle.invokeExact
查閱一律會成功。 <li>如果已安裝安全性管理員,則可以以各種理由禁止查閱(請參閱下方)。 相反地, ldc
常數上的 CONSTANT_MethodHandle
指令不受安全性管理員檢查的影響。 <li>如果查閱的方法有非常大的 Arity,則方法句柄建立可能會失敗,因為方法句柄類型有太多參數。 </ul>
<h1>“access”>Access checking</h1> 存取檢查會在 建立方法句柄時,套用在 的處理站方法 Lookup
中。 這是核心反映 API 的主要差異,因為 java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke
會在每個呼叫上針對每個呼叫端執行存取檢查。
所有存取檢查都是從 Lookup
對象開始,它會比較其記錄的查閱類別與建立方法句柄的所有要求。 單 Lookup
一物件可用來建立任意數目的存取檢查方法句柄,所有句柄都會針對單一查閱類別進行檢查。
Lookup
物件可以與其他受信任的程式代碼共用,例如 Metaobject 通訊協定。 共享 Lookup
物件會委派在查閱類別的私人成員上建立方法句柄的功能。 即使特殊許可權程式代碼使用 Lookup
物件,存取檢查仍受限於原始查閱類別的許可權。
查閱可能會失敗,因為查閱類別無法存取包含類別,或因為缺少所需的類別成員,或因為查閱類別無法存取所需的類別成員,或因為查閱物件不夠受信任而無法存取成員。 在這些情況下, ReflectiveOperationException
將會從嘗試的查閱擲回 。 確切類別會是下列其中一項:ul>li NoSuchMethodException —如果要求方法但不存在 li NoSuchFieldException —如果已要求字段,但不存在 li>>IllegalAccessException —如果成員存在<<但存取檢查失敗<,則為 /ul><<>
一般而言,查詢方法 M
句柄的條件不會比查閱類別可能編譯、驗證及解析對 M
的呼叫條件更嚴格。 當 JVM 引發類似 的 NoSuchMethodError
例外狀況時,方法句柄查閱通常會引發對應的已檢查例外狀況,例如 NoSuchMethodException
。 而叫用查閱所產生的方法句柄效果與執行編譯、驗證和解析對 M
的呼叫完全相等。 欄位和建構函式的相同點也是如此。 <p style=“font-size:smaller;”><em>Discussion:</em> Access 檢查僅適用於具名和反映的方法、建構函式和字段。 其他方法會處理建立方法,例如 MethodHandle#asType MethodHandle.asType
,不需要任何存取檢查,而且與任何 Lookup
對象無關。
如果所需的成員為 protected
,則會套用一般 JVM 規則,包括查閱類別必須位於與所需成員相同的套件中,或必須繼承該成員的需求。 (請參閱 Java 虛擬機規格、4.9.2、5.4.3.5 和 6.4 節。此外,如果所需的成員是不同封裝中的非靜態欄位或方法,則產生的方法句柄只能套用至查閱類別的物件或其子類別的其中一個。 這項需求是藉由將前置 this
參數的類型從 C
(這一定是查閱類別的超類別) 縮小到查閱類別本身來強制執行。
JVM 會對指令施加類似的需求 invokespecial
,表示接收者自變數必須符合已解析的方法 <em>和</em> 目前的類別。 同樣地,這項需求是藉由將前置參數的類型縮小為產生的方法句柄來強制執行。 (請參閱 Java 虛擬機規格,第 4.10.1.9 節。
JVM 會將建構函式和靜態初始化運算式區塊表示為具有特殊名稱 ("<init>"
和 "<clinit>"
) 的內部方法。 調用指令的內部語法可讓它們參考這類內部方法,就像是一般方法一樣,但 JVM 位元組程式代碼驗證程式會拒絕它們。 這類內部方法的查閱會產生 NoSuchMethodException
。
在某些情況下,Java 編譯程式會藉由建立包裝函式方法來存取相同最上層宣告中另一個類別的私人方法,來取得巢狀類別之間的存取。 例如,巢狀類別C.D
可以存取 、、 或 C.B
等其他C
C.D.E
相關類別內的私用成員,但 Java 編譯程式可能需要在這些相關類別中產生包裝函式方法。 在這種情況下, Lookup
上的 C.E
對象將無法使用這些私用成員。 這項限制的因應措施是 Lookup#in Lookup.in
方法,可將查閱轉換成任何其他類別上的查閱 C.E
,而不需要特殊許可權提升。
允許存取指定查閱物件的存取權可能會受限於 #lookupModes lookupModes
查閱類別通常可存取的成員子集。 例如, #publicLookup publicLookup
方法會產生只允許存取公用類別中的公用成員的查閱物件。 呼叫端敏感性方法 #lookup lookup
會產生具有與其呼叫端類別相關完整功能的查閱物件,以模擬所有支援的位元組程式代碼行為。 此外, Lookup#in Lookup.in
方法可能會產生存取模式比原始查閱物件少的查閱物件。
<p style=“font-size:smaller;”> ”privacc“><>em 私人存取的討論:</em> 我們說,如果查閱 #lookupModes 查閱模式包含存取private
成員的可能性,則查閱具有 <em>private access</em>。 如其他地方的相關方法所述,只有具有私人存取權的查閱具有下列功能:<ul style=“font-size:smaller;”><li>存取查閱類別 <li>create 方法的私人字段、方法和建構函式會處理叫用呼叫端敏感性方法的句柄,例如 li create 方法句柄Lookup#findSpecial emulate invokespecial
,<而<Class.forName
li>會避免套件存取檢查查閱類別 <li create 可存取的類別,>而 li>create Lookup#in delegated lookup objects
具有相同套件成員 </ul><p style=“font-size 內其他類別的私人存取權:smaller;”>這些許可權都是因為具有私用存取權的查閱物件可以安全地追蹤回原始類別,其位元組程式代碼行為和 Java 語言存取權限可由方法句柄可靠地判斷和模擬。
<h1>“secmgr”>Security manager interactions</h1> 雖然位元組程式代碼指令只能參考相關類別載入器中的類別,但只要有對象的參考 Class
可用,此 API 就可以在任何類別中搜尋方法。 核心反映 API 也可以使用這類跨載入器參考,而且無法位元組程式代碼指示,例如 invokestatic
或 getfield
。 有 java.lang.SecurityManager 安全性管理員 API 可讓應用程式檢查這類跨載入器參考。 這些檢查同時MethodHandles.Lookup
適用於 API 和核心反映 API(如 上找到)。java.lang.Class Class
如果安全性管理員存在,成員查閱會受限於其他檢查。 從一到三個呼叫會呼叫安全性管理員。 這些呼叫中的任何一個 java.lang.SecurityException SecurityException
都可以擲回 來拒絕存取。 將定義為 smgr
安全性管理員、 lookc
做為目前查閱物件的查閱類別、 refc
作為要搜尋成員所在的包含類別,以及 defc
做為實際定義成員的類別。 lookc
如果目前的查閱對象沒有私用存取權,此值會定義為 <em> 不存在</em>。 呼叫會根據下列規則進行:ul>li b 步驟 1:</b> 如果lookc
不存在,或者其類別載入器與 的類別載入器或 類別載入器refc
祖系不同,則會SecurityManager#checkPackageAccess smgr.checkPackageAccess(refcPkg)
呼叫 ,其中 refcPkg
是 的refc
封裝。>><<< <li><b>步驟 2:</b> 如果擷取的成員不是公用且lookc
不存在,則會SecurityManager#checkPermission smgr.checkPermission
RuntimePermission("accessDeclaredMembers")
使用 呼叫 。 <li><b>步驟 3:</b> 如果擷取的成員不是公用的,如果不存在,而且 如果lookc
defc
和 refc
不同,SecurityManager#checkPackageAccess smgr.checkPackageAccess(defcPkg)
則會呼叫 ,其中 defcPkg
是 的defc
封裝。 </ul> 安全性檢查會在其他存取檢查通過之後執行。 因此,上述規則會預先提供公用的成員,或者從具有存取成員許可權的查閱類別存取。
<h1>“callsens”>Caller sensitive methods</h1> 少數 Java 方法具有稱為呼叫端敏感度的特殊屬性。 <em>caller-sensitive</em> 方法的行為可能會根據其立即呼叫者的身分識別而有所不同。
如果要求呼叫端敏感性方法的方法句柄,則會套用位元組程式代碼行為的一般規則,但會以特殊方式考慮查閱類別。 產生的方法句柄的行為就像是從查閱類別中包含的指令呼叫,讓呼叫端敏感方法偵測查閱類別。 (相反地,會忽略方法句柄的叫用者。因此,在呼叫端區分方法的情況下,不同的查閱類別可能會產生不同的行為方法句柄。
如果查閱物件是 #publicLookup publicLookup()
,或某些沒有私用存取的其他查閱物件,則會忽略查閱類別。 在這種情況下,無法建立任何區分呼叫端的方法句柄、禁止存取,而且查閱會失敗並出現 IllegalAccessException
。 <p style=“font-size:smaller;”><em>Discussion:</em> 例如,呼叫端敏感性方法 java.lang.Class#forName(String) Class.forName(x)
可以傳回不同的類別或擲回不同的例外狀況,視呼叫它的類別載入器而定。 的公開查閱 Class.forName
將會失敗,因為沒有合理的方法來判斷其位元組程序代碼行為。 <p style=“font-size:smaller;”> 如果應用程式快取方法會處理廣泛共用,則應該使用 publicLookup()
來建立它們。 如果有 查閱 Class.forName
,將會失敗,而且應用程式在該情況下必須採取適當的動作。 可能是稍後的查閱,也許是在叫用啟動程式方法期間,可以併入呼叫端的特定身分識別,讓方法可供存取。 <p style=“font-size:smaller;”> 函式 MethodHandles.lookup
會區分呼叫端,以便有一個安全的查閱基礎。 JSR 292 API 中幾乎所有的其他方法都依賴查閱對象來檢查存取要求。
的 java.lang.invoke.MethodHandles.Lookup
Java 檔。
此頁面的部分是根據 Android 開放原始碼專案所建立和共用的工作進行修改,並根據 Creative Commons 2.5 屬性授權中所述的詞彙使用。
欄位
Package |
已淘汰.
表示 |
Private |
已淘汰.
表示 |
Protected |
已淘汰.
表示 |
Public |
已淘汰.
表示 |
屬性
Class |
傳回這個 |
Handle |
基礎Android實例的句柄。 (繼承來源 Object) |
JniIdentityHashCode |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
JniPeerMembers |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 |
PeerReference |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
ThresholdClass |
此 API 支援適用於 Android 的 Mono 基礎結構,並不適合直接從您的程式代碼使用。 (繼承來源 Object) |
ThresholdType |
此 API 支援適用於 Android 的 Mono 基礎結構,並不適合直接從您的程式代碼使用。 (繼承來源 Object) |
方法
Bind(Object, String, MethodType) |
產生非靜態方法的早期綁定方法句柄。 |
Clone() |
建立並傳回這個 對象的複本。 (繼承來源 Object) |
Dispose() |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
Dispose(Boolean) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
Equals(Object) |
指出其他物件是否「等於」這個物件。 (繼承來源 Object) |
FindConstructor(Class, MethodType) |
產生方法句柄,這個句柄會使用指定型別的建構函式建立物件並初始化它。 |
FindGetter(Class, String, Class) |
產生方法句柄,授與非靜態字段的讀取許可權。 |
FindSetter(Class, String, Class) |
產生方法句柄,授與非靜態字段的寫入許可權。 |
FindSpecial(Class, String, MethodType, Class) |
產生虛擬方法的早期綁定方法句柄。 |
FindStatic(Class, String, MethodType) |
產生靜態方法的方法句柄。 |
FindStaticGetter(Class, String, Class) |
產生方法句柄,提供靜態欄位的讀取許可權。 |
FindStaticSetter(Class, String, Class) |
產生方法句柄,提供靜態字段的寫入許可權。 |
FindStaticVarHandle(Class, String, Class) |
產生 VarHandle,以存取類型 |
FindVarHandle(Class, String, Class) |
產生 VarHandle,以存取型別類別中宣告之類型的 |
FindVirtual(Class, String, MethodType) |
產生虛擬方法的方法句柄。 |
GetHashCode() |
傳回此物件的雜湊碼值。 (繼承來源 Object) |
In(Class) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 |
JavaFinalize() |
當垃圾收集決定不再參考物件時,垃圾收集行程在 物件上呼叫。 (繼承來源 Object) |
LookupClass() |
告知哪個類別正在執行查閱。 |
LookupModes() |
告知這個查閱物件可以產生哪些成員的存取保護類別。 |
Notify() |
喚醒正在等候此物件監視器的單一線程。 (繼承來源 Object) |
NotifyAll() |
喚醒正在等候此物件監視器的所有線程。 (繼承來源 Object) |
RevealDirect(MethodHandle) |
破解這個查閱物件或類似物件所建立的直接方法句柄。 |
SetHandle(IntPtr, JniHandleOwnership) |
設定 Handle 屬性。 (繼承來源 Object) |
ToArray<T>() |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
ToString() |
傳回物件的字串表示。 (繼承來源 Object) |
Unreflect(Method) |
如果查閱類別具有許可權,請將直接方法句柄 設為 m。 |
UnreflectConstructor(Constructor) |
產生反映建構函式的方法句柄。 |
UnreflectGetter(Field) |
產生方法句柄,提供反映欄位的讀取許可權。 |
UnreflectSetter(Field) |
產生方法句柄,提供反映欄位的寫入許可權。 |
UnreflectSpecial(Method, Class) |
產生反映方法的方法句柄。 |
UnreflectVarHandle(Field) |
產生 VarHandle,以存取型別類別 |
UnregisterFromRuntime() |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
Wait() |
讓目前線程等候直到喚醒為止,通常是藉由em <notified/em>或<em>interrupted</em> 來喚醒它。<> (繼承來源 Object) |
Wait(Int64, Int32) |
讓目前的線程等到喚醒為止,通常是因為 <em>notified</em> 或 <em>interrupted</em>,或直到經過一定數量的實時為止。 (繼承來源 Object) |
Wait(Int64) |
讓目前的線程等到喚醒為止,通常是因為 <em>notified</em> 或 <em>interrupted</em>,或直到經過一定數量的實時為止。 (繼承來源 Object) |
明確介面實作
IJavaPeerable.Disposed() |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
IJavaPeerable.DisposeUnlessReferenced() |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
IJavaPeerable.Finalized() |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
IJavaPeerable.JniManagedPeerState |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
IJavaPeerable.SetJniIdentityHashCode(Int32) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
IJavaPeerable.SetPeerReference(JniObjectReference) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 (繼承來源 Object) |
擴充方法
JavaCast<TResult>(IJavaObject) |
執行 Android 執行時間檢查的類型轉換。 |
JavaCast<TResult>(IJavaObject) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 |
GetJniTypeName(IJavaPeerable) |
<em>lookup 物件</em> 是建立方法句柄的處理站,當建立需要存取檢查時。 |