6.7.3 使用内部类

6.7.3 使用内部类

1. 在外部类内部使用内部类

在外部类内部使用内部类时,与平常使用普通类没有太大的区别。一样可以直接

  • 通过内部类类名来定义变量,
  • 通过new调用内部类构造器来创建实例。

唯一存在的一个区别是:**不要在外部类的静态成员(包括静态方法和静态初始化块)中使用非静态内部类,因为静态成员不能访问非静态成员**。

2. 在外部类以外使用非静态内部类

如果希望在外部类以外的地方访问内部类(包括静态和非静态两种),则内部类不能使用private访问控制权限, private修饰的内部类只能在外部类内部使用。对于使用其他访问控制符修饰的内部类,则能在访问控制符对应的访问权限内使用。也就是:

  • 如果省略访问控制符的内部类,只能被与外部类处于同一个包中的其他类所访问。
  • 如果使用protected修饰的内部类,可被与外部类处于同一个包中的其他类和外部类的子类所访问
  • 如果使用public修饰的内部类,可以在任何地方被访问。

在外部类之外定义内部类的引用变量

在外部类以外的地方定义内部类(包括静态和非静态两种)变量的语法格式如下:
OuterClass.InnerClass varName;

完整的内部类类名

从上面语法格式可以看出,在外部类以外的地方使用内部类时,内部类完整的类名应该是OuterClass.InnerClass。如果外部类有包名,则还应该增加包名前缀。

在外部类之外创建非静态内部类对象

由于非静态内部类的对象必须寄生在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类对象。在外部类以外的地方创建非静态内部类实例的语法如下:
outerInstance.new InnerConstructor();

从上面语法格式可以看出,在外部类以外的地方创建非静态内部类实例必须使用外部类实例new来调用非静态内部类的构造器

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
class Out
{
// 定义一个内部类,不使用访问控制符,
// 即只有同一个包中其他类可访问该内部类
class In
{
public In(String msg)
{
System.out.println(msg);
}
}
}
public class CreateInnerInstance
{
public static void main(String[] args)
{
Out.In in = new Out().new In("测试信息");
/*
上面代码可改为如下三行代码:
使用OutterClass.InnerClass的形式定义内部类变量
Out.In in;
创建外部类实例,非静态内部类实例将寄存在该实例中
Out out = new Out();
通过外部类实例和new来调用内部类构造器创建非静态内部类实例
in = out.new In("测试信息");
*/
}
}

非静态内部类的构造器必须使用外部类对象来调用

继承非静态内部类

当创建一个子类时,子类构造器总会调用父类的构造器,因此在创建非静态内部类的子类时,必须保证让子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,必须存在一个外部类对象。

非静态内部类In对象和器子类SubClass对象都必须持有指向Outer对象的引用,区别是创建两种对象时传入Out对象的方式不同:

  • 当创建非静态内部类In类的对象时,必须通过Outer对象来调用new关键字;
  • 当创建创建非静态内部类In类的子类的对象时,必须使用Outer对象作为调用者来调用ln类的构造器,
    • 这就要求在SubClass的构造器中传如一个外部Outer对象,然后

非静态内部类的子类不一定是内部类,它可以是一个外部类。
非静态内部类的子类实例一样需要保留一个引用,该引用指向其父类所在外部类的对象。也就是说,如果有一个内部类子类的对象存在,则一定存在与之对应的外部类对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Out {
// 定义一个内部类,不使用访问控制符,
// 即只有同一个包中其他类可访问该内部类
class In {
String msg;

public In(String msg) {
System.out.println(msg);
}
}
}

public class SubClass extends Out.In {
// 显示定义SubClass的构造器
public SubClass(Out out, String msg) {
// 通过传入的外部类对象out来显式调用内部类In的构造器
// super相当于In
out.super(msg);
}
}

3. 在外部类以外使用静态内部类

创建静态内部类对象时无须创建外部类对象

创建静态内部类实例

在外部类以外的地方创建静态内部类实例的语法如下:
new OuterClass.InnerConstructor();
不管是静态内部类还是非静态内部类,它们声明变量的语法完全一样。
区别只是在创建内部类对象时,

  • 静态内部类只需使用外部类即可调用构造器,
  • 而非静态内部类必须使用外部类对象来调用构造器。

继承静态内部类

因为调用静态内部类的构造器时无须使用外部类对象,所以创建静态内部类的子类也比较简单,下面代码就为静态内部类StaticIn类定义了一个空的子类。

1
2
3
public class StaticSubClass extends StaticOut.StaticIn{

}

优先使用静态内部类

相比之下,使用静态内部类比使用非静态内部类要简单很多,只要把外部类当成静态内部类的包空间即可。因此当程序需要使用内部类时,应该优先考虑使用静态内部类