你不知道的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的this和super吗?的更多相关文章

  1. 你真的理解Java 注解吗?

    你真的理解Java 注解吗? 1.什么是注解? 官方解释: Java 注解用于为 Java 代码提供元数据.作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的.Java ...

  2. Java随谈(六)## 我们真的理解 Java 里的整型吗?

    我们真的理解 Java 里的整型吗 整型是我们日常生活中最常用到的基础数据类型,看这篇文章之前,我想问: 我们真的像自己认为的那么理解 Java 内的整型吗? 也许看完本篇文章你就有自己的答案. C ...

  3. 你真的理解Java的按引用传递吗?

    首先我们来看下面这段代码: public class Test1 { String a = "123"; public static void change(Test1 test) ...

  4. 你真的理解Java中的try/catch/finally吗?

    看几个例子,回顾一下执行顺序 例子1 无异常,finally中的return会导致提前返回 public static String test() {    try {        System.o ...

  5. Java内存管理-你真的理解Java中的数据类型吗(十)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 作为Java程序员,Java 的数据类型这个是一定要知道的! 但是不管是那种数据类型最 ...

  6. 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...

  7. 深入理解Java枚举

    深入理解Java枚举 重新认识Java枚举 老实说,挺羞愧的,这么久了,一直不知道Java枚举的本质是啥,虽然也在用,但是真不知道它的底层是个啥样的 直到2020年4月28日的晚上20点左右,我才真的 ...

  8. Java内存模型原理,你真的理解吗?

    [51CTO.com原创稿件]这篇文章主要介绍模型产生的问题背景,解决的问题,处理思路,相关实现规则,环环相扣,希望读者看完这篇文章后能对 Java 内存模型体系产生一个相对清晰的理解,知其然知其所以 ...

  9. [转]深入理解Java 8 Lambda(类库篇——Streams API,Collectors和并行)

    以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-l ...

随机推荐

  1. Kickstart + http Linux自动化部署服务端

    设备需要开启Network Boot功能.具体PXE技术就另外提,本文主要讲解配置. 在搭建该服务器之前需要关闭SELinux和iptables不然可能dhcp服务都起不来,客户端收不到IP地址,无法 ...

  2. MySql数据库3【优化3】缓存设置的优化

    1.表缓存 相关参数: table_open_cache 指定表缓存的大小.每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容.通过检查峰值时间的状 ...

  3. php 拓展 Filter 过滤器

    简介       Filter,它的作用就和他的名字一样——过滤.过滤规则成为过滤器,Filter内置了多个常用过滤器,根据过滤器功能的不 同,可以分成净化过滤器(Sanitization)和验证过滤 ...

  4. Mysql访问 for橙子小海

    package com.mvc.model.dao; import com.mvc.model.daoutil.DBConn; import com.mvc.model.entity.Blog; 这是 ...

  5. java 知识结构

    JAVA基础阶段 阶段 技术名称 技术内容 T线 JavaSE JAVA 开发基础知识 | Eclipse 开发环境 | JavaSE 7.0 API | JavaSE 8.0新特性 | 多线程技术 ...

  6. linux dd命令参数及用法详解---用指定大小的块拷贝一个文件(也可整盘备份)

    linux dd命令参数及用法详解---用指定大小的块拷贝一个文件 日期:2010-06-14 点击:3830 来源: 未知 分享至:            linux dd命令使用详解 dd 的主要 ...

  7. c#:类 相关练习;

    1. 2. int i = a.Length;//获取字符串的长度   a = a.ToLower();//将字符串中的大写英文字符转化为小写   a = a.ToUpper();//将字符串中的小写 ...

  8. Android 批量上传sd卡图片

    最近手头上需要批量上传一些保存到SD卡图片由于简单,过于忘记,写在博客中吧!同时也希望能帮到大家! 一 . 以下是一个Service类 package cn.com.service; import j ...

  9. nodejs触发事件的两种方式

    nodejs触发事件的两种方式: 方式之一:通过实例化events.EventEmitter //引入events模块 var events = require('events'); //初始化eve ...

  10. VIM default configuration

    == Vim的行号.语法显示等设置(.vimrc文件的配置) ==2008年01月18日 星期五 23:01 在终端下使用vim进行编辑时,默认情况下,编辑的界面上是没有显示行号.语法高亮度显示.智能 ...