MethodHandles.Lookup 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
<EM>查找物件</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>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 方法句柄在被呼叫時不會進行存取檢查,而是在建立時進行。 因此,在建立方法句柄時,必須強制執行方法句柄存取限制。 執行這些限制的呼叫類別稱為 #lookupClass 查詢類別。
需要建立方法句柄的查找類別會呼叫 #lookup MethodHandles.lookup 為自己建立工廠。 當 Lookup 工廠物件建立時,查詢類別的身份會被確定,並安全地儲存在物件 Lookup 中。 查找類別(或其代理)接著可以使用物件上的 Lookup 工廠方法,為存取檢查成員建立方法句柄。 這包括所有允許進入查找類別的方法、建構子和欄位,甚至是私有的。
<h1>“lookups”> Lookup Factory 方法</h1> 物件上的 Lookup 工廠方法對應所有主要的方法、建構子與欄位的使用情境。 工廠方法建立的每個方法句柄,都是特定 <em>位元組碼行為</em> 的功能等價物。 (位元組碼行為詳見 Java 虛擬機規範第 5.4.3.5 節。)以下是這些工廠方法與所得方法處理行為之間的對應關係摘要:<table border=1 cellpadding=5 summary=“查找方法行為”><tr><th>“等值”查找>表達式</th><th 成員></th><th 位>元組碼行為</th></tr><tr td><>java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)</td><td>FT f;</td td/ td td/><>(T) this.f;<達陣>/達陣<>TR TD<><>java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)/TD<><>staticTD BR<>FT f;/TD TD<><>(T) C.f;</TD>/TR<>TR TD<><>java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)/TD<>TD<>FT f;/TD<><>this.f = x;<>/TD/TR TR TD/TD TD/TD/TR<>TR TD<><>java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)/TD<>TD<>staticBR/TD<>FT f;< TD><>C.f = arg;/<>TD/TR<><翻譯><達陣>java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)</達陣><TD>T m(A*);</TD><達>(T) this.m(arg*);<陣/><TD/TR><TR TD><>java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)</TD><TD>static<達陣 BR>T m(A*);</TD TD><>(T) C.m(arg*);<>/TD</TR><TR TD><>java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)</TD TD><>/TD TR Tr TD/TDT 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*);<></TR><TR TD><>java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)</TD(>)?<>static<BR>FT f;</TD><TD>(FT) aField.get(thisOrNull);</TD></TR><TR TD><>java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)</TD(>達<>static陣)?<BR>FT f;</TD><TD>aField.set(thisOrNull, arg);</TD></TR><TR TD><>java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)</TD(>達<>static陣)?<BR>T m(A*);</TD><TD>(T) aMethod.invoke(thisOrNull, arg*);</TD></TR><TR><TD>java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)</TD TD><>/TDC(A*);</TD TD/TD><>(C) aConstructor.newInstance(arg*);<></TR><TR TD><>java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)</TD( 達陣/TD><> TD(static)?<BR>T m(A*);</TD><TD>(T) aMethod.invoke(thisOrNull, arg*);</TD/TD></TR/Table><>
此時,型別 C 是正在搜尋成員的類別或介面,並以查找方法中命名 refc 的參數形式記錄。 方法型別 MT 由返回型態 T 與參數類型 A*序列組成。 建構子同時擁有一連串參數類型 A* ,並被視為回傳新建立的類型 C物件。
MT以及欄位類型FT都以名為 type的參數形式記錄。 形式參數 this 代表型別 C的自指;若存在,則它總是方法句柄調用的首參數。 (在某些 protected 成員的情況下,型 this 別可能限制於查找類別;詳見下文。)這個名稱 arg 代表所有其他方法的 handle 參數。 在核心反射 API 的程式碼範例中,若存取的方法或欄位為靜態thisOrNull,則該名稱this代表空參考,否則則不然。 名稱 aMethod、 aField、 aConstructor 代表對應給定構件的反射物體。
若該成員為變數元數(即方法或建構子),回傳的方法句柄也會是 MethodHandle#asVarargsCollector 變數元數。 在其他情況下,回傳的方法 handle 將具有固定的數值。
<em>討論:</em> 查找方法的代言碼與底層類別成員及位元組碼行為之間的等價性可分為幾種方式:<ul style=“font-size:smaller;「><li>如果 C 無法從查找類別的載入器符號上存取,即使沒有對應的 Java 表達式或位元組碼常數,查詢仍可成功。
<同>理,如果TMT查找類別的載入器符號上無法存取,查詢仍可成功。 例如,查詢 和 MethodHandle.invokeExactMethodHandle.invoke 都會成功,無論請求的類型為何。
<li>如果安裝了安全管理員,可能會基於各種理由禁止查詢(見下文)。 相較之下, ldc 常 CONSTANT_MethodHandle 數的指令不受安全管理人員的檢查。
<li>如果查找方法的元數非常大,方法代碼建立可能會失敗,因為該方法代碼型別參數過多。
</ul>
<h1>「存取」>存取檢查</h1> 存取檢查會在工廠方法 Lookup中套用,當建立方法句柄時。 這是與 Core Reflection API 的主要差異,因為 java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke 它會對每個呼叫者、每次通話進行存取檢查。
所有存取檢查都從一個 Lookup 物件開始,該物件會將其記錄的查找類別與所有建立方法句柄的請求進行比較。
Lookup單一物件可用來建立任意數量的存取檢查方法句柄,且全部透過單一查找類別進行檢查。
物件 Lookup 可以與其他受信任的程式碼共享,例如元物件協定。 共享 Lookup 物件授權在查找類別的私有成員上建立方法句柄的能力。 即使有特權程式碼使用該 Lookup 物件,存取檢查仍限於原始查找類別的權限。
查詢可能失敗,原因可能是包含的類別無法被查找類別存取,或是缺少所需的類別成員,或是查詢類別無法存取所需的類別成員,或是查詢物件不夠被信任而無法存取該成員。 在這些情況下,嘗試查詢時會拋棄 a ReflectiveOperationException 。 該類別的具體類別如下:<ul><li>NoSuchMethodException —若請求方法但不存在<,則為 li>NoSuchFieldException —若請求欄位但不存在<,則為 li>IllegalAccessException —若該成員存在但存取檢查失敗<,則為 /ul>
一般而言,查找 M 方法處理的條件與查找類別編譯、驗證及解析呼叫 M的條件限制不大。 JVM 會像 NoSuchMethodError,例如 ,方法處理查詢通常會產生相應的檢查異常,例如 NoSuchMethodException。 而調用由查詢產生的方法句柄的效果,正好等同於執行已編譯、驗證並解析的呼叫。M 場與構造子亦然。
<em>討論:</em> 存取檢查僅適用於命名及反映的方法、建構子與欄位。 其他方法的句柄建立方法,如 MethodHandle#asType MethodHandle.asType,則不需任何存取檢查,且可獨立於任何 Lookup 物件使用。
若期望成員為 protected,則適用一般 JVM 規則,包括查詢類別必須與期望成員在同一封裝中,或必須繼承該成員。 (參見 Java 虛擬機器規範,第 4.9.2、5.4.3.5 及 6.4 節。)此外,若所需成員是不同套件中的非靜態欄位或方法,所得方法的句柄只能套用於查找類別或其子類別的物件。 此要求透過將首參數 thisC 類型從(必然是查找類別的超類別)縮小到查找類別本身來強制執行。
JVM 對指令也施加類似要求 invokespecial ,即接收端參數必須同時匹配已解析的方法 <em>和</em> 目前類別。 同樣地,此要求是透過縮小領先參數的類型至所得方法的handle來強制執行。 (詳見 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 方法可能產生的查詢物件存取模式比原始查詢物件少。
「privacc」><em>關於私人存取的討論:</em> 如果查詢的 #lookupModes 查詢模式包含存取成員的可能性<,我們稱其為 >em<private access>/emprivate。 如其他相關方法所述,只有具備私密存取權的查詢才具備以下功能:<ul style=“font-size:smaller;”><LI>存取 lookup 類別<的私有欄位、方法與構造子 LI>建立方法句柄,呼叫呼叫者敏感的方法,例如Class.forName< LI>建立方法句柄,LI Lookup#findSpecial emulate invokespecial 指令 <LI>避免套件存取檢查 對 Lookup 類別<>可存取的類別 LI Create Lookup#in delegated lookup objects 擁有對同一套件成員<內其他類別的私有存取權限 /ul>
這些權限都是因為具有私有存取權的查詢物件可以安全追溯到原始類別,該類別的位元組碼行為與 Java 語言存取權限可由方法句柄可靠地確定並模擬。
<h1>「secmgr」>安全管理員互動/<h1> 雖然位元組碼指令只能參考相關類別載入器中的類別,但此 API 能在任何類別中搜尋方法,只要有物件的 Class 參考。 此類交叉載入參考也可透過核心反射 API 實現,且無法以位元組碼指令(如 invokestatic 或 getfield)進行。 有 java.lang.SecurityManager 安全管理 API 讓應用程式檢查此類交叉載入器參考。 這些檢查同時MethodHandles.Lookup適用於 API 與核心反射 API(如 Access)。java.lang.Class Class
若有安全經理在場,會員查詢會受到額外檢查。 會撥打一到三通電話給保全經理。 這些通話中的任何一通都可以透過拋出 java.lang.SecurityException SecurityException. 來拒絕存取。 定義 smgr 為安全管理器,定義 lookc 為目前查找物件的查找類別, refc 作為尋找該成員的包含類別,以及 defc 該成員實際被定義的類別。
lookc若目前查找物件沒有私有存取權,則定義<為 em>not present</em>。 呼叫依據以下規則進行:ul<li b 步驟 1:>/b< 若><不存在,或其類別載入器與類別載入器不同或非 的>前祖,則 < 被調用為 ,其中 > 是 的lookc封包。refcSecurityManager#checkPackageAccess smgr.checkPackageAccess(refcPkg)refcPkgrefc
<li><b>步驟 2:</b> 如果檢索的成員不是公開的且lookc不存在,則SecurityManager#checkPermission smgr.checkPermission呼叫 。RuntimePermission("accessDeclaredMembers")
<li><b>步驟 3:</b> 如果檢索的成員不是公有的,且 lookc 不存在,defcrefc且 與 不同,則 SecurityManager#checkPackageAccess smgr.checkPackageAccess(defcPkg) 被調用,其中 defcPkg 是 的defc封包。
</ul> 安全性檢查是在其他存取檢查通過後才執行。 因此,上述規則假設成員是公開的,或是從有權存取該成員的查詢類別中被存取。
<h1>「callsens」>呼叫敏感方法</h1> 少數 Java 方法具有特殊特性,稱為呼叫敏感度。 <EM>呼叫者敏感</EM> 方法的行為會根據其直接呼叫者的身份而有所不同。
若請求呼叫者敏感方法的方法句柄,則會適用位元組碼行為的一般規則,但會以特殊方式考量查找類別。 所得的方法代碼行為就像是從查找類別中包含的指令中呼叫,因此呼叫者敏感的方法會偵測到該查詢類別。 (相較之下,方法代號的調用者則被忽略。)因此,在呼叫者敏感方法的情況下,不同的查找類別可能導致行為不同的方法代柄。
若查詢物件為 #publicLookup publicLookup(),或是其他沒有私人存取權限的查詢物件,查詢類別會被忽略。 在這種情況下,無法建立呼叫者敏感的方法句柄,禁止存取,查詢也會 IllegalAccessException因 。
<em>討論:</em> 例如,呼叫者敏感方法 java.lang.Class#forName(String) Class.forName(x) 可以回傳不同的類別或拋出不同的例外,取決於呼叫該類別的類別載入器。 公開查詢 Class.forName 會失敗,因為沒有合理方法能判斷其位元組碼行為。
如果應用程式快取方法能處理廣泛分享,應該使用它 publicLookup() 來建立它們。 若對 有查詢 Class.forName,則會失敗,應用程式必須採取適當行動。 或許在後續查詢時,例如在呼叫啟動法時,可以納入呼叫者的具體身份,使該方法變得可及。
這個函式 MethodHandles.lookup 是呼叫者敏感的,這樣可以有安全的查詢基礎。 JSR 292 API 中幾乎所有其他方法都依賴查找物件來檢查存取請求。
Java 文件 java.lang.invoke.MethodHandles.Lookup。
本頁部分內容為基於 Open Source Project 所創建與分享的作品,並依授權條款所描述的使用進行修改。
欄位
| 名稱 | Description |
|---|---|
| Package |
已淘汰.
一個代表 |
| Private |
已淘汰.
一個代表 |
| Protected |
已淘汰.
一個代表 |
| Public |
已淘汰.
一個代表 |
屬性
| 名稱 | Description |
|---|---|
| Class |
回傳此 |
| Handle |
底層 Android 實例的帳號。 (繼承來源 Object) |
| JniIdentityHashCode |
取得由互通執行時指派給此 Java 對等端的身份雜湊碼。 (繼承來源 Object) |
| JniManagedPeerState |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| JniPeerMembers |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 |
| PeerReference |
取得這個 Java 節點的 JNI 物件參考。 (繼承來源 Object) |
| ThresholdClass |
此 API 支援 Mono for Android 基礎架構,並非直接從你的程式碼中使用。 (繼承來源 Object) |
| ThresholdType |
此 API 支援 Mono for Android 基礎架構,並非直接從你的程式碼中使用。 (繼承來源 Object) |
方法
| 名稱 | Description |
|---|---|
| Bind(Object, String, MethodType) |
產生一個非靜態方法的早綁方法句柄。 |
| Clone() |
建立並回傳此物件的副本。 (繼承來源 Object) |
| Construct(JniObjectReference, JniObjectReferenceOptions) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| Dispose() |
釋放該 Java 節點所持有的資源。 (繼承來源 Object) |
| Dispose(Boolean) |
釋放該 Java 節點所持有的資源。 (繼承來源 Object) |
| DisposeUnlessReferenced() |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| Equals(Object) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| 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) |
建立一個針對指定的新查詢類別的查詢。 |
| JavaFinalize() |
已淘汰.
當垃圾回收判定該物件不再有相關參考時,由垃圾回收器呼叫。 (繼承來源 Object) |
| LookupClass() |
告訴你是哪個類別正在執行查找。 |
| LookupModes() |
告訴該查詢物件能產生哪些存取保護類別的成員。 |
| Notify() |
喚醒一個正在該物件監視器上等待的執行緒。 (繼承來源 Object) |
| NotifyAll() |
喚醒所有等待該物件監視器的執行緒。 (繼承來源 Object) |
| RevealDirect(MethodHandle) |
破解由此查找物件或類似物件所建立的直接方法指柄。 |
| SetHandle(IntPtr, JniHandleOwnership) |
設定 Handle 屬性。 (繼承來源 Object) |
| SetPeerReference(JniObjectReference, JniObjectReferenceOptions) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| ToArray<T>() |
從這個 Java 陣列包裝器建立一個受管理陣列。 (繼承來源 Object) |
| ToString() |
回傳物件的字串表示。 (繼承來源 Object) |
| Unreflect(Method) |
如果查找類別有權限,會直接將方法句柄傳到 m。 |
| UnreflectConstructor(Constructor) |
產生一個反射建構子的方法柄。 |
| UnreflectGetter(Field) |
產生一個方法代柄,讓讀取能存取反射欄位。 |
| UnreflectSetter(Field) |
產生一個方法句柄,允許對反射欄位進行寫入存取。 |
| UnreflectSpecial(Method, Class) |
產生一個反射方法的方法柄。 |
| UnreflectVarHandle(Field) |
產生一個 VarHandle,提供存取類型中宣告 |
| UnregisterFromRuntime() |
將此 Java 節點從互通執行時中取消註冊。 (繼承來源 Object) |
| Wait() |
導致目前執行緒等待被喚醒,通常是透過 <em>通知</><em 或 em>中斷</em> 來喚醒。 (繼承來源 Object) |
| Wait(Int64, Int32) |
會讓目前執行緒等待喚醒,通常是透過 <em>通知</><em 或 em>中斷</em>,或是經過一定的真實時間。 (繼承來源 Object) |
| Wait(Int64) |
會讓目前執行緒等待喚醒,通常是透過 <em>通知</><em 或 em>中斷</em>,或是經過一定的真實時間。 (繼承來源 Object) |
明確介面實作
| 名稱 | Description |
|---|---|
| IJavaPeerable.Disposed() |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| IJavaPeerable.Finalized() |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| IJavaPeerable.JniObjectReferenceControlBlock |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| IJavaPeerable.SetJniIdentityHashCode(Int32) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
| IJavaPeerable.SetPeerReference(JniObjectReference) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 (繼承來源 JavaObject) |
擴充方法
| 名稱 | Description |
|---|---|
| GetJniTypeName(IJavaPeerable) |
取得實例 |
| JavaAs<TResult>(IJavaPeerable) |
試著強制 |
| JavaCast<TResult>(IJavaObject) |
執行 Android 執行時檢查型別轉換。 |
| JavaCast<TResult>(IJavaObject) |
<EM>查找物件</em> 是建立方法句柄的工廠,當建立需要存取檢查時。 |
| TryJavaCast<TResult>(IJavaPeerable, TResult) |
試著強制 |