成员内部类可以继承其他的类,也可以被其它类继承,本文主要说明其它类继承成员内部类的问题。

本文要点如下:

1).成员内部类的子类可以是内部类,也可以不是内部类;

2).当成员内部类的子类不是内部类或子类虽是内部类但与其父类不在同一个外部类时,子类的构造方法第一句要显式添加如下的语句:

外部类对象引用.super(参数);

这里的外部类指父类所在的外部类;

3).编译器默认给成员内部类的构造方法传入一个参数,该参数是内部类所依附的外部类对象的引用;

注:本文涉及到的类都是非静态类

作者: 蝉蝉

请尊重作者劳动成果,转载请在标题注明“转载”字样,并标明原文链接:

http://www.cnblogs.com/chanchan/p/8345144.html

参考资料:

http://www.cnblogs.com/dolphin0520/p/3811445.html

背景知识点:

1).内部类是如何依附于外部类的?

编译器编译时,是把外部类与成员内部类编译成两个独立的文件的;

但会给成员内部类默认添加一个类型为外部类对象引用的成员变量并为构造方法默认传入一个类型为外部类对象引用的参数,并以该参数值来初始化该成员变量;

如下所示:

final Person this$0;

InnerClass(Person per){

    ...

    this$0 = per;

    ...

  }

也就是说,成员内部类的对象保存了一个外部类对象的引用,通过这个引用,内部类就可以无限制的访问外部类的成员了。

从这里也可以看出,创建成员内部类对象之前必须要存在一个外部类对象,即,成员内部类是依附于外部类的。

2).创建子类对象时,要先调用父类构造方法再调用子类构造方法。

详细参见笔记11

3).子类构造方法中如果没有显式调用super(参数),则会在构造方法最前面默认添加super();。

下面分三种情况来讨论:

1.子类是内部类且与父类位于同一个外部类

外部类是Person,父类是成员内部类InnerClassParent,子类是成员内部类InnerClassChild。

     //笔记22--成员内部类--父类
class InnerClassParent {
InnerClassParent (){
System.out.println("内部类--父类");
}
} //笔记22-成员内部类--子类
class InnerClassChild extends InnerClassParent {
InnerClassChild(){
System.out.println("内部类的子类是内部类且位于同一外部类");
}
} public static void main(String[] args) {
Person per22 = new Person();
InnerClassChild inCCh = per22.new InnerClassChild();
}

输出结果为:

内部类--父类
内部类的子类是内部类且位于同一外部类

分析:

  1).由背景知识点1)可知,编译后,

子类实际的样子大概是如下这样的:

     //笔记22-成员内部类--子类
class InnerClassChild extends InnerClassParent {
final Person this$0;

InnerClassChildIn(Person per){
super();
this$0 = per;
System.out.println("内部类的子类是内部类且位于同一外部类");
}
}

父类实际的样子大概是如下这样的:

     //笔记22--成员内部类--父类
class InnerClassParent {
final Person this$0;
InnerClassParent(Person per){
this$0 = per;
System.out.println("内部类--父类");
}
}

  2).根据上面的分析,作出执行的流程图,如下所示:

1>.先创建外部类对象per,再通过per来创建其成员内部类InnerClassChild(子类);

2>.要创建子类对象,必须先加载父类再加载子类(这里子类、父类都是初次使用,尚未加载),然后初始化父类成员并调用父类构造方法,最后再初始化子类成员并调用子类的构造方法;

3>调用完子类构造方法后,子类对象inCCh创建完成;

  3).子类对象inCCh创建后的内存结构图如下所示:

子类对象创建完成后,子类与父类都有一个外部类对象引用this$0,且都指向了per。

相关知识点:

1>.堆、栈,参见笔记把大端、小端与堆、栈的生长方向联系起来记忆

2>.隐藏与覆盖,参见笔记12

2.子类是内部类且与父类位于不同的外部类

外部类DustMan的成员内部类是InnerClassChildDM,InnerClassChildDM继承了外部类Person的成员内部类InnerClassParent。

