正确的理解this 和 super
this和super是Java的两个关键字。
先明确一个问题,有人错误的认为它们是对象里的“属性”,这只能怪老师没有讲清楚计算机的本质了。因为计算机的处理器只能用指令去处理数据,像C语言之类的容易理解,就是一个个的方法调用,对数据进行处理。那面向对象语言,确实是用对象调用方法啊,怎么回事?
好办,编译器耍个花样,将对象当做方法的参数就是了。比如
class Test{
public void test(){}
}
Test t = new Test();
t.test();
计算机怎么处理呢?
假设我们把以上代码映射到面向过程的语言,大体是这个样子的:
void Test::test(final Test this){
}
当使用t.test();时,计算机实际处理为:
Test::test(t);//看到了吗?在方法中,this相当于形式参数,而调用方法的对象是实际参数。
也就是说this是实例方法中的第一个参数。对于static的方法,因为没有这个参数,所以就不能使用this了。
this和super的基本功能这里不想探讨,只想说明一下它们在本质上的差别。
有提法分别称之为this引用和super引用,为了表达的方便,这么说也无可厚非。但是从本质上来说,super并非一个引用,仅仅是一个起到指示作用的关键字而已,这与this在本质上是不同的。很简单的两行代码就说明问题了:
class Main {
public void test() {
System.out.println(this);
System.out.println(super);
}
}
编译报错,super后面缺少.。也就说,至少在Java语言看来,super并不是一个合法的引用,而显然this是可以的。
为了表达的方便,我们仍然称super为"super引用"。这种意义下,super引用和this引用有什么差别吗?差别当然有,最重要的是,类型不 同,super的类型为父类类型引用,而this为当前类类型的引用。相同点呢?那就是这两个都是指向“当前对象”。不是说“父类对象”吗?啥,哪来的“ 父类对象”这个概念啊?
言多必失,还是看代码吧。
class Base {
int i = 5;
public void test() {
System.out.println("In Base:" + this.i);
}
}
public class Test extends Base {
int i = 55;
public void test() {
//System.out.println(super); 竟然编译都不让通过
System.out.println(this); //正确,调用toString()方法
System.out.println(super.i);
System.out.println(this.i);
super.test();
}
public static void main(String[] args) {
new Test().test();
}
}
看出什么了?没有。没有就对了,反汇编。
public void test(); Code: 0: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_0 4: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 7: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 10: aload_0 11: getfield #5; //Field Base.i:I 14: invokevirtual #6; //Method java/io/PrintStream.println:(I)V 17: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 20: aload_0 21: getfield #2; //Field i:I 24: invokevirtual #6; //Method java/io/PrintStream.println:(I)V 27: aload_0 28: invokespecial #7; //Method Base.test:()V 31: return public static void main(java.lang.String[]); Code: 0: new #8; //class Test 3: dup 4: invokespecial #9; //Method "<init>":()V 7: invokevirtual #10; //Method test:()V 10: return
注意那几个aload_0, 这可是获取this啊(前面交代了,this是实例方法的第一个参数,第一个参数当然位置是0了)!那访问this.i和super.i的差别在什么地方呢?在这个i上。
10: aload_0
11: getfield #5; //Field Base.i:I
这是获取Base定义的i
20: aload_0
21: getfield #2; //Field i:I
这是获取Test中定义的i
简单的说,Base.i和i就是当前对象中两个名字不同的字段。
有人要质疑了:瞎掰吧!如果super和this是同一个对象的引用,那super调用方法的时候不又多态了 ?这的确是个问题。不过Java的设计者考虑 到这个问题了,在jvm中提供了不同的调用方法的指令,分别是invokevirtual、invokespecial、 invokeinterface、invokedynamic等 。通过super调用实例方法时,用的就是invokespecial 指令。当 然,java的设计者们也不是一开始就考虑这么多的,invokespecial这个指令就是后来才加上的。事后诸葛亮?呵呵。
再看一下上面的反编译代码:
27: aload_0
28: invokespecial #7; //Method Base.test:()V
//用invokespecial指令避免此时发生多态调用
而多态方法调用时用什么指令呢?
看main方法是如何调用test方法的吧:public static void main(java.lang.String[]);
7: invokevirtual #10; //Method test:()V
为什么叫virtual呢?C++里有个叫做虚函数的东西,难道……
其实我们可以形象的说明一下,假设有两个变量_super和_this。
Test _this = new Test();
Super _super = _this;
这样就能更清晰的区分this和super了吧!
正确的理解this 和 super的更多相关文章
- 如何正确的理解和解决 ORA-01843:not a valid month
今天码代码的时候遇到了这个问题,因为oracle用的比较少,所在查询了一下. 顿时傻眼,有很多的贴子说是因为nls_date_language的问题,还要改会话级的NLS_DATE_LANGUAGE设 ...
- 理解python的super
def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1] super做了这些事 摘自:https: ...
- 怎样正确的理解和解决 ORA-01843:not a valid month
今天码代码的时候遇到了这个问题,由于oracle用的比較少,所在查询了一下. 顿时傻眼,有非常多的贴子说是由于nls_date_language的问题,还要改会话级的NLS_DATE_LANGUAGE ...
- TCP三次握手的seq和ack号的【正确】理解
1 理论知识 先上一张图,TCP/IP详解第18章的这张图描述了一个正常的三次握手和四次挥手的状态迁移,以及seq.ack序号的变化. 基本状态看图就能了解,本文主要围绕序号的变化进行讲解. 1)se ...
- JVM如何理解Java泛型类
//泛型代码 public class Pair<T>{ private T first=null; private T second=null; public Pair(T fir,T ...
- (转载)新手如何正确理解GitHub中“PR(pull request)”中的意思
我从知乎看到的两个答案,分别从实际意义以及语言学角度告诉你改怎么理解PR,很简洁,这个理解非常棒,会解决新手刚看到PR(pull request)这个词时的困惑. 实际意义: 有一个仓库,叫R ...
- iOS 中self和super如何理解?
或许你理解self和super都是指的是类的对象 self指的是本类的对象,而super指的是父类的对象,但是事实情况呢,可能有些和你想象的不一样? 简单看下下面例子: @interface Pe ...
- IM开发基础知识补课:正确理解前置HTTP SSO单点登陆接口的原理
1.前言 一个安全的信息系统,合法身份检查是必须环节.尤其IM这种以“人”为中心的社交体系,身份认证更是必不可少. 一些PC时代小型IM系统中,身份认证可能直接做到长连接中(也就是整个IM系统都是以长 ...
- IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列
1.引言 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一. 消息从发送者到接收者的典型传递方式有两种: 1)一种我 ...
随机推荐
- STL学习三:deque容器
1.Deque简介 deque是“double-ended queue”的缩写,和vector一样都是STL的容器,deque是双端数组,而vector是单端的. deque在接口上和vector非常 ...
- c++事件内核对象(event)进程间激活(转)
源出处:http://blog.csdn.net/richerg85/article/details/7538493 此文主要说明的是,c++中创建的一个事件内核对象可以在不同的程序(进程)间共用,也 ...
- <<梦断代码>>读书笔记
从任何角度,Chandler项目开始时都是值得羡慕的.虽然是讲一个软件项目是如何失败的,不过里面有让我觉得很有意思. 失败了就进行反思:定位不能逆时代的潮流, 互联网的趋势不可逆转,人员沟通与合作是永 ...
- 玩耍Hibernate系列(二)--基础知识
Hibernate思维导图 Hibernate映射 关于hibernate的映射要说明的一点就是关于ID的访问权限,peroperty以及field的区别: 表的主键在内存中对应一个OID对象描述 ...
- CSS3中box-shadow的用法介绍
一般我们通过box-shadow来设置盒阴影,但是有些属性我们一般没有用到,这篇文章将对box-shadow属性进行逐个分析.语法 CSS Code复制内容到剪贴板 E {box-shadow:ins ...
- C# Redis
概念 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,和Memcached类似,它支持存储的value类型相对更多,包括string( ...
- 【DP】permu
permu [Description] 给定两个1~N的全排列A,B.有两个指针q和p,一开始q.p都为0,可执行以下三种操作: 1.q+1:2.p+1:3.q+1且p+1(Aq+1≠Bp+1时才可以 ...
- 【BZOJ】【3439】Kpm的MC密码
Trie树/可持久化线段树 神题啊……搞了我一下午= =(其实第233个提交也是我的) 我一开始的思路:这个找kpm串的过程,其实就跟在AC自动机上沿fail倒着往下走是差不多的(看当前是哪些点的后缀 ...
- 跨站点端口攻击 – XSPA(SSPA)
许多Web应用程序提供的功能将数据从其他Web服务器,由于种种原因.下载XML提要,从远程服务器,Web应用程序可以使用用户指定的URL,获取图像,此功能可能会被滥用,使制作的查询使用易受攻击的Web ...
- win7/8下VirtualBox虚拟Ubuntu共享文件夹设置
实验环境: 主机:win8.1 虚拟机软件:VirtualBox4.3 虚拟的主机:centos6.5 final 亲测可用! 1. 安装增强功能包(VBoxGuestAdditions) 打开虚拟 ...