本文主要以成员内部类 为讲解对象
本文要点如下:
- 成员内部类的子类可以是内部类,也可以不是内部类;
- 当成员内部类的子类不是内部类或子类虽是内部类但与其父类不在同一个外部类时,子类的构造方法第一句要显式添加如下的语句:
外部类对象引用.super(参数);
这里的外部类指父类所在的外部类 - 编译器默认给成员内部类的构造方法传入一个参数,该参数是内部类所依附的外部类对象的引用;
注:本文涉及到的类都是非静态类
先看个例子
class Man {
public Man() {
}
public void getWoman() {
int num1 = 1; // jdk8隐式给局部变量加了final修饰符
class Woman { //局部内部类
int num2 = 0;
//局部内部类放在外部类的方法体内,前面不能有修饰符
public void showInner() {
System.out.println(num1);
//num1++; num1是final变量,无法变动
//局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰,jdk8默认num1是final变量
System.out.println(num2);
}
}
//局部内部类的对象需在内部类编译后再创建
//局部内部类对于外界是隐藏的,因此需要在内部类里面完成对象的定义和引用
new Woman().showInner();
}
public static void main(String[] args) {
Man m = new Man();
m.getWoman();
}
}
子类Woman存在于父类Man的方法getWoman()中,此时在方法中定义的属性变量 jdk8默认在其前面加上了final标识,在子类中不可更改。
1.子类是内部类且与父类在同一个外部类
class WithInner {
class Inner {
}
class InheritInner extends Inner {
InheritInner() {
System.out.println("*****");
}
}
public static void main(String[] args) {
// Person per = new Person();
WithInner wi = new WithInner();
//主方法在WithInner里,不用 WiteInner.InheritInner 形式
InheritInner obj = wi.new InheritInner();
}
}
运行结果如下
*****
此时子类InheritInner和父类Inner位于同一个外部类WithInner下
WithInner wi = new WithInner();
InheritInner obj = wi.new InheritInner();
使用父类的外部类对象引用.new 子类构造方法()
格式调用构造方法
2. 子类是内部类但与父类不在同一个外部类下
class WithInner {
class Inner {
}
}
class Person {
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
System.out.println("*****");
}
}
public static void main(String[] args) {
Person per = new Person();
WithInner wi = new WithInner();
InheritInner obj = per.new InheritInner(wi);
}
}
使用子类的外部类对象引用.new 子类构造方法(父类外部类对象引用)
格式调用子类构造方法
子类InheritInner中显式添加了wi.super();在构造方法中传入了父类对象的引用
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
System.out.println("*****");
}
这是因为,子类与父类处于不同的外部类,编译时,子类的构造方法默认传入的是子类的外部类Person类的对象引用,而不是父类Inner类的对象引用;
如果要调用父类的构造方法的话,必须要给它传入一个其外部类WithInner的对象引用;
所以这时,子类的构造方法显式传入一个WithInner类对象引用wi,并通过wi.super();的方式把wi传给父类的构造方法并调用之。
3. 子类不是内部类
class WithInner {
class Inner {
}
}
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
System.out.println("*****");
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
}
}
父类Inner位于外部类WithInner下,子类InheritInner没有外部类
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
声明子类对象引用时直接调用子类构造方法即可,注意参数为父类的外部类对象引用
总结:
-
内部类是如何依附于外部类的?
编译器编译时,是把外部类与成员内部类编译成两个独立的文件的;
但会给成员内部类默认添加一个类型为外部类对象引用的成员变量,并为构造方法默认传入一个类型为外部类对象引用的参数,并以该参数值来初始化该成员变量。
-
创建子类对象时,要先调用父类构造方法再调用子类构造方法。
-
子类构造方法中如果没有显式调用super(参数),则会在构造方法最前面默认添加super();
-
只有子类和父类都是同一个类的成员内部类时,可以不用
父类外部类对象引用.super()