前言
除了前面介绍,内部类还有一些更高级的用法,下面就简单的介绍一下
接口内部类
内部类除了可以定义在类的内部,也可以定义在接口里面,用法与类类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public interface Move {
void run(); void walk();
class Run {
public void move() { System.out.println("run"); } }
class Walk { public void move() { System.out.println("walk"); } } }
public class AnimalMoveImpl implements Move { @Override public void run() { new Run().move(); }
@Override public void walk() { new Walk().move(); } }
|
多层嵌套内部类访问外围类成员
内部类无论嵌套了多少层,内部类都是可以无条件的访问外部的成员,包括private
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class MultiInner { private int val = 0; class Inner1 { { System.out.println(val); } class Inner2 { { System.out.println(val); } class Inner3 { { System.out.println(val); } } } } }
|
内部类继承
这是一个比较有意思的事情
NOTE: 这里说的内部类继承不是内部类继承其他类,而是其他类继承内部类
1 2 3 4 5 6 7 8
| class WithInner { class Inner {} }
public class InheritInner extends WithInner.Inner {
}
|
在想象中应该是这样写,没问题,但是如果在ide中敲代码,编译器会报错
1
| No enclosing instance of type 'xxx.xxx.xxx.WithInner' is in scope
|
意思为没有封闭类型的WithInner类型,在ide会提示一种方案是将Inner改为静态内部类,这样确实可以解决问题,但是如果不能用静态内部类呢?
试想一下为什么静态内部类可以,而成员内部类会报错,这两者有什么区别?
回头看一下发现,成员内部类在创建的时候是要依赖外部类的实例对象,但是在第三方类继承内部类的时候,没有外部类对象,这样就无法构成闭环,所以报错。解决办法也很简单,在构造第三方类的时候,手动提供一个外部类对象,并对其初始化即可
1 2 3 4 5 6 7 8 9 10
| public class InheritInner extends WithInner.Inner { InheritInner(WithInner wi) { wi.super(); }
public static void main(String[] args) { WithInner wi = new WithInner(); InheritInner ii = new InheritInner(wi); } }
|
内部类能被覆盖吗?
你觉得呢?
分析一下,内部类(以成员内部类来说)依赖于外部类,被编译器编译成WithInner$Inner.class
,假如说有个WithInner
的子类SubWithInner
包含了一个同名的Inner
类,这个会覆盖父类中的Inner吗?子类中的Inner被编译成SubWithInner$Inner.class
这明显与父类中的类名不一样。所以理论上是不会覆盖的。实践一下!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Egg {
private Yolk y;
protected class Yolk { public Yolk() { System.out.println("Egg.Yolk"); } }
public Egg() { System.out.println("new egg()"); y = new Yolk(); } }
public class BigEgg extends Egg {
public class Yolk { public Yolk() { System.out.println("BigEgg.Yolk"); } }
public static void main(String[] args) { new BigEgg(); } }
|
从输出结果来看,确实没有覆盖,所以,内部类是不会像方法一样被覆盖,但是,如果手动继承那就另说