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

本文要点如下:

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. maven 打包Could not resolve dependencies for project和无效的目标发行版: 1.8

    1.maven 打包Could not resolve dependencies for project 最近项目上使用的是idea ide的多模块话,需要模块之间的依赖,比如说系统管理模块依赖授权模 ...

  2. 4.1 State Snapshot Transfer

    摘要: 出处:黑洞中的奇点 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但请保留该 ...

  3. Solr 管理界面删除所有数据

    https://my.oschina.net/lcdmusic/blog/326698

  4. php 运行的四种模式

    1)cgi 通用网关接口(Common Gateway Interface)) CGI即通用网关接口(Common Gateway Interface),它是一段程序, 通俗的讲CGI就象是一座桥,把 ...

  5. vue-router源码学习(一)

    因为v3.01版本中的   /src代码使用TypeScript进行书写,我这里仅仅用作模块学习, 具体学习的还是 /dist/vue-router.js 代码. (一)基本使用方式 JS代码 // ...

  6. springMVC(6)---处理模型数据

    springMVC(6)---处理模型数据 之前一篇博客,写个怎么获取前段数据:springMVC(2)---获取前段数据,这篇文章写怎么从后端往前端传入数据. 模型数据类型             ...

  7. 从JVM字节码执行看重载和重写

    Java 重写(Override)与重载(Overload) 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的 ...

  8. Swift语言中与C/C++和Java不同的语法(四)

    这一节,我们将会讨论一下Swift中的函数相关的基本内容 首先是函数的创建: func sayHello (name:String) -> String { return "Hello ...

  9. 关于 python 新式类和旧式类继承顺序的验证

    参考:http://www.cnblogs.com/blackmatrix/p/5630515.html 官方:https://docs.python.org/2/tutorial/classes.h ...

  10. 利用pip批量更新python库

    如果python库比较旧,需要更新到最新版本,可以利用pip工具. DOS命令行下,输入pip -V查看pip版本,可以先把pip更新到新版本. 查看系统里过期的python库 pip list #列 ...