内部类(Inner Class)
可以将一个类的定义放在另一个类的定义内部,这就是内部类。
内部类特点
- 可用public、protected、private和默认(package-private)关键字修饰,作用域跟普通类的作用于相同。
// A称之为外围类
public class A {
// 用public关键字修饰可以被所有类访问
public class AA {}
// 用protected关键字修饰可以被自身、外部类、子类访问
protected class AB {}
// 只能被外部类和自身访问
private class AC {}
// 只能被自身、同包的类访问到
class AD {}
// 只有同外部类的内部类才能继承改外部类的其他内部类
class AE extends AB {}
public static void main(String... args) {
// 外围类实例化后的对象才能实例化内部类
A a = new A();
A.AE ae = a.new AE();
}
}
- 内部类能访问其外围对象的所有成员,而不需要任何特殊条件。
public class A {
private final int i = 1;
public class B {
public int getI() {
return i;
}
}
}
- 静态内部类(嵌套类)不需要对外部类对象的引用。
public class A {
public static B {
}
public static void main(String... args) {
// 嵌套类不需要对外部类对象的引用
A.B b = new A.B();
}
}
- 内部类与向上转型,例子如下
public class A {
// 通过扩展接口
private class AA implements FInterface {
@Override
public void print() {
System.out.println("hehe");
}
}
// 向上转型
public FInterface getF() {
return new AA();
}
}
public class B {
public static void main(Stirng... args) {
A a = new A();
// AA是内部私有类,除了AA本身和外围类,其他类均无法访问
// 这时向上转型为接口就能调用AA的方法
FInterface f = a.getF();
// 控制台将会输出"hehe"
f.print();
/*
事实上,f也不能向下转型,通过这样的方式
隐藏实现的细节。
*/
}
}
上面举的例子都是内部类在外围类中的,实际上内部类还包括局部内部类、匿名内部类、嵌套类。
局部内部类
public class A {
private static int i = 1;
public void methodA() {
// 局部内部类,不能添加作用域
// 因为局部内部类只能在该局部方法中存在
// 换句话说,除了methodA方法,其他地方不存在该内部类
class AAA {
private int i = A.i;
}
AAA a = new AAA();
}
}
匿名内部类
public class A {
private int i = 1;
public void methodA(final int i) {
A a = new A() {
// 在匿名内部类中,想要访问外部定义的对象
// 需要添加final使之变成常量
int l = i;
};
}
}
嵌套类
如果不需要内部类对象与其外部类对象之间有联系,那么可以将内部类声明为static。这通常称为嵌套类。
特点
- 要创建嵌套类的对象,不需要其外围类的对象
- 不能从嵌套类的对象中访问非静态的外围类对象
- 普通内部类的字段和方法只能放在类的外部层次上,所以普通的内部类不能有static数据和字段,但是嵌套类可以包含这些东西
public class A {
private int a = 1;
private static class AA {
// 嵌套类可以定义静态属性
public static int i = 1;
// 这样做编译器会报错
// 不能从嵌套类的对象中访问非静态的外围类对象
public static int i = a;
}
public static void main(String... args) {
// 创建嵌套类不需要其外围类的对象
A.AA aa = new A.AA();
System.out.println(aa.i);
}
}
接口内部的类
嵌套类可以作为接口的一个部分。在接口中的任何类都自动为public和static的,只是将嵌套类置于接口的命名空间中,这并不违反接口的规则。如果你想要创建某些公共代码,使得他们可以被某个接口的所有不同实现所共有,那么在接口中使用嵌套类会显得方便。(有点像抽象类)
interface AInterface {
void print();
// 自动为public、static
class A implements AInterface {
@Override
public void print() {
System.out.println("heheda");
}
}
}
为什么需要内部类
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的实现),对于内部类都没有影响。
- 如果没有内部类提供的可以继承多个具体或抽象的类的实现,一些设计和编程问题将很难解决。
- 还有Json一些复杂数据转换成java对象也将变得不简单??
闭包(closure)
闭包是一个可调用的对象,它记录了来自于创建它的作用域的信息。 因为内部类能够访问外围类的任何属性方法,所以用内部类来实现闭包的功能是非常棒的。
内部类标识符
由于每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息(此信息产生一个“meta-lcass”,叫做Class对象),内部类也必须创建一个.class文件已包含他们的Class对象信息。 这些类文件的命名有规范:外围类的名字加上"$",再加上内部类的名字,如果是匿名的,编译器会简单产生一个数字作为标识符。