1.可以用反射实现
2.可以用虚拟机级别的invokeddynamic实现(基于java1.7版本以及以上才可以)
代码如下:
/**
* @(#)Text4.java
*
*
* @author
* @version 1.00 2016/12/6
*/
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import static java.lang.invoke.MethodHandles.lookup;
public class Text4 {
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 Text4().new son()).thinking();
}
}
对上述代码使用生成class字节码:
Classfile /E:/JAVAprojects/noMain/bin/noMain/son.class
Last modified 2016-12-6; size 1386 bytes
Compiled from "son.java"
public class noMain.son extends noMain.Father
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // noMain/son
#2 = Utf8 noMain/son
#3 = Class #4 // noMain/Father
#4 = Utf8 noMain/Father
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // noMain/Father."<init>":()V
#9 = NameAndType #5:#6 // "<init>":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 LnoMain/son;
#14 = Utf8 thinking
#15 = Methodref #16.#18 // java/lang/Object.getClass:()Ljava/lang/Class;
#16 = Class #17 // java/lang/Object
#17 = Utf8 java/lang/Object
#18 = NameAndType #19:#20 // getClass:()Ljava/lang/Class;
#19 = Utf8 getClass
#20 = Utf8 ()Ljava/lang/Class;
#21 = Fieldref #22.#24 // java/lang/Void.TYPE:Ljava/lang/Class;
#22 = Class #23 // java/lang/Void
#23 = Utf8 java/lang/Void
#24 = NameAndType #25:#26 // TYPE:Ljava/lang/Class;
#25 = Utf8 TYPE
#26 = Utf8 Ljava/lang/Class;
#27 = Methodref #28.#30 // java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
#28 = Class #29 // java/lang/invoke/MethodType
#29 = Utf8 java/lang/invoke/MethodType
#30 = NameAndType #31:#32 // methodType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
#31 = Utf8 methodType
#32 = Utf8 (Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
#33 = Methodref #34.#36 // java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
#34 = Class #35 // java/lang/invoke/MethodHandles
#35 = Utf8 java/lang/invoke/MethodHandles
#36 = NameAndType #37:#38 // lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
#37 = Utf8 lookup
#38 = Utf8 ()Ljava/lang/invoke/MethodHandles$Lookup;
#39 = Class #40 // noMain/GrandFather
#40 = Utf8 noMain/GrandFather
#41 = String #14 // thinking
#42 = Methodref #43.#45 // java/lang/invoke/MethodHandles$Lookup.findSpecial:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;
#43 = Class #44 // java/lang/invoke/MethodHandles$Lookup
#44 = Utf8 java/lang/invoke/MethodHandles$Lookup
#45 = NameAndType #46:#47 // findSpecial:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;
#46 = Utf8 findSpecial
#47 = Utf8 (Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;
#48 = Methodref #49.#51 // java/lang/invoke/MethodHandle.invoke:(LnoMain/son;)V
#49 = Class #50 // java/lang/invoke/MethodHandle
#50 = Utf8 java/lang/invoke/MethodHandle
#51 = NameAndType #52:#53 // invoke:(LnoMain/son;)V
#52 = Utf8 invoke
#53 = Utf8 (LnoMain/son;)V
#54 = Class #55 // java/lang/Throwable
#55 = Utf8 java/lang/Throwable
#56 = Utf8 a
#57 = Utf8 mt
#58 = Utf8 Ljava/lang/invoke/MethodType;
#59 = Utf8 mh
#60 = Utf8 Ljava/lang/invoke/MethodHandle;
#61 = Utf8 StackMapTable
#62 = Class #63 // java/lang/Class
#63 = Utf8 java/lang/Class
#64 = Utf8 main
#65 = Utf8 ([Ljava/lang/String;)V
#66 = Methodref #1.#9 // noMain/son."<init>":()V
#67 = Methodref #1.#68 // noMain/son.thinking:()V
#68 = NameAndType #14:#6 // thinking:()V
#69 = Utf8 args
#70 = Utf8 [Ljava/lang/String;
#71 = Utf8 SourceFile
#72 = Utf8 son.java
#73 = Utf8 InnerClasses
#74 = Utf8 Lookup
{
public noMain.son();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method noMain/Father."<init>":()V
4: return
LineNumberTable:
line 32: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LnoMain/son;
void thinking();
descriptor: ()V
flags:
Code:
stack=5, locals=4, args_size=1
0: aload_0
1: invokevirtual #15 // Method java/lang/Object.getClass:()Ljava/lang/Class;
4: astore_1
5: getstatic #21 // Field java/lang/Void.TYPE:Ljava/lang/Class;
8: invokestatic #27 // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
11: astore_2
12: invokestatic #33 // Method java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
15: ldc #39 // class noMain/GrandFather
17: ldc #41 // String thinking
19: aload_2
20: aload_1
21: invokevirtual #42 // Method java/lang/invoke/MethodHandles$Lookup.findSpecial:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;
24: astore_3
25: aload_3
26: aload_0
27: invokevirtual #48 // Method java/lang/invoke/MethodHandle.invoke:(LnoMain/son;)V
30: goto 34
33: astore_2
34: return
Exception table:
from to target type
5 30 33 Class java/lang/Throwable
LineNumberTable:
line 36: 0
line 38: 5
line 39: 12
line 40: 15
line 41: 17
line 40: 21
line 39: 24
line 43: 25
line 44: 30
line 47: 34
LocalVariableTable:
Start Length Slot Name Signature
0 35 0 this LnoMain/son;
5 30 1 a Ljava/lang/Class;
12 18 2 mt Ljava/lang/invoke/MethodType;
25 5 3 mh Ljava/lang/invoke/MethodHandle;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 33
locals = [ class noMain/son, class java/lang/Class ]
stack = [ class java/lang/Throwable ]
frame_type = 0 /* same */
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #1 // class noMain/son
3: dup
4: invokespecial #66 // Method "<init>":()V
7: invokevirtual #67 // Method thinking:()V
10: return
LineNumberTable:
line 53: 0
line 55: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 args [Ljava/lang/String;
}
SourceFile: "son.java"
InnerClasses:
public static final #74= #43 of #34; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
没有生成invokedynamic调用,应该是我的jvm配置出错,使得jvm栈帧的模式值调用了出栈的第一个实例使得输出答案为 i am father
/**
* @(#)StaticDispatch.java
*
*
* @author
* @version 1.00 2016/12/6
*/
import java.lang.invoke.*;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import static java.lang.invoke.MethodHandles.lookup;
public class StaticDispatch {
static class ClassA{
public void println(String s){
System.out.println(s);
}
}
private static MethodHandle getPrintlnMH(Object recevier) throws Throwable{
MethodType mt = MethodType.methodType(void.class,String.class);
return lookup().findVirtual(recevier.getClass(),"println",mt).bindTo(recevier);
}
public static void main(String[] args) throws Throwable{
Object ob = System.currentTimeMillis() % 2 == 0 ? System.out : new ClassA();
getPrintlnMH(ob).invokeExact("invoke println");
}
}