前言
从字节码看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, 然后再做相关操作!
总结:
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对w3xue的支持。