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 方法<會對應至方法、建構函式和字段的所有主要使用案例。 處理站方法所建立的每個方法句柄都是與特定 <em>位元組程式代碼行為</em> 相同的功能。 (Bytecode 行為會在 Java 虛擬機規格的第 5.4.3.5 節中說明 ) ,以下是這些處理站方法與結果方法句柄行為之間的對應摘要:<數據表 border=1 cellpadding=5 summary=“lookup method behaviors”><tr<>th>“equiv”>lookup expression</th member</th>bytecode behavior/th/th bytecode behavior</><>><><th/tr><><td>java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)
</Td><td>FT f;
</td><<(T) this.f;
>/td></tr>><<tdjava.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)
<>/td td brFT f;
<>/td><><<static
>(T) C.f;
>< td/td></tr<<<>>java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)
> tr td/><<this.f = x;
<>>>FT f;
<td/tr tr<java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)
><>>< td/<>td><>static
<>FT f;
<><Td>C.f = arg;
</td></tr><tr><td><java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)
/td><td/tdT m(A*);
></td>(T) this.m(arg*);
<><<>/trjava.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)
>><><< td/<><<>static
>T m(A*);
td td br/<>><(T) C.m(arg*);
td td td/td/tr tr><><<java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)
> td/td>T m(A*);
><><< td><>(T) super.m(arg*);
</Td></tr><tr><td><java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)
/td><td><C(A*);
/td td>new C(arg*);
</td><></tr><<>tdjava.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)
<>/td td<>> (static
) ?<br>FT f;
</td><td>(FT) aField.get(thisOrNull);
</td/tr>><<td></td td<java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)
><>> (static
) ?<br>FT f;
</td><td/td><aField.set(thisOrNull, arg);
/tr><<>td></tdjava.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)
<> td<>> (static
) ?<br><T m(A*);
/td><td/td>(T) aMethod.invoke(thisOrNull, arg*);
<<>/tr>><<td<>java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)
/tdC(A*);
><<> td/td/td>(C) aConstructor.newInstance(arg*);
<></<>tr>><<>java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)
< td/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.invokeExact
查閱 和 MethodHandle.invoke
一律會成功。 <li>如果已安裝安全性管理員,它可以禁止查閱各種 (請參閱下方) 。 相反地 ldc
,常數上的 CONSTANT_MethodHandle
指令不受安全性管理員檢查限制。 <li>如果查閱的方法具有非常大的arity,則方法句柄建立可能會失敗,因為方法句柄類型有太多參數。 </ul>
<h1>「存取」>存取檢查</h1> 存取檢查會在 建立方法句柄時套用在 的 Lookup
處理站方法中。 這是核心反映 API 的主要差異,因為 java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke
每次呼叫都會對每個呼叫端執行存取檢查。
所有存取檢查都會從 Lookup
對象開始,它會將其記錄的查閱類別與所有要求進行比較,以建立方法句柄。 單 Lookup
一物件可用來建立任意數目的存取檢查方法句柄,全都會針對單一查閱類別進行檢查。
Lookup
物件可以與其他受信任的程式代碼共用,例如中繼物件通訊協定。 共享 Lookup
物件會委派在查閱類別的私人成員上建立方法句柄的功能。 即使特殊許可權程式代碼使用 Lookup
物件,存取檢查仍受限於原始查閱類別的許可權。
查閱可能會失敗,因為查閱類別無法存取包含類別,或因為遺漏所需的類別成員,或因為查閱類別無法存取所需的類別成員,或因為查閱物件不受信任而無法存取成員。 在這些情況下, ReflectiveOperationException
將會從嘗試的查閱擲回 。 確切類別將是下列其中一項:ul>li NoSuchMethodException —如果要求方法但不存在 <li>NoSuchFieldException —如果要求字段但不存在 <li>IllegalAccessException &mdash,則為 ;如果成員存在但存取檢查失敗<,則為>/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
、 C.D.E
或 C.B
,但 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> 假設查閱具有 <em>private access</em> ,如果其 #lookupModes 查閱模式包含存取 private
成員的可能性。 如其他地方的相關方法所述,只有具有私人存取權的查閱具有下列功能:<ul style=“font-size:smaller;”><li>access private fields, methods, and constructors of the lookup class <li>create method handles which invoke caller sensitive methods, such<Class.forName
li>create method handles Lookup#findSpecial emulate invokespecial
which instructions <li>avoid package access checks for classes access for the lookup class <li>createLookup#in delegated lookup objects
, which have private access to other classes within the same package member </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>“callens”>Caller sensitive methods</h1> 少數 Java 方法具有稱為呼叫端敏感度的特殊屬性。 <em>呼叫端敏感</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 檔。
此頁面的部分是根據 所建立和共用的工作進行修改,並根據 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 支援 Mono for Android 基礎結構,並不適合直接從您的程式代碼使用。 (繼承來源 Object) |
ThresholdType |
此 API 支援 Mono for Android 基礎結構,並不適合直接從您的程式代碼使用。 (繼承來源 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) |
讓目前的線程等到喚醒為止,通常是<透過em>notified</em或em>interrupted</em>>,或<直到經過一定數量的實時為止。 (繼承來源 Object) |
Wait(Int64, Int32) |
讓目前的線程等到喚醒為止,通常是<透過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> 是建立方法句柄的處理站,當建立需要存取檢查時。 |