Java中,由this关键字引发的问题
很久之前一直有一个疑问,最近重新翻了遍JVM的书,才算是终于有所顿悟。问题如下:
被自己遗忘的问题
package org.hanyan.test.testClass;
public class T3AboutThis {
public static void main(String[] args) {
new SubT3().func();
SuperT3 s = new SuperT3();
System.out.println(s instanceof SubT3);//false
}
}
class SuperT3 {
public String name = "Jack";
protected void func() {
System.out.println(this.name);//Jack
System.out.println(this instanceof SuperT3);//true
System.out.println(this instanceof SubT3);//true
}
}
class SubT3 extends SuperT3 {
public String name = "Peter";
}
一直没搞明白,上述代码中第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关键字也只是在编译好的字节码文件中,方法的第一个参数(方法的接收者)的访问符而已。整个问题的重点应该关注虚拟机如何执行这些字节码指令。
Java中,由this关键字引发的问题的更多相关文章
- 再议Java中的static关键字
再议Java中的static关键字 java中的static关键字在很久之前的一篇博文中已经讲到过了,感兴趣的朋友可以参考:<Java中的static关键字解析>. 今天我们再来谈一谈st ...
- “无法改变的设计”——浅谈Java中的final关键字
在Java中,final关键字可以用来修饰类.变量(包括成员变量和局部变量).方法,下面从这三个方面分别说明. final方法 当一个方法被final修饰时,表明这个方法不能被子类重写. 下面程序试图 ...
- (转)Java中的static关键字解析
转载: http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: &q ...
- 浅析Java中的final关键字(转载)
自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...
- 关于Java中的transient关键字
Java中的transient关键字是在序列化时候用的,如果用transient修饰变量,那么该变量不会被序列化. 下面的例子中创建了一个Student类,有三个成员变量:id,name,age.ag ...
- 关于Java中的final关键字
Java中的final关键字是用来限制用户行为的,说白了,就是用来限制我们这些程序员的.final可以用来修饰:变量.方法.类. 1)Java final variable final用来修饰变量时, ...
- 关于Java中的static关键字
Java中的 static 关键字,确实是一个关键的字(key word),今天就来总结一下它的用法,说说为什么关键. Java中的 static 关键字主要是用来做内存管理的.理解了这句话才能够比较 ...
- Java中的static关键字解析
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- 深入理解Java中的final关键字
Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...
- 浅析Java中的final关键字
浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
随机推荐
- 用JDOM读取XML文件
用JDOM读取XML文件需先用org.jdom.input.SAXBuilder对象的build()方法创建Document对象,然后用Document类.Element类等的方法读取所需的内容.IB ...
- Python爬取豆瓣《复仇者联盟3》评论并生成乖萌的格鲁特
代码地址如下:http://www.demodashi.com/demo/13257.html 1. 需求说明 本项目基于Python爬虫,爬取豆瓣电影上关于复仇者联盟3的所有影评,并保存至本地文件. ...
- StandardServer.await: create[8005]java.net.BindException: Address already in use: JVM_Bind错误
StandardServer.await: create[8005]java.net.BindException: Address already in use: JVM_Bind错误. 原因是:To ...
- Xml帮助类
public class XMLHelper { #region 将xml文件转换为object对象类型 /// <summary> /// 将xml文件转换为object对象类型 /// ...
- 在 .NET 4.0 下编写扩展代码以支持 async 异步编程
微软在C# 5中引入了async.await这两个异步编程的关键字,要使用这两个关键字需要你的IDE支持C#5.0语法,也就意味着你需要使用VS 2012版本以上IDE,或者在Vs2010卸载其编译器 ...
- Android加密算法之AES加密和解密实现
<pre name="code" class="plain"><span style="font-family:Microsoft ...
- jQuery.Validate常用的一些规则
// 手机号码验证 jQuery.validator.addMethod("mobile", function(value, element) { var length = val ...
- Openlayer4 - 最好最强大的开源地图引擎
Openlayer4 - 最好最强大的开源地图引擎 # githubhttps://github.com/openlayers/openlayers # 官网http://openlayers.org ...
- NIO之阻塞IO与非阻塞IO(包含Selector使用)
阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...
- Strategy模式
Strategy模式 Strategy模式要解决的问题和Template模式类似.都是为了把算法的声明和算法的实现解耦.Template模式是通过继承来实现的,而Strategy模式是通过组合来实现的 ...