31

从字节码看java中 this 隐式传参具体体现

 5 years ago
source link: http://www.cnblogs.com/yougewe/p/9929249.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

从字节码看java中 this 隐式传参具体体现,也发现了 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 中的变量了。

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK