• 从字节码看java中 this 的隐式传参


      从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static 方法的区别所在!

      static与非static方法都是存储java的方法区。在static 方法中,没有this引用,因此无法使用当前类中所定义的变量,而非static方法则会默认传入this。我们今天就从另一个角度来真实看一下这个答案吧!

    来个例子,并将其反编译为可视代码:

    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
                0      10     0  this   Lcom/xx/api/Hello;
                0      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
                0       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
                0      26     0  this   Lcom/xx/api/Hello;
                0      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
                0      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 中的变量了。

                在LocalVariableTable 本地变量表中,可以清楚地看到,哪个slot存储了什么变量。

       当要操作当前类的变量或方法时,需要先 aload_0, 然后再做相关操作!

  • 相关阅读:
    No result defined for action
    敏捷管理视频
    如何预测一个互联网产品的未来:一套关于产品的数学模型
    ZooKeeper 笔记(3) 实战应用之【统一配置管理】
    mybatis migrate常用指令
    dubbo远程调试运行
    解决 nginx https反向代理http协议 302重定向localtion到http问题
    nginx设置不使用缓存 add_header Cache-Control no-cache
    openssl数字证书私钥删除私钥密码
    读 Zepto 源码系列
  • 原文地址:https://www.cnblogs.com/yougewe/p/9929249.html
Copyright © 2020-2023  润新知