`

继承成员内部类的步骤及代码分析

阅读更多

下面使用以下代码讲解成员内部类的继承

package test7;
 
//第一步,引入内部类定义。无论该类是否如子类在同一个包下还是同一个文件下。
import test7.Person.Address;
 
public class ExtendsInnerClassTest {
   public static void main(String[] args) {
      Person p1 = new Person("forestqqqq",20);
      new AddressDetail(p1,"TianJin","HeXi",1234).printAddress();
   }
 
}
 
//外部类Person
class Person{
   private String name;
   private int age;
   public Person(String name,int age){
      this.name = name;
      this.age = age;
   }
   //内部类Address
   public class Address{
      private String city;
      private String street;
      private int number;
      public Address(String city,String street,int number) {
        this.city = city;
        this.street = street;
        this.number = number;
      }
      public Address(int number){
        this.city = "TianJin";
        this.street = "HeXi";
        this.number = number;
      }
      public void printAddress(){
        System.out.println(name+"'s age is "+age+" and  Address is "+city+","+street+number);
      }
   }
}
 
//第二步,使用extends关键字,子类继承该内部类。
//内部类的子类AddressDetail
class AddressDetail extends Address{
  
   //第三步,给子类的每一个构造方法传递一个参数,即外部类实例。
   //(其实这一步是为第四步做准备的,只要第四步能够实现,这一步是可以省略的,
   //也就是说,并不是每一个构造方法都需要传入外部类实例的,只要它能够实现第四步)
   public AddressDetail(
        Person p, //******这就是传入的的父类实例
        String city,String street,int number){
      //第四步,直接或间接(这里是直接)实例化父类内容
      p.super(city,street,number);
   }
  
   //这个第三步省略了
   public AddressDetail(){
      //第四步,直接或间接(这里是间接)实例化父类内容
      this(new Person("forestqqqq",20),"TianJin","HeXi",1234);
   }
}

 

第一 继承成员内部类的步骤(看代码和注释)

1import该类

2继承该类

3在每一个构造方法中添加一个参数,即外部类对象

4在构造方法的第一句,直接或间接的调用外部类对象的super方法,初始化父类内容

第二分析成员内部类的继承方式

 

想弄明白成员内部类的继承方式应该依次弄清楚以下这些知识点:

1内部类是Java语法规范,不是虚拟机规范。虚拟机不清楚Java语法中是否有内部类这种东西,也没精力去维护内部类与外部类之间的复杂的关系。虚拟机只是乐于加载一个又一个的class文件,而且它只知道每一个class文件就代表者一个单独的类就行了。

2内部类与外部类之间的复杂的关系,是在编译器编译java文件成为class文件时生成的。编译器将一文件中的每一个类(内部类或者外部类)分别编译成为不同的class文件。如上例中,编译之后生成4class文件,即,ExtendsInnerClassTest.classPerson.classPerson$Address.classAddressDetail.class。其中Person.class是外部类Personclass文件,Person$Address.class是内部类的class文件。

3编译器是通过改造内部类和外部类的构造方法、普通方法和属性定义来实现两个类之间的复杂联系的。

外部类Person反编译之后的结果:

class Person{
   public Person(String name,int age){
      //..
   }
 
   static String access$0(Person p){
      return ..;
   }
  
   static int access$1(Person p){
      return ..;
   }
 
   private String name;
   private int age;
}

 

内部类Address反编译之后的结果:

class Person$Address{
   public Person$Address(Person p,String city,String street,int number){
      //..
   }
   public Person$Address(Person p,int number){
      //..
   }
 
   public void printAddress(){
      System.out.println(Person.access$0(this.this$0) + "'s age is " + Person.access$1(this.this$0) + " and  Address is " + this.city + "," + this.street + this.number);
   }
 
   private String city;
   private String street;
   private int number;
   final Person this$0;
}

 

 

从代码上我们看到外部类Person中多了两个静态方法access$0access$1,它们分别返回的是nameage,这两个方法是在编译时动态生成的,如果内部类中没有访问到nameage这两个外部类的属性,则这两个静态方法不会生成。正是因为内部类的printAddress方法中使用到了这两个属性,所以才就生成了这两个静态方法。

我们还看到内部类中多了一个外部类的引用属性:

final Person this$0;

 

这个属性保证了内部类与外部类的关联。

我们还看到,编译器改造了内部类的每一个构造方法,为每一个构造方法提供了一个外部类实例作为参数,实际上这个参数是用来初始化this$0这个属性的。这就保证了实例化内部类前必须实例化外部类对象。内部类就好像粘附在外部类实例上一样,外部类的实例总是先于内部类实例存在

4子类继承内部类也需要保证外部类实例先于内部类实例存在。所以子类实例的初始化顺序是,首先初始化外部类实例,然后初始化内部类内容,最后初始化子类独有的内容。因为经过编译器的改造后,内部类Address没有无参的构造方法,所以子类必须直接或者间接的调用父类的构造方法,但是父类每一个构造方法(经过改造后的)都要求有外部类的实例作为参数,所以,你必须给子类构造方法一个外部类实例。其实这是上面第三步和第四步的要求。

第四步的代码:

p.super(city,street,number);

 

是调用的内部类的构造方法,其实它在经过编译器改造之后是

super(p,city,street,number)

 

目的就是实例化父类(内部类)的内容。

 

总结起来就一句话,父类内容先于子类内容存在,外部类内容先于内部类内容存在

1
1
分享到:
评论

相关推荐

    day020-继承加强和设计模式代码和笔记.rar

    实现步骤 :通过对原类文件继承,对原有方法功能的基础上,增强新的功能 使用场景: 不必改变原类,并且对原有功能进行加强的时候,就需要用装饰者模式 3. 适配器模式:(了解) 适配器类:...

    javaSE代码实例

    15.1.4 内部类与外部类之间的成员互访 324 15.1.5 内部类与外部类的预定义对象引用this 327 15.2 局部内部类 328 15.2.1 局部内部类的定义及创建 328 15.2.2 局部变量与局部内部类 329 15.2.3 静态方法中...

    Java实现局域网内两点文件传输

    其中包括实现的原理,以及操作实现的源代码、实现的步骤、每一实现步骤对应的讲解,包括代码注释。 1. 定义 server 类,继承自 ServerSocket 类,并设置了一个常量 SERVER_PORT 表示服务端的端口号。 2. 在静态代码...

    21天学通Java-由浅入深

    240 12.2.1 创建局部内部类 240 12.2.2 在局部内部类中访问外部类成员变量 240 12.2.3 在局部内部类中访问外部类的局部变量 241 12.2.4 静态方法中的局部内部类 243 12.3 静态内部类 244 12.3.1 创建静态内部类 244 ...

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

    该资料是《Visual C++ 2010入门经典(第5版)》的源代码及课后练习答案 对应的书籍资料见: Visual C++ 2010入门经典(第5版) 基本信息 原书名: Ivor Horton's Beginning Visual C++ 2010 原出版社: Wrox 作者: ...

    C++ Primer第四版【中文高清扫描版】.pdf

    17.3.3 多重继承派生类的复制控制 619 17.3.4 多重继承下的类作用域 620 17.3.5 虚继承 622 17.3.6 虚基类的声明 624 17.3.7 特殊的初始化语义 625 小结 628 术语 628 第18章 特殊工具与技术 631 18.1 优化内存分配...

    Visual C++ 2005入门经典--源代码及课后练习答案

    9.3.3 继承类成员的访问级别 455 9.4 派生类中的复制构造函数 456 9.5 友元类成员 461 9.5.1 友元类 462 9.5.2 对类友元关系的限制 462 9.6 虚函数 462 9.6.1 虚函数的概念 465 9.6.2 使用指向类...

    精通MFC (光盘) 源代码

    15.2.1 内部类 15.2.2 接口映射类 15.2.3 聚合的实现 15.3 类厂及其MFC实现 15.3.1 ColeObjectFactory类 15.3.2 全局类厂链 15.3.3 类厂的注册/反注册 15.3.4 类厂对象的创建 15.3.5 类厂对象创建COM对象 ...

    疯狂JAVA讲义

    学生提问:既然内部类是外部类的成员,是否可以为外部类定义子类,在子类中再定义一个内部类来重写其父类中的内部类? 211 6.7.4 局部内部类 211 6.7.5 匿名内部类 212 6.7.6 闭包(Closure)和回调 215 6.8 ...

    C#23种设计模式_示例源代码及PDF

    如:如 何创建及如何向客户端提供。 2、BUILDER — MM 最爱听的就是“我爱你”这句话了,见到不同地方的 MM,要能够用她们的 、 方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到 MM ...

    JAVA面试题最全集

    一、Java基础知识 1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,... Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() ...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    必须要时从Java SE API的源代码分析,了解各种语法在Java SE API中如何应用。  《Java JDK 7学习笔记》将IDE操作纳为教学内容之一,使读者能与实践结合,提供的视频教学能更清楚地帮助读者掌握操作步骤。 内容简介 ...

    JAVA基础课程讲义

    内部类(innerclasses) 88 字符串(java.lang.String类)的使用 90 字符串相等的判断 92 思考作业 93 上机作业 94 第四章 异常机制 95 导引问题 95 异常(Exception)的概念 96 异常分类 96 Error 97 Error和...

    完成Java面向对象程序设计实验课的心得体会(1).doc

    通过对Java的了解,我发现它确实有很多方便之处,它集抽象性、封装 性、继承性和多态性于一体,实现了代码重用和代码扩充,提高了软件开发的效率。对 于我们这个专业来说学好Java语言是很重要的,所以在实验的过程中...

    从J2SE到J2EE知识点介绍

    3. 内部类 23 (七).集合 30 1.Map集合 30 2. ArrayList集合 32 3. LinkedList集合 33 (八).异常处理 34 1. 异常类的产生、捕获与处理 34 2. 抛出异常 36 二. Swing程序设计 38 (一) Swing概述 38 1. 布局管理器...

    MFC教程入门知识全集.rar

    1.1.2.2 类的使用 (例子代码EX01-00) 1.2 函数的重载 1.2.1 重载参数个数不同的函数 (例子代码EX01-01) 1.2.2 重载参数数据类型不同的函数 (例子代码EX01-02) 1.3 构造函数与析构函数 1.3.1 构造函数 ...

    java基础题 很全面

    71. 内部类可以引用他包含类的成员吗?有没有什么限制? 15 J2EE 15 1. JSP的内置对象及方法。 15 2. JSP的常用指令 16 3. Request对象的主要方法: 16 4. jsp有哪些动作?作用分别是什么? 16 5. JSP中动态INCLUDE与...

    Java语言基础下载

    内部类 106 实例分析 110 抽象类,接口 115 内容总结 120 独立实践 121 第八章:异常 122 学习目标 122 异常的概念 123 异常的分类 123 实例分析 124 自定义异常 126 方法覆盖和异常 127 内容总结 129 第九章:基于...

Global site tag (gtag.js) - Google Analytics