![](/img/trans.png)
[英]Hi I want to print all the palindromic primes between 2 numbers the user inputs
[英]I want to print hi GrandFather;but it seems to print hi father
我想打印hi GrandFather
但它似乎打印喜父親。 我不明白如何findSpecial
和findVirtual
之間的使用
我想要有人可以幫助我。 謝謝
class GrandFather{
void thinking(){
System.out.println("hi GrandFather");
}
}
class Father extends GrandFather{
void thinking(){
System.out.println("hi Father");
}
}
class Son extends Father{
void thinking(){
MethodType mt=MethodType.methodType(void.class);
//MethodHandle mh=MethodHandles.lookup().findVirtual(GrandFather.class,"thinking",mt).bindTo(this);
MethodHandle mh;
mh = MethodHandles.lookup().findSpecial(GrandFather.class,"thinking",mt,getClass());
mh.invoke(this);
}
}
public static void main(String[] args){
(new MethodHandleTest().new Son()).thinking();
}
findSpecial
的最后一個參數指定調用的上下文類。 您指定了getClass()
,這將導致Son.class
。 來自Son
的super
調用只能在Father
結束,就像源代碼中的普通super.thinking()
調用一樣。
您需要將Father.class
指定為上下文類,因為允許Father
對GrandFather
執行super
調用。 如果您在沒有進一步更改的情況下執行此操作,您將收到類似java.lang.IllegalAccessException: no private access for invokespecial…
的異常。 您必須更改您的lookup()
對象的上下文,才能訪問Father
private
功能:
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = MethodHandles.lookup().in(Father.class)
.findSpecial(GrandFather.class, "thinking", mt, Father.class);
mh.invoke(this);
這是有效的,因為Son
和Father
是同一個頂級類的內部類,因此允許訪問彼此的私有成員。 如果它們不是同一頂級類中的類,則in(…)
將更改上下文類但清除私有訪問權限。 在這種情況下,只有 Java 9 及更新版本有官方解決方案:
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = MethodHandles.privateLookupIn(Father.class, MethodHandles.lookup())
.findSpecial(GrandFather.class, "thinking", mt, Father.class);
mh.invoke(this);
當Father
和Son
在同一個模塊中或Father
的模塊已將Father
的包打開到Son
的模塊進行反射時,此方法有效。
Holger 像往常一樣是正確的。 我實際上花了一段時間才明白發生了什么,請將其視為對另一個非常好的答案的修正。 為了理解這一點,我不得不做 3 個不同的例子。
public class FindSpecialFailure {
public static void main(String[] args) {
try {
MethodType mt = MethodType.methodType(void.class);
Lookup l = MethodHandles.lookup();
MethodHandle mh = l.findSpecial(Son.class, "go", mt, Son.class);
mh.invoke(new Son());
} catch (Throwable t) {
t.printStackTrace();
}
}
static class Parent {
void go() {
System.out.println("parent");
}
}
static class Son extends Parent {
void go() {
System.out.println("son");
}
}
}
如果你運行它,它會失敗並顯示java.lang.IllegalAccessException: no private access for invokespecial...
。 文檔給出了為什么會發生這種情況的正確說明:
通常,可以為方法 M 查找方法句柄的條件並不比查找類可以編譯、驗證和解析對 M 的調用的條件更具限制性。
相同的文檔也解釋了這一點:
強制執行這些限制的調用者類稱為查找類。
在我們的例子中, lookup class
是FindSpecialFailure
,因此,這將用於判斷來自Son.class
方法go
Son.class
可以被編譯、驗證和解析。
你可以想得更簡單一點。 你能(理論上)在FindSpecialFailure::main
創建一個invokeSpecial
字節碼指令並調用它嗎? 再次,理論上。 你可以在那里創建它:
invokeSpecial Son.go:()V
你能調用它嗎? 嗯,沒有; 具體來說,以我的理解,這條規則將被打破:
如果符號引用命名一個類(不是接口),則該類是當前類的超類。
顯然Son
不是FindSpecialFailure
的超類。
為了證明我的觀點,您可以將上面的代碼更改為(第二個示例):
// example 1
public class FindSpecialInterface {
public static void main(String[] args) {
try {
MethodType mt = MethodType.methodType(void.class);
Lookup l = MethodHandles.lookup();
// <---- Parent.class
MethodHandle mh = l.findSpecial(Parent.class, "go", mt, Son.class);
mh.invoke(new Son());
} catch (Throwable t) {
t.printStackTrace();
}
}
// <---- this is now an interface
interface Parent {
default void go() {
System.out.println("parent");
}
}
static class Son implements Parent {
public void go() {
System.out.println("son");
}
}
}
這一次一切都會正常工作,因為( 來自相同的規范):
否則,如果 C 是一個接口並且類 Object 包含一個與解析方法具有相同名稱和描述符的公共實例方法的聲明,那么它就是要調用的方法。
我如何修復第一個例子? ( FindSpecialFailure
) 您需要添加一個有趣的選項:
public static void main(String[] args) {
try {
MethodType mt = MethodType.methodType(void.class);
// <--- Notice the .in(Son.class) -->
Lookup l = MethodHandles.lookup().in(Son.class);
MethodHandle mh = l.findSpecial(Son.class, "go", mt, Son.class);
mh.invoke(new Son());
} catch (Throwable t) {
t.printStackTrace();
}
}
如果您轉到相同的文檔,您會發現:
在某些情況下,嵌套類之間的訪問是由 Java 編譯器通過創建包裝器方法來訪問同一頂級聲明中另一個類的私有方法來獲得的。 例如,嵌套類 CD 可以訪問其他相關類(如 C、CDE 或 CB)中的私有成員,但 Java 編譯器可能需要在這些相關類中生成包裝方法。 在這種情況下,CE 上的 Lookup 對象將無法訪問這些私有成員。 此限制的一種解決方法是 Lookup.in 方法,它可以將 CE 上的查找轉換為任何其他類上的查找,無需特殊提升特權。
第三個例子不知何故開始看起來更像你的例子:
public class FinSpecialMoveIntoSon {
public static void main(String[] args) {
new Son().invokeMe();
}
static class Parent {
public void go() {
System.out.println("parent");
}
}
static class Son extends Parent {
void invokeMe() {
try {
MethodType mt = MethodType.methodType(void.class);
Lookup l = MethodHandles.lookup();
MethodHandle mh = l.findSpecial(Son.class, "go", mt, Son.class);
mh.invoke(new Son());
} catch (Throwable t) {
t.printStackTrace();
}
}
public void go() {
System.out.println("son");
}
}
}
這個問題的重點是findSpecial
的文檔說明了第一個參數:
refc 訪問方法的類或接口。
這就是為什么它會打印Son
而不是Parent
。
有了這個,你的例子就更容易理解了:
static class Son extends Father {
void thinking() {
try {
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = MethodHandles.lookup().findSpecial(GrandFather.class, "thinking", mt, getClass());
mh.invoke(this);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
查找類是Son.class
,方法解析和refc
(從那里訪問方法的類或接口)是GranFather
。 所以決議確實從GrandFather::thinking
開始,但由於你不能在java中調用super.super
方法,所以它被“降級”為Father::thinking
。
我在這里只能建議使用.in
來解決這個問題,我不知道privateLookupIn
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.