2 toponexds toponexds 于 2016.02.16 12:27 提问

《深入理解Java虚拟机》有关methodHandle的代码问题? 1C

以下代码书上说是输出“i am grandfather”,但远行实际输出为“i am father”
class Test {

class GrandFather {
void thinking() {
System.out.println("i am grandfather");
}
}

class Father extends GrandFather {
void thinking() {
System.out.println("i am father");
}
}

class Son extends Father {
void thinking() {
try {
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = lookup().findSpecial(GrandFather.class,
"thinking", mt, getClass());
mh.invoke(this);
} catch (Throwable e) {
}
}
}

public static void main(String[] args) {
    (new Test().new Son()).thinking();
}

}
求解!!

5个回答

wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.02.16 15:38

个人理解是这样的:invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法、私有方法和父类方法,对应findSpecial方法返回。此处,MethodHandles.lookup().findSpecial(GrandFather.class, "thinking", mt, getClass());你需要查找的是GrandFather类型,由当前Son类型作为调用者,调用父类的thinking方法。由于Son继承自Father,而Father又继承GrandFather,所以Son本质也是一个GrandFather类型。
那么查找GrandFather类型的thinking方法,并且是由Son作为子类调用,最终得到的方法就是Father类的thinking()。
这个方法的api是这样描述的:

 Produces an early-bound method handle for a virtual method.

所以此方法返回的绑定GrandFather类型的thinking方法,最终是Father类的thinking()。

wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.02.16 22:35

这个是获取specialCaller的最早绑定的methodType方法的,此处最早绑定的父类方法是Father类的所有的thinking(),但是如果Father类没有这个方法,那么就会进一步往上层父类GrandFather追溯查找这个方法的。
你可以将Father类的thinking方法注释掉,那么这个fandSpecial最终绑定的就是GrandFather的thinking()方法了。

jia20003
jia20003   2016.02.16 16:05

关键在于这里-mh.invoke(this);
你传入的实例是Father这个实例,Java基于运行期识别,当然会找它对于的方法,无它!

toponexds
toponexds   2016.02.16 18:49

这是知乎上关于此问题的连接
https://www.zhihu.com/question/40427344

Mr_dsw
Mr_dsw   Ds   Rxr 2016.02.16 22:26

可以看下这个文章的介绍:http://blog.csdn.net/aesop_wubo/article/details/48858931

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!