zoukankan      html  css  js  c++  java
  • Java中,由this关键字引发的问题

      很久之前一直有一个疑问,最近重新翻了遍JVM的书,才算是终于有所顿悟。问题如下:

    被自己遗忘的问题

     1 package org.hanyan.test.testClass;
     2 
     3 public class T3AboutThis {
     4     public static void main(String[] args) {
     5         new SubT3().func();
     6         SuperT3 s = new SuperT3();
     7         System.out.println(s instanceof SubT3);//false
     8     }
     9 }
    10 
    11 class SuperT3 {
    12     public String name = "Jack";
    13     
    14     protected void func() {
    15         System.out.println(this.name);//Jack
    16         System.out.println(this instanceof SuperT3);//true
    17         System.out.println(this instanceof SubT3);//true
    18     }
    19 }
    20 class SubT3 extends SuperT3 {
    21     public String name = "Peter";
    22 }

    一直没搞明白,上述代码中第17行为什么打印出来的true。

    javap 打印了SuperT3类编译后的字节码指令如下:

    第13、23字节的指令均为同一个引用变量,这个引用变量我们可以在本地变量表中看到是Lorg/hanyan/test/testClass/SuperT3,

    这里搞不明白为什么14、24字节的instanceof指令会返回同样的结果:true

    目前怀疑是在运行中,jvm将本地变量this替换了。但这又引出一个问题,为什么this.name中的this没有被替换?这个替换规则是怎么样的?

    我自认为还算比较准确的答案

    其实这个现象中有两个点需要说明:

    1.关于17行为什么会打印出true?

    这个是虚拟机字节码指令invokevirtual的动态查找过程的表现。

    13、23字节的指令的参数均为同一引用Lorg/hanyan/test/testClass/SuperT3,这里我之前理解的不深刻,其实这里的引用是“符号引用”,指SuperT3类常量池中的某个CONTANT_Methodref_info类型的“符号引用”。但虚拟机执行引擎在运行期执行这个字节码指令时,首先会查找这条指令的接收者(调用者)的实际类型,然后再确定真正的“直接引用”指向哪里。这个解析操作实现了方法的动态分派,也就是我们常说的“方法重写”。(具体“符号引用”解析为“直接引用”的解释请参考java的动态解析)。所以13、23的字节码指令的接收者实际是SubT3,即返回true。

    那么就会引出第二个关注点,代码的15行为什么是“Jack”?

    2.代码的15行为什么是“Jack”?

    虚拟机字节码指令getfeild,与invokevirtual不同,不存在动态查找过程。所以,getfeild字节码指令的参数为当前类的常量池的“符号引用”,此时的“符号引用”已在类加载过程中的“解析”阶段转化为“直接引用”,即表示当前类的变量name的值,所以返回“Jack”。


    至此,整个解释完毕。

    总结,this关键字也只是在编译好的字节码文件中,方法的第一个参数(方法的接收者)的访问符而已。整个问题的重点应该关注虚拟机如何执行这些字节码指令。

  • 相关阅读:
    学习Spring Boot:(八)Mybatis使用分页插件PageHelper
    学习Spring Boot:(七)集成Mybatis
    学习Spring Boot:(六) 集成Swagger2
    学习Spring Boot:(五)使用 devtools热部署
    学习Spring Boot:(四)应用日志
    学习Spring Boot:(三)配置文件
    学习Spring Boot:(二)启动原理
    学习Spring Boot:(一)入门
    Java8 新特性Stream 的学习和使用方法
    简易promise的实现(二)
  • 原文地址:https://www.cnblogs.com/hanmou/p/4613321.html
Copyright © 2011-2022 走看看