子类InnerClassChildDM的代码如下:

     //笔记22--成员内部类--子类为内部类且不在同一个外部类
class InnerClassChildDM extends Person.InnerClassParent {
InnerClassChildDM(Person per){
per.super();
System.out.println("成员内部类的子类为内部类且与父类不在同一个外部类");
}
}
public static void main(String[] args) {
DustMan du = new DustMan();
Person per = new Person();
InnerClassChildDM inCChDM = du.new InnerClassChildDM(per);
}

输出结果如下:

内部类--父类
成员内部类的子类为内部类且与父类不在同一个外部类

分析:

    1).编译后,子类的实际样子大概是下面这样的:

     //笔记22--成员内部类--子类为内部类且不在同一个外部类
class InnerClassChildDM extends Person.InnerClassParent {
final DustMan this$0;
InnerClassChildDM(DustMan du, Person per){
per.super();
this$0 = du;
System.out.println("成员内部类的子类为内部类且与父类不在同一个外部类");
}
}

    2).与第一种情况不同的是,子类InnerClassChildDM中显式添加了per.super();

这是因为,子类与父类处于不同的外部类,编译时,子类的构造方法默认传入的是DustMan类的对象引用,而不是Person类的对象引用;

如果要调用父类的构造方法的话,必须要给它传入一个其外部类Person的对象引用;

所以这时,子类的构造方法显式传入一个Person类对象引用per,并通过per.super();的方式把per传给父类的构造方法并调用之。

    3).执行的流程图如下所示:

    4).子类对象inCChDM创建完成后的内存分配图如下:

其中,子类的this$0是指向DustMan类的对象du的,父类的this$0是指向Person类的对象per的。

3.子类不是内部类

InnerClassChild不是内部类,它继承了外部类Person的成员内部类InnerClassParent。

 package human;

 public class InnerClassChild extends Person.InnerClassParent {
InnerClassChild(Person per) {
per.super();
System.out.println("内部类的子类不是内部类");
} public static void main( String[] args ) {
Person per = new Person();
InnerClassChild inCCh = new InnerClassChild(per);
}
}

输出结果如下:

内部类--父类
内部类的子类不是内部类

分析:

    1).子类不是内部类,所以编译器不会在其构造方法中传入其外部类的对象引用。

    2).子类的构造方法也显式的添加了per.super();语句,原因同上。

    3).执行的流程图如下所示:

    4).子类对象inCChNoI创建完成后,内存分配图如下:

其中,只有父类有this$0成员变量,且指向了Person类的对象per。

总结:

成员内部类的非静态子类可以是与其位于同一个外部类的子类,也可以是位于不同外部类的子类,还可以是一般类。

后两种情况,必须在子类的构造方法中显式添加 父类的外部类的对象.super(参数); 这样一条语句,以保证为父类传入其外部类的对象引用,继而保证能调用父类的构造方法。

