下面使用以下代码讲解成员内部类的继承
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文件。如上例中,编译之后生成4个class文件,即,ExtendsInnerClassTest.class、Person.class、Person$Address.class和AddressDetail.class。其中Person.class是外部类Person的class文件,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$0和access$1,它们分别返回的是name和age,这两个方法是在编译时动态生成的,如果内部类中没有访问到name和age这两个外部类的属性,则这两个静态方法不会生成。正是因为内部类的printAddress方法中使用到了这两个属性,所以才就生成了这两个静态方法。
我们还看到内部类中多了一个外部类的引用属性:
final Person this$0;
这个属性保证了内部类与外部类的关联。
我们还看到,编译器改造了内部类的每一个构造方法,为每一个构造方法提供了一个外部类实例作为参数,实际上这个参数是用来初始化this$0这个属性的。这就保证了实例化内部类前必须实例化外部类对象。内部类就好像粘附在外部类实例上一样,外部类的实例总是先于内部类实例存在。
4子类继承内部类也需要保证外部类实例先于内部类实例存在。所以子类实例的初始化顺序是,首先初始化外部类实例,然后初始化内部类内容,最后初始化子类独有的内容。因为经过编译器的改造后,内部类Address没有无参的构造方法,所以子类必须直接或者间接的调用父类的构造方法,但是父类每一个构造方法(经过改造后的)都要求有外部类的实例作为参数,所以,你必须给子类构造方法一个外部类实例。其实这是上面第三步和第四步的要求。
第四步的代码:
p.super(city,street,number);
是调用的内部类的构造方法,其实它在经过编译器改造之后是
super(p,city,street,number)
目的就是实例化父类(内部类)的内容。
总结起来就一句话,父类内容先于子类内容存在,外部类内容先于内部类内容存在
相关推荐
首先,内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类就像是外部类的一个成员,它可以访问外部类的所有成员,包括私有成员。局部内部类只在方法或块的范围内有效,而匿名内部类...
成员内部类是定义在一个类的成员位置的类,它就像是类的一个普通成员变量或方法。成员内部类可以直接访问外部类的所有成员,包括私有成员,因为它们之间有隐式的引用关系。 2. 局部内部类: 局部内部类是定义在...
静态内部类是一种特殊的成员内部类,它可以被外部类的静态方法访问,并且不需要依赖于外部类的实例就可以创建。静态内部类的定义与普通内部类类似,但需要加上 `static` 关键字。 ##### 2.1 访问静态内部类 静态...
1. **成员内部类**:如同普通的成员变量一样,成员内部类可以是public、protected或private,也可以没有访问修饰符。它可以访问外部类的所有成员,包括实例变量和方法。 2. **局部内部类**:定义在方法、构造器或块...
1. **成员内部类**:这是最常见的内部类形式,它可以作为外部类的成员存在,拥有访问外部类的所有成员的权限,包括私有成员。成员内部类可以是静态的,也可以是非静态的。静态内部类不持有对外部类的引用,而非静态...
内部类可以分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。本文主要讨论非静态内部类(也称为实例内部类)的使用及其特点。 首先,非静态内部类的一个关键特性是它拥有对外部类的隐式引用。这意味...
- **成员内部类**:像成员变量一样,可以在类的主体中定义,与类的其他成员处于同一级别。 - **方法内部类**(局部内部类):定义在某个方法内部,只在该方法的作用域内有效。 - **匿名内部类**:没有名字的内部...
在C#编程语言中,类的继承是面向对象编程的核心概念之一,它允许我们创建一个新类(子类或派生类),该类基于现有类(基类或父类)的功能,同时可以添加新的特性或扩展已有的功能。通过继承,我们可以重用代码,提高...
继承(Inheritance)则是另一种复用代码的方法,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以扩展或修改父类的功能,实现“is-a”关系。比如,我们可以定义一个Vehicle类,然后创建更具体的Car...
3. 匿名内部类可以访问和修改其外部类的成员,包括私有成员,但不能访问final修饰的局部变量。 4. 匿名内部类可以作为方法的返回值,也可以作为参数传递。 接下来,我们谈谈适配器模式。适配器模式是一种结构型设计...
内部类可以是成员内部类、局部内部类、匿名内部类或者静态内部类,每种都有其特定的用途和使用场景。在日常编程实践中,内部类能够帮助我们更好地组织代码,实现更复杂的设计模式。 1. 成员内部类:成员内部类就像...
`public`使得成员对所有类可见,`private`限制成员只在当前类内部可见,而`protected`则允许子类访问这些成员。在`Circle`类中,`radius`属性使用`private`保护,但通过`public`的`Radius`属性进行访问,这是封装...
4. 静态内部类:静态内部类与普通成员内部类的区别在于,静态内部类不持有对外部类的引用,因此可以独立于外部类实例存在。它们可以用static关键字修饰,并且可以通过外部类名直接创建实例。 ```java public class ...
总的来说,理解并正确使用PHP的类继承机制是提升代码复用性和可维护性的重要步骤。遇到上述问题时,应根据需求选择合适的解决方案,例如使用接口、组合、抽象类和抽象方法,以及合理设置访问权限和利用final关键字来...
继承是面向对象编程的一个关键特性,允许一个类(子类)继承另一个类(父类)的属性和方法,从而避免重复代码,提高代码复用率。子类可以扩展父类的功能,同时保持原有的行为,这就是所谓的多态性。 1. 继承...
内部类可以分为成员内部类、静态内部类、方法内部类和匿名内部类。 **成员内部类**: - 成员内部类是最常见的内部类形式,它可以访问外部类的所有成员,包括私有成员。 - 在成员内部类中,可以创建外部类的实例,但...
3. 类的成员的访问控制:类的成员可以分为公有成员和私有成员,公有成员可以在类外部访问,私有成员只能在类内部访问。访问控制的目的是保护类的内部实现细节,提高代码的安全性和可维护性。 4. 构造函数和析构函数...
内部类是Java特有的特性,它可以定义在类的内部,有成员内部类、局部内部类、匿名内部类和静态内部类四种类型。内部类可以访问外部类的所有成员,包括私有成员,这为封装提供了强大支持。局部内部类仅在方法或块中...
Java程序设计中的高级类特性是Java编程中至关重要的一部分,这些特性包括了静态成员、final关键字、抽象类、接口以及内部类。本章将详细探讨这些关键概念。 首先,`static`关键字是Java中一个非常重要的修饰符。它...