前言

除了前面介绍,内部类还有一些更高级的用法,下面就简单的介绍一下

接口内部类

内部类除了可以定义在类的内部,也可以定义在接口里面,用法与类类似

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
// Move.java

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");
}
}
}

// AnimalMoveImpl.java
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
// Egg.java
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();
}
}

// BigEgg.java
public class BigEgg extends Egg {

public class Yolk {
public Yolk() {
System.out.println("BigEgg.Yolk");
}
}

public static void main(String[] args) {
new BigEgg();
}
}
1
2
new egg()
Egg.Yolk

从输出结果来看,确实没有覆盖,所以,内部类是不会像方法一样被覆盖,但是,如果手动继承那就另说