笔记:invoke方法和invoke字节码

invoke方法用于动态调用一个方法,为Method类下的一个public方法,函数签名public Object invoke(Object root, Object...parameters) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

invoke方法是实现代理的重要方法,先从一个简单的例子开始。

package com.godder.test;

import java.lang.reflect.Method;

public class AClass {

    public void hello(String name) {
        System.out.println("hello " + name);
    }

    public static void main(String[] args) throws Throwable {
        Method method = AClass.class.getMethod("hello", String.class);
        method.invoke(AClass.class.newInstance( "godder");
    }

}

输出结果为: hello godder

通过javap指令获取main方法的字节码如下:
public static void main(java.lang.String[]) throws java.lang.Throwable;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Exceptions:
throws java.lang.Throwable
Code:
stack=6, locals=2, args_size=1
0: ldc #1 // class com/godder/test/AClass
2: ldc #48 // String hello
4: iconst_1
5: anewarray #49 // class java/lang/Class
8: dup
9: iconst_0
10: ldc #51 // class java/lang/String
12: aastore
13: invokevirtual #53 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
16: astore_1
17: aload_1
18: ldc #1 // class com/godder/test/AClass
20: invokevirtual #57 // Method java/lang/Class.newInstance:()Ljava/lang/Object;
23: iconst_1
24: anewarray #3 // class java/lang/Object
27: dup
28: iconst_0
29: ldc #61 // String godder
31: aastore
32: invokevirtual #63 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
35: pop
36: return

其中invokevirtual指令出现了3次,分别是调用方法:
Class.getMethod(); Class.newInstance(); Method.invoke();
这三个方法都是虚方法(除static方法,private方法,constructor方法,super方法,final方法外的方法)
现在用另外一个例子

package com.godder.test;

import java.lang.reflect.Method;

public class BClass extends AClass {
    public static void fuker(String name) {
        System.out.println("fuker " + name);
    }

    public static void main(String[] args) throws Throwable {
        BClass clz = new BClass();
        Method method1 = clz.getClass().getMethod("hello", String.class);
        method1.invoke(clz, "godder");
        Method method2 = clz.getClass().getMethod("fuker", String.class);
        method2.invoke(null, "godder");
        BClass.fuker("god`
er");
    }
}

``
输出结果为:
hello godder
fuker godder
fuker godder

由javap指令获取的main函数的字节码如下:
 public static void main(java.lang.String[]) throws java.lang.Throwable;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Exceptions:
      throws java.lang.Throwable
    Code:
      stack=6, locals=4, args_size=1
         0: new           #1                  // class com/godder/test/BClass
         3: dup
         4: invokespecial #48                 // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #49                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
        12: ldc           #55                 // String hello
        14: iconst_1
        15: anewarray     #57                 // class java/lang/Class
        18: dup
        19: iconst_0
        20: ldc           #59                 // class java/lang/String
        22: aastore
        23: invokevirtual #61                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        26: astore_2
        27: aload_2
        28: aload_1
        29: iconst_1
        30: anewarray     #50                 // class java/lang/Object
        33: dup
        34: iconst_0
        35: ldc           #65                 // String godder
        37: aastore
        38: invokevirtual #67                 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
        41: pop
        42: aload_1
        43: invokevirtual #49                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
        46: ldc           #73                 // String fuker
        48: iconst_1
        49: anewarray     #57                 // class java/lang/Class
        52: dup
        53: iconst_0
        54: ldc           #59                 // class java/lang/String
        56: aastore
        57: invokevirtual #61                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        60: astore_3
        61: aload_3
        62: aconst_null
        63: iconst_1
        64: anewarray     #50                 // class java/lang/Object
        67: dup
        68: iconst_0
        69: ldc           #65                 // String godder
        71: aastore
        72: invokevirtual #67                 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
        75: pop
        76: ldc           #65                 // String godder
        78: invokestatic  #74                 // Method fuker:(Ljava/lang/String;)V
        81: return
这里出现了invokespecial指令用于调用构造器<init>方法来创建一个BClass的实例;
同时这里通过俩种不同的方法来调用static方法:fuker(String name),但这里却出现了不同的字节码。通过invoke()方法调用的字节码为invokevirtual,直接调用该方法的字节码为invokestatic。这里说明了invoke方法实现了动态的调用。由于java是静态编译语言,与python,js等动态编译语言不同,java在编译之前必须确定变量的类型,并且严格按照类型约束,如果类型不匹配则编译失败。
现在再来一个invokeinterface的例子:

package com.godder.test;

import java.lang.reflect.Method;

public class CClass implements Interface {

@Override
public void silyB(String name) {
    System.out.println(name + " is a SB by C");
}

public static void main(String[] args) throws Throwable{
    Interface clz = new CClass();
    CClass clz2 = new CClass();
    Method method = clz.getClass().getMethod("silyB", String.class);
    method.invoke(clz, "godder");
    clz.silyB("godder");
    clz2.silyB("go`

der”);
}

}

“`
输出结果为:
godder is a SB by C
godder is a SB by C
godder is a SB by C
由javap指令得出的main方法的字节码为:
public static void main(java.lang.String[]) throws java.lang.Throwable;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Exceptions:
throws java.lang.Throwable
Code:
stack=6, locals=4, args_size=1
0: new #1 // class com/godder/test/CClass
3: dup
4: invokespecial #56 // Method “”:()V
7: astore_1
8: new #1 // class com/godder/test/CClass
11: dup
12: invokespecial #56 // Method “”:()V
15: astore_2
16: aload_1
17: invokevirtual #57 // Method java/lang/Object.getClass:()Ljava/lang/Class;
20: ldc #61 // String silyB
22: iconst_1
23: anewarray #62 // class java/lang/Class
26: dup
27: iconst_0
28: ldc #27 // class java/lang/String
30: aastore
31: invokevirtual #64 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
34: astore_3
35: aload_3
36: aload_1
37: iconst_1
38: anewarray #3 // class java/lang/Object
41: dup
42: iconst_0
43: ldc #68 // String godder
45: aastore
46: invokevirtual #70 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
49: pop
50: aload_1
51: ldc #68 // String godder
53: invokeinterface #76, 2 // InterfaceMethod com/godder/test/Interface.silyB:(Ljava/lang/String;)V
58: aload_2
59: ldc #68 // String godder
61: invokevirtual #78 // Method silyB:(Ljava/lang/String;)V
64: return
可以看出,类型为Interface的对象调用的方法对应的字节码为invokeinterface,由具体类为类型的对象调用的方法对应的字节码为invokevirtual。

在jvm中还有一个invokedynamic指令,用于支持动态类型语言。但鉴于其内容,我希望将他放在一篇单独的博客里,以上便是关于invoke方法和invoke字节码的基础部分类容,如果要讨论invoke方法的具体实将涉及native方法和jvm底层,故不在此深究。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值