首页 > 开发 > Java > 正文

通过字节码看java中this的隐式传参详解

2024-07-14 08:42:47
字体:
来源:转载
供稿:网友

前言

从java/224771.html">字节码看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_SUPERConstant 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, 然后再做相关操作!

总结:

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对VeVb武林网的支持。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表