一般有四种内部类的使用方式:
- 嵌套的内部类
- 方法内的内部类
- 静态内部类
- 匿名内部类
什么时候用内部类:
- 有时候明显一个类只有另一个类使用,且他们的关联性较强。(此时使用内部类可以省去为每个类创建文件)
- 有些类需要访问另一个类的内部成员,甚至私有成员。如果用两个类实现,需要暴露一些接口出来,为了增强了封装性,可以选择使用内部类。这种情况类似于C++的友元(有人会说,那干脆把内部类和外部类合并算了,但是这样就少了一层抽象,会逐渐形成上帝类)。
- 内部类可以的定义在紧邻它使用的地方,从而增强可读性和可维护性。
- 当一个内部类只有在某个方法内部使用,且你懒得去为这个内部类想一个名字(通常这个名字没必要,因为外部没人用到它),此时你可以选择匿名内部类(匿名内部类用于实现接口,跟javafx框架结合用起来很方便,待研究)。
- A common use of static nested class is ViewHolder design pattern in RecyclerView and ListView(inner class的使用是基于一些设计的需要引入的,待研究)
- 内部类是实现类似C++多继承的一种方式(这一条在on java8中被认为是使用内部类最重要的一个理由)。
interface Super{
void Show();
// void Method();
}
class Outer {
// Simple nested inner class
class Inner1 {
public void Show() {
System.out.println("Inner1.Show()");
}
}
void OuterMethod() {
int para = 5;
System.out.println("Outer.OuterMethod()");
// Inner class is local to outerMethod()
class Inner2 { // [1]
void Show() {
System.out.println("Inner2.Show(), inner1.para = " + para);
}
@Override
protected void finalize() {
System.out.println("\nInner2.finalize(), inner1.para = " + para); // [2]
}
}
Inner2 y = new Inner2();
y.Show();
System.out.println("OuterMethod is over!");
}
// A static inner class
static class Inner3 {
public static void main(String[] args) { // [3] 静态内部类可以有静态main方法
System.out.println("Inner3.main()");
new Outer().OuterMethod();
}
void Show() {
System.out.println("Inner3.Show()");
}
}
// An anonymous class with Demo as base class
// [4]
static Super inner4 = new Super() { // 匿名内部类对象可以通过new一个接口,也可以new一个父类来实现。
@Override
public void Show() {
System.out.println("I am in anonymous inner class");
}
// @Override
// public void Method(){}
};
}
class InnerClassDemo {
public static void main(String[] args) {
Outer out = new Outer();
System.out.println("\ncase 1 out put:");
Outer.Inner1 in = out.new Inner1(); // 能够这样定义对象的前提是,Inner类不是private属性的。
in.Show();
System.out.println("\ncase 2 out put:");
out.OuterMethod();
System.out.println("\ncase 3 out put:");
new Outer.Inner3().Show();
System.out.println("\ncase 4 out put:");
out.inner4.Show();
System.gc(); // [5]
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
case 1 out put:
Inner1.Show()
case 2 out put:
Outer.OuterMethod()
Inner2.Show(), inner1.para = 5
OuterMethod is over!
case 3 out put:
Inner3.Show()
case 4 out put:
I am in anonymous inner class
Inner2.finalize(), inner1.para = 5
代码中的标注解释:
[1]. 外部类方法OuterMethod中的内部类,不能是private/public/protected/static/transient,但可以是final。因为这个内部类是无法通过OuterMethod之外的任何方法访问的,所以设置权限没有意义。
[2]. JDK 1.8之前,方法内的内部类,不能访问方法内的局部变量,除非变量是final的。(但不知道为什么JDK1.8又能够访问了)。这里使用finalize为了验证可能存在的副作用。
[3]. 不允许非静态内部类中有静态方法。(因为这种情况下,你没有办法调用这个静态方法)
[4]. 匿名内部类内部类用于实现接口,且只有一个方法时,可以使用lambda表达式。可以替换为更简洁的lambda表达式写法: static Super inner4 = () -> System.out.println("i am in anonymous class");
[5]. 在OuterMethod方法调用结束很久后,还访问了其中的局部变量,说明了内部类使用包含它的方法的局部变量可能存在隐患(虽然这里还能打出来值,是因为没有被覆写,但是很危险)。finalize的副作用见gc&finalize()。。
网友评论