zoukankan      html  css  js  c++  java
  • 你真的理解Java的this和super吗?

    你不知道的this

    很多介绍java的书籍都说this指该对象本身。我们来看下面代码:

    class Base{
    	private int i = 3;
    	public Base()
    	{
    		this.display();
    	}
    	public void display()
    	{
    		System.out.println(i);
    	}
    }
    class Sub extends Base{
    	private int i = 33;
    	public Sub()
    	{
    		i = 333;
    	}
    	public void display()
    	{
    		System.out.println(i);
    	}
    }
    public class FiledTest{
    	public static void main(String[] args)
    	{
    		new Sub();
    	}
    }
    


    上面的结果不是3,也不是33,更不是333,而是0.

    我们来从内存分配角度来分析上面代码。

    首先,运行new Sub()时会先初始化它的父类。而初始化实例变量的过程是怎样的呢?实际上,在语法上,初始化Java的实例变量有三种方法:

    • 初始化语句。
    • 初始化块。
    • 构造函数。
    其中初始化语句和初始化块先于构造函数执行,且初始化语句和初始化块的执行先后取决于代码书写前后。这里要强调一点,对象的创建并不是由构造函数完成,因为对象的创建时你在使用它后就分配了内存,构造函数只是完成初始化变量工作。另外,对于编译器而言,无论是初始化语句还是初始化块,它们最后都会被提取到构造函数里。这一点我们可以使用命令 javap得到验证。使用 javap -c Base分析字节码有如下结果:


    有汇编基础的朋友可以看出i=3会在构造函数里执行。
    现在的问题是父类构造函数的this是什么的?实际上,这个this的真正解释是:this在构造器里时,this代表正在初始化的对象。所以这个this指的就是Sub!可能有些朋友会想,不是有super这个隐含对象吗?等会在介绍super时告诉你,根本就没有隐含对象这回事。
    这样,执行的Sub的display,而此时Sub的i还没有初始化,还是为默认值0。但是,如果在Base的构造器里添加 System.out.println(this.i); 那么这句话会打印出 3。这是因为这个this在编译时是Base。或者说,对于实例变量,它的执行和声明的类型有关;而对于方法,它的执行和其引用对象类型有关。这就是编译时类型和运行时类型的秘密。这里更深层的原因,笔者将在以后的文章里详细介绍。

    你不知道的super
    有一点要明确,像类型上面代码的结构里,系统只有一个Sub对象,不存在父类。但是这个Sub对象持有了两个i的实例变量。
    如果我们在父类有方法:
    public Base getThis()
    {
         return this;
    }

    在子类有,
    public Base getSuper()
    {
        return super,getThis();
    }
    Sub s = new Sub();
    Base b = s.getSuper();
    

    执行 a==b,结果是true。这表明super根本就不是默认的父类对象。有很多其他语法可以证明这点,比如 不能return super,super不能单独使用。


  • 相关阅读:
    java数据库访问类和接口
    数据删除的用法
    短信发送(M800)
    Spring注解开发(六)扩展原理
    观察者模式(Obeserver Pattern)
    Spring注解开发(五)声明式事务
    Spring注解开发(四)AOP原理与源码分析
    Spring注解开发(三)属性赋值与自动装配
    Spring注解开发(二)生命周期
    Spring注解开发(一)组件注册
  • 原文地址:https://www.cnblogs.com/pangblog/p/3359719.html
Copyright © 2011-2022 走看看