起源:JDK1.1开始,新增加了内部类的特性。现在很多设计模式中都会用到这一特性,用好内部类,能够让你更加灵活的设计你的系统。
一、什么是内部类?
顾名思义,内部类是定义在另一个类中的类,主要特性有两点:
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
- 内部类可以对同一个包的其他类隐藏
内部类共有以下四种:
1. 普通内部类(成员内部类):常规内部类没有用static修饰且定义在在外部类类体中,代码位置和成员变量同级,也可以称为成员内部类;如下列代码中的InnerClass类。
public class InnerClassTest {
class InnerClass {
}
}
2. 静态内部类:和成员内部类类似,作为类中的成员,添加了static修饰,并且拥有static的特性。
public class InnerClassTest {
static class StaticInnerClass {
}
}
3. 局部内部类:在方法体或语句块(包括方法、构造方法、局部块或静态初始化块)内部定义的类成为局部内部类;本文不做扩展。
void test() {
// 我是一个局部内部类,不能加任何访问修饰符,因为我只对局部块有效
class Person {
private String home = "China";
public String getHome() {
return home;
}
}
System.out.println(new Person().getHome());
}
局部内部类不能加任何访问修饰符,因为它只对局部块有效。
4. 匿名内部类:定义类的最终目的是创建一个类的实例,在定义类的同时直接创建类的对象,用于单次使用,因此没有对类进行命名,所以叫匿名内部类;本文不做扩展。
public static void main(String[] args) {
// 这是一个匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
// TODO...
}
};
}
二、非静态内部类的特性解析:
- 通过内部类实例的创建方式可以了解到,非静态内部类必须寄生在外部类的对象中。
public static void main(String[] args) {
// 在外部无法直接创建内部类的对象
// new OuterClass.InnerClass();
// 需要通过外部类的对象来创建内部类的对象
OuterClass outer = new OuterClass();
OuterClass.InnerClass innerClass = outer.new InnerClass();
}
- 非静态内部类可以直接访问外部类的实例变量、类变量、实例方法、类方法,包括私有化的。
public class OuterClass {
private String name = "OuterClass";
private String status = "outer";
class InnerClass {
private String name = "InnerClass";
public void test() {
System.out.println(name);
System.out.println(status);
}
}
}
test方法运行结果:
name = InnerClass
status = outer
内部类是如何访问到外部类的成员的?
非静态内部类对象总有一个隐式引用,指向了创建它的外部类对象,如图
3. 非静态内部类的特殊语法
如上面的代码示例,内部类可以直接调用外部类的成员,但是如果内部类和外部类拥有相同名称的成员时应该怎么区分呢?
- 直接用成员名称:先判断内部类自身是否有该成员,如果没有,再使用外部类的该成员
- this.成员名称:使用内部类自身的成员
- OuterClass.this.成员名称:使用外部类的成员
public class OuterClass {
private String name = "OuterClass";
private String status = "outer";
class InnerClass {
private String name = "InnerClass";
public void test() {
System.out.println(name);
System.out.println(this.name);
System.out.println(OuterClass.this.name);
System.out.println(status);
}
}
}
test方法运行结果:
name = InnerClass
this.name = InnerClass
OuterClass.this.name = OuterClass
status = outer
三、静态内部类
用static修饰后的成员内部类,则为静态内部类,这个类属于外部类的本身,但是不属于外部类的任何对象
static内部类是内部类中一个比较特殊的情况,Java文档中是这样描述static内部类的:一旦内部类使用static 修饰,那么此时这个内部类就升级为顶级类。
其拥有一些不同的特性。如:
- 静态内部类不能访问外部类的实例成员,只能访问外部类的类成员
- 外部类可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象访问其实例成员。
public class OuterClass {
private static String name = "OuterClass";
private String status = "outer";
static class StaticInnerClass{
public static String status = "static";
public String name = "StaticInnerClass";
void innerTest(){
// 静态内部类无法访问外部类的非静态成员
// System.out.println(OuterClass.status);
System.out.println(OuterClass.name);
}
}
void outerTest(){
// 外部类无法通过类名来调用静态内部类的非静态成员,可以通过实例来访问
// System.out.println(StaticInnerClass.name);
System.out.println(new StaticInnerClass().name);
System.out.println(StaticInnerClass.status);
}
}
- 静态内部类的创建
public static void main(String[] args) {
OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();
}
以上可以看出,相比较于非静态内部类对外部类的依赖关系,静态内部类更像是一个单独的、和外部类并行的类,它可以在外部直接通过类名创建对象(不过要加上外部类类名作为前缀),可以拥有自己的静态和非静态的成员
四、内部接口
与内部类不同的是,所有内部接口默认为静态的,也就是说,普通类是可以直接实现内部接口的。
public class OuterClass {
interface InnerInterface{}
}
class Test implements OuterClass.InnerInterface {
}