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的更多相关文章

  1. 如何正确的理解和解决 ORA-01843:not a valid month

    今天码代码的时候遇到了这个问题,因为oracle用的比较少,所在查询了一下. 顿时傻眼,有很多的贴子说是因为nls_date_language的问题,还要改会话级的NLS_DATE_LANGUAGE设 ...

  2. 理解python的super

    def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1] super做了这些事 摘自:https: ...

  3. 怎样正确的理解和解决 ORA-01843:not a valid month

    今天码代码的时候遇到了这个问题,由于oracle用的比較少,所在查询了一下. 顿时傻眼,有非常多的贴子说是由于nls_date_language的问题,还要改会话级的NLS_DATE_LANGUAGE ...

  4. TCP三次握手的seq和ack号的【正确】理解

    1 理论知识 先上一张图,TCP/IP详解第18章的这张图描述了一个正常的三次握手和四次挥手的状态迁移,以及seq.ack序号的变化. 基本状态看图就能了解,本文主要围绕序号的变化进行讲解. 1)se ...

  5. JVM如何理解Java泛型类

    //泛型代码 public class Pair<T>{ private T first=null; private T second=null; public Pair(T fir,T  ...

  6. (转载)新手如何正确理解GitHub中“PR(pull request)”中的意思

    我从知乎看到的两个答案,分别从实际意义以及语言学角度告诉你改怎么理解PR,很简洁,这个理解非常棒,会解决新手刚看到PR(pull request)这个词时的困惑.   实际意义:   有一个仓库,叫R ...

  7. iOS 中self和super如何理解?

    或许你理解self和super都是指的是类的对象   self指的是本类的对象,而super指的是父类的对象,但是事实情况呢,可能有些和你想象的不一样? 简单看下下面例子: @interface Pe ...

  8. IM开发基础知识补课:正确理解前置HTTP SSO单点登陆接口的原理

    1.前言 一个安全的信息系统,合法身份检查是必须环节.尤其IM这种以“人”为中心的社交体系,身份认证更是必不可少. 一些PC时代小型IM系统中,身份认证可能直接做到长连接中(也就是整个IM系统都是以长 ...

  9. IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

    1.引言 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一. 消息从发送者到接收者的典型传递方式有两种: 1)一种我 ...

随机推荐

  1. Eigen库实现简单的旋转、平移操作

    本来课程要求用GUI界面来实现Eigen的旋转.平移操作的,但是接触GUI编程时间太短,虽然要求很简单,但是做了几天还是没有完成.就把命令行下面的简单的贴一下吧. main.cpp #include ...

  2. Ngrok 内网穿透神器(转载)

    mac上配置web服务: http://note.rpsh.net/posts/2013/11/27/osx-10-9-apache-server-php-mysql/ Ngrok 内网穿透神器 由于 ...

  3. Spring MVC mapping[From Spring MVC Beginner's Guide]

    In a Spring MVC application, the URL can logically be divided into five parts (see the following fig ...

  4. std::function,std::bind复习

    #include <iostream> #include <functional>//std::bind返回函数对象 void fun1(int a, int b) { std ...

  5. [剑指OFFER] 数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.     分析:利用归并排序的思想,分成2部分,每一部分按照从大到 ...

  6. [转载]为什么我希望用C而不是C++来实现ZeroMQ

    来源: http://blog.jobbole.com/19647/ 开始前我要先做个澄清:这篇文章同Linus Torvalds这种死忠C程序员吐槽C++的观点是不同的.在我的整个职业生涯里我都在使 ...

  7. HDOJ 1069 DP

    开启DP之路 题目:http://acm.hdu.edu.cn/showproblem.php?pid=1069 描述一下: 就是给定N(N<=20)个方体,让你放置,求放置的最高高度,限制条件 ...

  8. function的prototype

    prototype只有function才有的属性. var a = function() { this.age = 12; this.name = "haha"; }; a.pro ...

  9. eclipse git 整合

    最近朋友都推荐使用github管理自己的项目,而且免费用户可以有5个仓库,恰好我也想了解下git,借此机会学习一下.github官方指南使用独立第三方git工具来进行版本控制,并不借助于eclipse ...

  10. Sqli-labs less 56

    Less-56 与less54.55形式是一致的,我们关注sql语句, $sql="SELECT * FROM security.users WHERE id=('$id') LIMIT 0 ...