当前位置: 移动技术网 > IT编程>开发语言>Java > 通过字节码看java中this的隐式传参详解

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

2019年07月19日  | 移动技术网IT编程  | 我要评论

前言

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

总结:

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网