Java学习笔记22---内部类之成员内部类的继承问题的更多相关文章

  1. Java学习笔记之---内部类

    Java学习笔记之---内部类 (一)成员内部类 内部类在外部使用时,无法直接实例化,需要借助外部类信息才能实例化 内部类的访问修饰符可以任意,但是访问范围会受到影响 内部类可以直接访问外部类的成员, ...

  2. 疯狂java学习笔记之面向对象(五) - 封装、继承、多态

    一.封装: 封装的概念: - 合理的隐藏:隐藏不想被外界操作的Field.方法.构造器 - 合理的暴露:一般就是希望给别人调用的方法 e.g:显示器(按键暴露出来操作,但实际的东西/细节方法被隐藏起来 ...

  3. Java学习笔记之——内部类

    内部类 形式:把一个类定义在一个类的内部. 分为:成员内部类和匿名内部类重点掌握 a) 成员内部类 b) 静态成员内部类 c) 匿名内部类 d) 局部内部类 (1)成员内部类: Java的语言是面向对 ...

  4. Java学习笔记:内部类/匿名内部类的全面介绍

    编写java程序时,一般一个类(或者接口)都是放在一个独立的java文件中,并且类名同文件名(如果类是public的,类名必须与文件名一致:非public得,无强制要求).如果想把多个java类放在一 ...

  5. 3)Java学习笔记:内部类

    什么是内部类 内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(而外部类只能使用public和 ...

  6. 【原】Java学习笔记025 - 内部类

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 内部类(嵌套类): ...

  7. Java学习笔记22(Date类、DateFormat类)

    Date,时间和日期类,这里讲util包中的而不是sql包中的 Date:表示特定的时间瞬间,精确到毫秒(1000毫秒=1秒) 时间和日期的操作都基于毫秒值 时间原点:1970年1月1日,0时0分0秒 ...

  8. Java学习笔记22(List接口)

    List接口继承自Collection接口,自身具有三大特点: 1.有序集合:存入和取出的顺序一致: 2.此接口的用户可以对每个元素插入位置进行精确控制:可以通过索引操作元素 3.可以存储重复元素 L ...

  9. Java学习笔记(三)——封装、继承、多态

    一.封装 概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 实现步骤: 修改属性的可见性——设为private. 创建getter/se ...

随机推荐

  1. c语言中的转义序列

    c中的输出函数printf()可以带以下的转义序列,不同的转义序列会得到不同的结果. 1.\a:警报 2.\b:退格(光标回退一格)3.\f:换页4.\n:换行(光标去到下一行的起始处)5.\r:回车 ...

  2. [数据清洗]- Pandas 清洗“脏”数据(三)

    预览数据 这次我们使用 Artworks.csv ,我们选取 100 行数据来完成本次内容.具体步骤: 导入 Pandas 读取 csv 数据到 DataFrame(要确保数据已经下载到指定路径) D ...

  3. 三十天学不会TCP,UDP/IP网络编程-TraceRoute的哲学

    新年快乐,继续来部分粘贴复制我的这一系列文章啦,如果对和程序员有关的计算机网络知识,和对计算机网络方面的编程有兴趣,欢迎去gitbook(https://www.gitbook.com/@rogerz ...

  4. 常用API接口汇总

    下面列举了100多个国内常用API接口,并按照 笔记.出行.词典.电商.地图.电影.即时通讯.开发者网站.快递查询.旅游.社交.视频.天气.团队协作.图片与图像处理.外卖.消息推送.音乐.云.语义识别 ...

  5. Travis CI实现持续部署

    安装Ruby 2.0以上版本并安装travis的命令行工具 可以看出我的已经是安装好的(Ubuntu 16.04.3 LTS 系统) ruby -v ruby --) [x86_64-linux-gn ...

  6. nvm 装 nodejs 重启终端失效的解决方法

    (1) 安装 nvm wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.30.1/install.sh | bash (2) ...

  7. Neo4j学习笔记(2)——数据索引

    和关系数据库一样,Neo4j同样可以创建索引来加快查找速度. 在关系数据库中创建索引需要索引字段和指向记录的指针,通过索引可以快速查找到表中的行. 在Neo4j中,其索引是通过属性来创建,便于快速查找 ...

  8. 让git不再跟踪配置文件的变化

    我们经常会在配置文件里留下一些敏感信息 比如数据库链接字符串的用户名和密码 如果不提交配置文件到github或者其他源码管理网站 那么你的粉丝很可能就无法正确运行你的项目,就达不到开源的目的了 那么, ...

  9. PyQt4 的事件与信号 -- 重写事件处理方法

    # PyQt中的事件处理主要依赖重写事件处理函数来实现 import sys from PyQt4 import QtCore, QtGui class MainWindow(QtGui.QWidge ...

  10. PE文件详解(三)

    本文转自小甲鱼的PE文件详解系列传送门 PE文件到内存的映射 在执行一个PE文件的时候,windows 并不在一开始就将整个文件读入内存的,二十采用与内存映射文件类似的机制. 也就是说,windows ...