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

本文要点如下:

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. python爬取大众点评

    拖了好久的代码 1.首先进入页面确定自己要抓取的数据(我们要抓取的是左侧分类栏-----包括美食.火锅)先爬取第一级分类(美食.婚纱摄影.电影),之后根据第一级链接爬取第二层(火锅).要注意第二级的p ...

  2. 【liferay】2、可配置portlet

    定义:edit和config模式一般没有使用,对于使用editor和config等模式的portlet,我们可以将他们称为可配置portlet. 我们先新建一个portlet项 添加可配置的控制元素, ...

  3. [编织消息框架][JAVA核心技术]动态代理介绍

    由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展 ...

  4. Python sort方法

    官方文档: sort(*, key=None, reverse=False) This method sorts the list in place, using only < comparis ...

  5. Vuejs之开发环境搭建

    Vue.js Vue.js是目前很火的一个前端框架,采用MVVM模式设计,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们能够快 ...

  6. Javascipt数组

    Javascipt数组 在Javascript中数组的做用是:使用单独的变量名来储存一系列的值. 数组只有一个属性,就是length,length表示的数组所占内存空间的数目. <!DOCTYP ...

  7. 淘宝NPM源的使用

    npm作为国外的node仓库安装工具,自然会受到我大长城防火墙的干扰,国内用户在安装相关的资源的时候,会出现安装失败,以及速度很慢的情况.为了解决npm安装的问题,国内出现了很多npm的镜像网址,ta ...

  8. Java Web高级编程(三)

    使用过滤器改进应用程序 一.过滤器的目的 过滤器是可以拦截访问资源的请求.资源的响应或者同时拦截两者的应用组件.过滤器可以检测和修改请求和响应,同时也可以拒绝.重定向或转发请求.javax.servl ...

  9. 嵌入式linux下wifi网卡的使用(四)——应用程序sub_supplicant编译

    有readme先看看readme看看有没有编译的方法 里面告诉我们安装时可能会依赖某些库事实证明会依赖openssl库,之前也使用过openssl 这个文件中有个defualtconfig,先用它做. ...

  10. 【CSS初识】

    一.CSS是什么? CSS是一种样式表语言,用于为HTML文档定义布局.例如,CSS涉及字体.颜色.边距.高度.宽度.背景图像.高级定位等方面. HTML用于结构化内容:CSS用于格式化结构化的内容. ...