经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
通过字节码看java中this的隐式传参详解
来源:jb51  时间:2018/11/9 17:17:02  对本文有异议

前言

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

static与非static方法都是存储java的方法区。在static 方法中,没有this引用,因此无法使用当前类中所定义的变量,而非static方法则会默认传入this。

概述

  • this关键字,是一个隐式参数,另外一个隐式参数是super。
  • this用于方法里面,用于方法外面无意义。
  • this关键字一般用于set方法和构造方法中。

我们今天就从另一个角度来真实看一下这个答案吧!

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

  1. public class Hello {
  2.  
  3. private final int ii;
  4.  
  5. public Hello(int a) {
  6. ii = a;
  7. }
  8.  
  9. public static void main(String[] args) throws Exception {
  10. sayHelloStatic("ok");
  11. }
  12.  
  13. public void sayHello(String word) {
  14. System.out.println("hello, " + word);
  15. }
  16. public static void sayHelloStatic(String word) {
  17. System.out.println("static hello, " + word);
  18. }
  19. }

反汇编命令:

  1. javap -verbose Hello.class

反汇编结果:

  1. Classfile /D:/xx/target/classes/com/xx/api/Hello.class
  2. Last modified 2018-11-8; size 1069 bytes
  3. MD5 checksum 9d39cd9d4e95588a73c059a4e69f01e8
  4. Compiled from "Hello.java"
  5. public class com.xx.api.Hello
  6. minor version: 0
  7. major version: 52
  8. flags: ACC_PUBLIC, ACC_SUPER
  9. Constant pool:
  10. #1 = Methodref #14.#38 // java/lang/Object."<init>":()V
  11. #2 = Fieldref #13.#39 // com/xx/api/Hello.ii:I
  12. #3 = String #40 // ok
  13. #4 = Methodref #13.#41 // com/xx/api/Hello.sayHelloStatic:(Ljava/lang/String;)V
  14. #5 = Fieldref #42.#43 // java/lang/System.out:Ljava/io/PrintStream;
  15. #6 = Class #44 // java/lang/StringBuilder
  16. #7 = Methodref #6.#38 // java/lang/StringBuilder."<init>":()V
  17. #8 = String #45 // hello,
  18. #9 = Methodref #6.#46 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  19. #10 = Methodref #6.#47 // java/lang/StringBuilder.toString:()Ljava/lang/String;
  20. #11 = Methodref #48.#49 // java/io/PrintStream.println:(Ljava/lang/String;)V
  21. #12 = String #50 // static hello,
  22. #13 = Class #51 // com/xx/api/Hello
  23. #14 = Class #52 // java/lang/Object
  24. #15 = Utf8 ii
  25. #16 = Utf8 I
  26. #17 = Utf8 <init>
  27. #18 = Utf8 (I)V
  28. #19 = Utf8 Code
  29. #20 = Utf8 LineNumberTable
  30. #21 = Utf8 LocalVariableTable
  31. #22 = Utf8 this
  32. #23 = Utf8 Lcom/xx/api/Hello;
  33. #24 = Utf8 a
  34. #25 = Utf8 main
  35. #26 = Utf8 ([Ljava/lang/String;)V
  36. #27 = Utf8 args
  37. #28 = Utf8 [Ljava/lang/String;
  38. #29 = Utf8 Exceptions
  39. #30 = Class #53 // java/lang/Exception
  40. #31 = Utf8 sayHello
  41. #32 = Utf8 (Ljava/lang/String;)V
  42. #33 = Utf8 word
  43. #34 = Utf8 Ljava/lang/String;
  44. #35 = Utf8 sayHelloStatic
  45. #36 = Utf8 SourceFile
  46. #37 = Utf8 Hello.java
  47. #38 = NameAndType #17:#54 // "<init>":()V
  48. #39 = NameAndType #15:#16 // ii:I
  49. #40 = Utf8 ok
  50. #41 = NameAndType #35:#32 // sayHelloStatic:(Ljava/lang/String;)V
  51. #42 = Class #55 // java/lang/System
  52. #43 = NameAndType #56:#57 // out:Ljava/io/PrintStream;
  53. #44 = Utf8 java/lang/StringBuilder
  54. #45 = Utf8 hello,
  55. #46 = NameAndType #58:#59 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  56. #47 = NameAndType #60:#61 // toString:()Ljava/lang/String;
  57. #48 = Class #62 // java/io/PrintStream
  58. #49 = NameAndType #63:#32 // println:(Ljava/lang/String;)V
  59. #50 = Utf8 static hello,
  60. #51 = Utf8 com/xx/api/Hello
  61. #52 = Utf8 java/lang/Object
  62. #53 = Utf8 java/lang/Exception
  63. #54 = Utf8 ()V
  64. #55 = Utf8 java/lang/System
  65. #56 = Utf8 out
  66. #57 = Utf8 Ljava/io/PrintStream;
  67. #58 = Utf8 append
  68. #59 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
  69. #60 = Utf8 toString
  70. #61 = Utf8 ()Ljava/lang/String;
  71. #62 = Utf8 java/io/PrintStream
  72. #63 = Utf8 println
  73. {
  74. public com.xx.api.Hello(int);
  75. descriptor: (I)V
  76. flags: ACC_PUBLIC
  77. Code:
  78. stack=2, locals=2, args_size=2
  79. 0: aload_0
  80. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
  81. 4: aload_0
  82. 5: iload_1
  83. 6: putfield #2 // Field ii:I
  84. 9: return
  85. LineNumberTable:
  86. line 14: 0
  87. line 15: 4
  88. line 16: 9
  89. LocalVariableTable:
  90. Start Length Slot Name Signature
  91. 10 0 this Lcom/xx/api/Hello;
  92. 10 1 a I
  93.  
  94. public static void main(java.lang.String[]) throws java.lang.Exception;
  95. descriptor: ([Ljava/lang/String;)V
  96. flags: ACC_PUBLIC, ACC_STATIC
  97. Code:
  98. stack=1, locals=1, args_size=1
  99. 0: ldc #3 // String ok
  100. 2: invokestatic #4 // Method sayHelloStatic:(Ljava/lang/String;)V
  101. 5: return
  102. LineNumberTable:
  103. line 42: 0
  104. line 45: 5
  105. LocalVariableTable:
  106. Start Length Slot Name Signature
  107. 6 0 args [Ljava/lang/String;
  108. Exceptions:
  109. throws java.lang.Exception
  110.  
  111. public void sayHello(java.lang.String);
  112. descriptor: (Ljava/lang/String;)V
  113. flags: ACC_PUBLIC
  114. Code:
  115. stack=3, locals=2, args_size=2
  116. 0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
  117. 3: new #6 // class java/lang/StringBuilder
  118. 6: dup
  119. 7: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
  120. 10: ldc #8 // String hello,
  121. 12: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  122. 15: aload_1
  123. 16: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  124. 19: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  125. 22: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  126. 25: return
  127. LineNumberTable:
  128. line 48: 0
  129. line 49: 25
  130. LocalVariableTable:
  131. Start Length Slot Name Signature
  132. 26 0 this Lcom/xx/api/Hello;
  133. 26 1 word Ljava/lang/String;
  134.  
  135. public static void sayHelloStatic(java.lang.String);
  136. descriptor: (Ljava/lang/String;)V
  137. flags: ACC_PUBLIC, ACC_STATIC
  138. Code:
  139. stack=3, locals=1, args_size=1
  140. 0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
  141. 3: new #6 // class java/lang/StringBuilder
  142. 6: dup
  143. 7: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
  144. 10: ldc #12 // String static hello,
  145. 12: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  146. 15: aload_0
  147. 16: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  148. 19: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  149. 22: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  150. 25: return
  151. LineNumberTable:
  152. line 51: 0
  153. line 52: 25
  154. LocalVariableTable:
  155. Start Length Slot Name Signature
  156. 26 0 word Ljava/lang/String;
  157. }
  158. 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, 然后再做相关操作!

总结:

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号