通过字节码看java中this的隐式传参详解
程序员文章站
2024-02-29 13:09:58
前言
从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static...
前言
从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static 方法的区别所在!
static与非static方法都是存储java的方法区。在static 方法中,没有this引用,因此无法使用当前类中所定义的变量,而非static方法则会默认传入this。
概述
- this关键字,是一个隐式参数,另外一个隐式参数是super。
- this用于方法里面,用于方法外面无意义。
- this关键字一般用于set方法和构造方法中。
我们今天就从另一个角度来真实看一下这个答案吧!
来个例子,并将其反编译为可视代码:
public class hello { private final int ii; public hello(int a) { ii = a; } public static void main(string[] args) throws exception { sayhellostatic("ok"); } public void sayhello(string word) { system.out.println("hello, " + word); } public static void sayhellostatic(string word) { system.out.println("static hello, " + word); } }
反汇编命令:
javap -verbose hello.class
反汇编结果:
classfile /d:/xx/target/classes/com/xx/api/hello.class last modified 2018-11-8; size 1069 bytes md5 checksum 9d39cd9d4e95588a73c059a4e69f01e8 compiled from "hello.java" public class com.xx.api.hello minor version: 0 major version: 52 flags: acc_public, acc_super constant pool: #1 = methodref #14.#38 // java/lang/object."<init>":()v #2 = fieldref #13.#39 // com/xx/api/hello.ii:i #3 = string #40 // ok #4 = methodref #13.#41 // com/xx/api/hello.sayhellostatic:(ljava/lang/string;)v #5 = fieldref #42.#43 // java/lang/system.out:ljava/io/printstream; #6 = class #44 // java/lang/stringbuilder #7 = methodref #6.#38 // java/lang/stringbuilder."<init>":()v #8 = string #45 // hello, #9 = methodref #6.#46 // java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; #10 = methodref #6.#47 // java/lang/stringbuilder.tostring:()ljava/lang/string; #11 = methodref #48.#49 // java/io/printstream.println:(ljava/lang/string;)v #12 = string #50 // static hello, #13 = class #51 // com/xx/api/hello #14 = class #52 // java/lang/object #15 = utf8 ii #16 = utf8 i #17 = utf8 <init> #18 = utf8 (i)v #19 = utf8 code #20 = utf8 linenumbertable #21 = utf8 localvariabletable #22 = utf8 this #23 = utf8 lcom/xx/api/hello; #24 = utf8 a #25 = utf8 main #26 = utf8 ([ljava/lang/string;)v #27 = utf8 args #28 = utf8 [ljava/lang/string; #29 = utf8 exceptions #30 = class #53 // java/lang/exception #31 = utf8 sayhello #32 = utf8 (ljava/lang/string;)v #33 = utf8 word #34 = utf8 ljava/lang/string; #35 = utf8 sayhellostatic #36 = utf8 sourcefile #37 = utf8 hello.java #38 = nameandtype #17:#54 // "<init>":()v #39 = nameandtype #15:#16 // ii:i #40 = utf8 ok #41 = nameandtype #35:#32 // sayhellostatic:(ljava/lang/string;)v #42 = class #55 // java/lang/system #43 = nameandtype #56:#57 // out:ljava/io/printstream; #44 = utf8 java/lang/stringbuilder #45 = utf8 hello, #46 = nameandtype #58:#59 // append:(ljava/lang/string;)ljava/lang/stringbuilder; #47 = nameandtype #60:#61 // tostring:()ljava/lang/string; #48 = class #62 // java/io/printstream #49 = nameandtype #63:#32 // println:(ljava/lang/string;)v #50 = utf8 static hello, #51 = utf8 com/xx/api/hello #52 = utf8 java/lang/object #53 = utf8 java/lang/exception #54 = utf8 ()v #55 = utf8 java/lang/system #56 = utf8 out #57 = utf8 ljava/io/printstream; #58 = utf8 append #59 = utf8 (ljava/lang/string;)ljava/lang/stringbuilder; #60 = utf8 tostring #61 = utf8 ()ljava/lang/string; #62 = utf8 java/io/printstream #63 = utf8 println { public com.xx.api.hello(int); descriptor: (i)v flags: acc_public code: stack=2, locals=2, args_size=2 0: aload_0 1: invokespecial #1 // method java/lang/object."<init>":()v 4: aload_0 5: iload_1 6: putfield #2 // field ii:i 9: return linenumbertable: line 14: 0 line 15: 4 line 16: 9 localvariabletable: start length slot name signature 10 0 this lcom/xx/api/hello; 10 1 a i public static void main(java.lang.string[]) throws java.lang.exception; descriptor: ([ljava/lang/string;)v flags: acc_public, acc_static code: stack=1, locals=1, args_size=1 0: ldc #3 // string ok 2: invokestatic #4 // method sayhellostatic:(ljava/lang/string;)v 5: return linenumbertable: line 42: 0 line 45: 5 localvariabletable: start length slot name signature 6 0 args [ljava/lang/string; exceptions: throws java.lang.exception public void sayhello(java.lang.string); descriptor: (ljava/lang/string;)v flags: acc_public code: stack=3, locals=2, args_size=2 0: getstatic #5 // field java/lang/system.out:ljava/io/printstream; 3: new #6 // class java/lang/stringbuilder 6: dup 7: invokespecial #7 // method java/lang/stringbuilder."<init>":()v 10: ldc #8 // string hello, 12: invokevirtual #9 // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; 15: aload_1 16: invokevirtual #9 // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; 19: invokevirtual #10 // method java/lang/stringbuilder.tostring:()ljava/lang/string; 22: invokevirtual #11 // method java/io/printstream.println:(ljava/lang/string;)v 25: return linenumbertable: line 48: 0 line 49: 25 localvariabletable: start length slot name signature 26 0 this lcom/xx/api/hello; 26 1 word ljava/lang/string; public static void sayhellostatic(java.lang.string); descriptor: (ljava/lang/string;)v flags: acc_public, acc_static code: stack=3, locals=1, args_size=1 0: getstatic #5 // field java/lang/system.out:ljava/io/printstream; 3: new #6 // class java/lang/stringbuilder 6: dup 7: invokespecial #7 // method java/lang/stringbuilder."<init>":()v 10: ldc #12 // string static hello, 12: invokevirtual #9 // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; 15: aload_0 16: invokevirtual #9 // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; 19: invokevirtual #10 // method java/lang/stringbuilder.tostring:()ljava/lang/string; 22: invokevirtual #11 // method java/io/printstream.println:(ljava/lang/string;)v 25: return linenumbertable: line 51: 0 line 52: 25 localvariabletable: start length slot name signature 26 0 word ljava/lang/string; } sourcefile: "hello.java"
我们从字节码文件中可以看出来:
sayhello(string word) 和 sayhellostatic(string word) 都只有一个参数,但是在字节码中:
sayhello(string word) 中引用 word 时使用了 15: aload_1, 可以看出其加载的变量是在 slot1中,而 slot0中即保存了 this 。
sayhellostatic(string word) 中引用 word 时使用了 15: aload_0, 可以看出静态方法中,直接将变量存在了 slot0中,因此无法使用 this 中的变量了。
当要操作当前类的变量或方法时,需要先 aload_0, 然后再做相关操作!
总结:
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。