文章目录
1 内部类的简介
1.1 内部类的定义
可以将一个类的定义放在另一个类的定义的内部,这就是内部类。
1.2 内部类的功能
- 1 组织逻辑相关的类
- 2 实现一种代码隐藏机制
- 3 与外围类通信
1.3 内部类的优缺点
优点:Java 的内部类是非常有用的特性,在实现多重继承上,Java 的内部类给予我们更大的操作空间,比起同是面向对象语言的 C++,内部类在实现与理解上更为简单。
注意:C++ 没有内部类特性,但它依旧可以实现多重继承;java 的内部类与 C++ 的嵌套类是非常不同的。
缺点:难以把握使用内部类的需求;实现它难以做到优雅、清晰。
1.4 内部类使用的注意事项
对于使用内部类,我们必须在 coding 前深思熟虑,“%80 的程序功能都是由 %20 的代码实现的”,内部类属于比较深奥复杂的特性,在许多功能的实现上,我们可以使用更简单的特性去实现。
内部类的使用应该是在设计阶段考虑的问题,使用它之前应该给予足够的理由。
2 内部类的创建与使用
2.1 一个简单内部类的创建实例
下面创建了一个包含内部类的类:(内部类可以拥有自己的成员与方法)
public class Test {
// 代码段1
class Inner {
private int n = 810;
public void readValue() { System.out.println(n); }
}
// 代码段2
public void useInner() {
Inner i = new Inner();
i.readValue();
}
// 测试
public static void main(String[] args) {
// 测试代码段1
Test t = new Test();
Test.Inner ti = t.new Inner();
ti.readValue();
// 测试代码段2
new Test().useInner();
}
} /* Output:
810
810
*/
解析:
代码段 1:注意在测试代码段 1 时,我们先创建了一个外围类对象(前提内部类是非 static 的,这种情况要另行讨论),而不是直接用Test.Inner ti = new Test.Inner();
或者Test.Inner ti = new Inner();
(注意:用这两种方法会直接报错)。这是因为内部类有一个非常重要的隐藏特点:内部类的对象需要隐形地连接其外围类对象。
我们都知道:内部类拥有对其外围类所有成员的访问权,所以内部类一定要能联系到外围类的对象实体,这样才能访问相应的值,以避内部类在访问逻辑上出错。
代码段2:在外围类的方法中创建内部类对象时,可以直接使用Inner i = new Inner();
这种格式,这是因为外围类拥有其内部类的访问权(内部类的内部对于外围类来说是不可视的,这与作用域有关),注意:此处我们虽然没有创建外围类对象,但是在测试代码段 2 时,我们用的是new Test().useInner();
,所以最终在实际生成内部类对象时还是创建了外围类对象。
注意:内部类对象的创建必须借助外围类对象,无论什么情况。
2.2 创建有关内部类的常用方法
通常关于内部类,我们会在外围类中创建一个返回内部类对象引用的方法,这有便于内部类的设计与使用。
public class Test {
class Inner {
private int n = 810;
public void readValue() { System.out.println(n); }
}
// 返回内部类引用的方法
public Inner getInner() {
return new Inner();
}
// 测试
public static void main(String[] args) {
Test t = new Test();
Test.Inner ti = t.getInner(); // 使用返回内部类对象引用的方法来创建内部类对象
ti.readValue();
}
} /* Output
810
*/
注意:
- 1 上述方法的功能也可以通过 .new 来实现。
- 2 内部类对象依旧需要与外围类对象“连接”。
2.3 使用 .new 来创建内部类对象
.new 语法对于创建内部类对象是极为方便的,与常用的返回内部类对象引用的方法一样,它们都需要与外围类对象相关联,示例如下:
public class Test {
class Inner {
private int n = 810;
public void readValue() { System.out.println(n); }
}
// 测试
public static void main(String[] args) {
Test t = new Test();
Test.Inner ti = t.new Inner(); // 使用 .new 创建内部类对象
ti.readValue();
}
} /* Output
810
*/
我们不会用OuterClassReference.new OuterClassName.InnerClassName()
来创建内部类对象(这种方式会直接报错),这是因为从逻辑上我们已经得到了外围类的对象引用 OuterClassReference,它可以访问内部类名称,所以OuterClassName 是多余的,使用OuterClassReference.new InnerClassName()
即可。
2.4 使用 .this 生成外围类对象引用
我们时常在外部生成内部类对象,可是我们如何在内部类中生成外围类对象呢?解决方案是使用 .this 语法。示例如下:
public class Outer {
void show() { print("Outer.show()"); }
public class Inner {
public Outer getOuter() {
return Outer.this; // 使用 .this 在内部类中创建外围类对象
}
}
public Inner getInner() { return new Inner(); }
public static void main(String[] args) {
Outer t = new Outer();
Outer.Inner ti = t.getInner();
ti.getOuter().show();
}
}/* Output
Outer.show()
*/
解析:我们通过调用内部类对象的方法 Outer() 得到了外围类对象的引用,从而调用外围类对象的方法
注意:这个通过 .this 返回的外围类对象引用是可以被显式得到的,可以创建一个外围类引用来指向这个对象。
3 总结
- 1 创建内部类的对象前,必须创建其所属外围类的的对象,使两者隐形相连,简单点说,就是内部类对象的创建需要借助外围类对象。
- 2 内部类拥有外围类所有成员的访问权。
- 3 使用内部类前需要有足够的理由并提前设计。
4 备注
更多细节可以看 Bruce Eckel 所著的《Java 编程思想》,本博文多为该书的学习心得,欢迎大家一起探讨。