内部类(inner class)
是定义在另一个类中的类。
使用内部类的原因 :
- 内部类可以对同一个包中的其他类隐藏。
- 内部类方法可以访问定义在这个类的作用域中的数据,包括原本私有的数据。
在Java中内部类的对象有一个隐式的引用,指向实例化这个类的外部对象。通过这个指针它可以访问外部类的全部状态。
但静态内部类没有附加这个指针。
6.3.1 使用内部类访问对象状态
可以使用内部类访问外部类的字段及方法
package innerClass;
public class Test02 {
private int age = 10;
public void h() {
System.out.println("haha");
}
public class Inner {
public void m() {
// Test02.this 得到外部类的引用
System.out.println(Test02.this.age);
Test02.this.h();
}
}
public static void main(String[] args) {
Test02 test02 = new Test02();
Inner inner = test02.new Inner();
inner.m();
}
}
6.3.2 内部类的特殊语法规则
在内部类中使用外部类引用 : OuterClass.this
在Java中,当你创建一个外部类的对象时,内部类的对象并不会自动创建。外部类和内部类是独立的实体,它们的生命周期和创建方式是分开的。
通过外部类创建一个内部类 : new OutClass().new InnerClass()
静态内部类可以脱离外部类直接创建 : new OutClass.InnerClass()
6.3.3 内部类是否有用,必要和安全
内部类是一个编译器现象
,与虚拟机无关。编译器将内部类转换为常规的类文件,用$
分隔外部类名与内部类名,而虚拟机对此一无所知。
6.3.4 局部内部类
局部内部类被定义在方法的内部。
声明局部内部类时不能有访问修饰符(public或private)
。
局部类的作用域被限定在声明这个局部类的块中。
6.3.5 由外部方法访问变量
局部类不仅能够访问外部变量,也能访问局部变量,但那些局部变量必须是实际最终变量(effectively final)
。
package innerClass;
public class OutClass02 {
public void f() {
String text = "hello";
class InnerClass02 {
public void m() {
System.out.println(text);
}
}
InnerClass02 class02 = new InnerClass02();
class02.m();
}
public static void main(String[] args) {
new OutClass02().f();
}
}
6.3.6 匿名内部类
如果只是想创建一个类甚至不需要给这个类取名字,这种类叫匿名内部类(anonymous inner class)
,匿名内部类通常与接口一起使用。
由于构造器名必须和类名保持一致,但匿名内部类没有类名,所以匿名内部类没有构造器,但它当扩展一个类时还是可以调用父类的构造器。
虽然匿名内部类没有构造器,但他可以有对象初始化块
。
这里还有一个小技巧,用于初始化数组或列表
package anonymousInnerClass;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test01 {
public static void f(List<String> list) {
list.stream().forEach(System.out::println);
}
public static void main(String[] args) {
List<String> list = Arrays.asList("abc", "efg");
f(list);
// 双括号初始化 (double brace initialization)
f(new ArrayList<String>() {{
add("abc");
add("efg");
}});
}
}
在匿名内部类中获得外部类
package anonymousInnerClass;
import java.util.ArrayList;
public class Test02 {
public static void main(String[] args) {
System.out.println(new ArrayList() {
}.getClass().getEnclosingClass().getName());
}
}
6.3.7 静态内部类
有时候使用内部类只是想把类隐藏在另一个类的内部,并不需要内部类有外部类的引用,此时可以将类声明成static
,这样就不会产生那个引用了。
package anonymousInnerClass;
import innerClass.Test02;
import java.util.Arrays;
public class Test03 {
public static class Pair {
private int first;
private int second;
public Pair(int first, int second) {
this.first = first;
this.second = second;
}
public int getFirst() {
return first;
}
public int getSecond() {
return second;
}
}
public static Pair find(int ...numbers) {
int max, min;
max = min = numbers[0];
for (int i = 1; i < numbers.length; i++) {
max = Math.max(max, numbers[i]);
min = Math.min(min, numbers[i]);
}
return new Pair(max, min);
}
public static void main(String[] args) {
Test03.Pair pair = find(1, 2, 4);
System.out.println(pair.getFirst());
System.out.println(pair.getSecond());
}
}
只要内部类不需要访问外围对象,就应该使用静态内部类。有人也称其为嵌套类(nested class)
表示静态内部类。