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

 更新时间:2018年11月09日 08:38:00   作者:等你归去来  
这篇文章主要给大家介绍了关于如何通过字节码看java中this的隐式传参的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

从字节码看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, 然后再做相关操作!

总结:

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

相关文章

  • SpringCloud整合Activiti过程中的踩坑记录

    SpringCloud整合Activiti过程中的踩坑记录

    由于项目需要,最近开始在项目Spring boot中集成工作流引擎Activiti,由于第一次集成,一路上步步都是坑,所以这篇文章主要给大家介绍了关于SpringCloud整合Activiti过程中所遇到的踩坑记录,需要的朋友可以参考下
    2021-09-09
  • SpringBoot如何手写一个starter并使用这个starter详解

    SpringBoot如何手写一个starter并使用这个starter详解

    starter是SpringBoot中的一个新发明,它有效的降低了项目开发过程的复杂程度,对于简化开发操作有着非常好的效果,下面这篇文章主要给大家介绍了关于SpringBoot如何手写一个starter并使用这个starter的相关资料,需要的朋友可以参考下
    2022-12-12
  • 如何利用Spring MVC实现RESTful风格

    如何利用Spring MVC实现RESTful风格

    这篇文章主要介绍了如何利用Spring MVC实现RESTful风格,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Java实现excel大数据量导入

    Java实现excel大数据量导入

    这篇文章主要为大家详细介绍了Java实现excel大数据量导入,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • JAVA如何按字节截取字符串

    JAVA如何按字节截取字符串

    这篇文章主要介绍了JAVA如何按字节截取字符串,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • springboot项目打包发布部署的过程及jar和war的区别

    springboot项目打包发布部署的过程及jar和war的区别

    Spring Boot使用了内嵌容器,因此它的部署方式也变得非常简单灵活,可以将Spring Boot项目打包成JAR包来独立运行,Spring Boot项目既可以生成WAR包发布,也可以生成JAR包发布,那么它们有什么区别呢
    2022-11-11
  • 详解Java七大阻塞队列之SynchronousQueue

    详解Java七大阻塞队列之SynchronousQueue

    SynchronousQueue不需要存储线程间交换的数据,它的作用像是一个匹配器,使生产者和消费者一一匹配。本文详细讲解了Java七大阻塞队列之一SynchronousQueue,需要了解的小伙伴可以参考一下这篇文章
    2021-09-09
  • Java实现贪吃蛇游戏源码

    Java实现贪吃蛇游戏源码

    这篇文章主要为大家详细介绍了Java实现贪吃蛇游戏源码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • Java基础之代码死循环详解

    Java基础之代码死循环详解

    这篇文章主要介绍了Java基础之代码死循环详解,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • MyBatis3源码解析之如何获取数据源详解

    MyBatis3源码解析之如何获取数据源详解

    用myBatis3与spring整合的时候,我们可以通过多种方式获取数据源,下面这篇文章主要给大家介绍了关于MyBatis3源码解析之如何获取数据源的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06

最新评论