将一个类的定义放在另一个类的定义的内部,这就是内部类。
1. 普通内部类
public class Example {
int index = 0;
public void increaseIndex() {
index++;
}
public class InnerClass {
private int getIndex() {
increaseIndex();
return index;
}
}
public static void main(String[] args) {
Example example = new Example();
InnerClass innerClass = example.new InnerClass();
innerClass.getIndex();
}
}
先来看这个例子,innerClass类的定义在example类里面,内部类可以访问外部类的属性和方法,比如代码中内部类的getIndex方法中可以直接调用外部类的increaseIndex方法和index属性(第8和第9行)。为什么能这样呢?当某个外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外部类对象的引用。
但如果想创建内部类的实例,必须先创建外部类,再通过外部类实例的.new方法创建内部类。
2. 局部内部类和匿名内部类
如果在一个代码块或者一个函数中创建内部类,就是局部内部类。
public class Example {
interface Destination {
String location();
}
public Destination makeInner() {
class MDestination implements Destination {
private String dest;
MDestination(String str) {
this.dest = str;
}
@Override public String location() {
return dest;
}
}
return new MDestination("1");
}
}
内部类MDestination的定义在方法makeInner()的内部,那么这个类就只能在方法内被初始化,在方法外的任何地方都不能使用。这类似于方法的局部变量。
还有另一种更简单的写法,匿名内部类:
public class Example {
interface Destination {
String location();
}
public Destination makeInner() {
return new Destination() {
@Override public String location() {
return "1";
}
};
}
}
makeInner方法里直接返回了new Detination(){},返回的类没有定义名称,所以称作匿名内部类。匿名内部类没有显式的名称,其实编译器在编译的时候给了一个默认的名称。
方法的内部类,一般情况下我们都不需要内部类的名称,但有些时候还是需要的:
1. 需要一个已命名的构造器,或者需要重载构造器。(匿名内部类没有名称,所以没有构造器)
2. 需要不止一个该内部类的对象。
3. 静态内部类(嵌套类)
如果不需要内部类对象与其外部类进行联系,可以将内部类声明为static。这通常称为嵌套类。
public class Example {
interface Destination {
String location();
}
public int index = 0;
public int getIndex() {
return index;
}
public static class MDestination implements Destination {
public String dest;
public MDestination(String str) {
this.dest = str;
}
@Override public String location() {
//getIndex(); error:can not access
//index++; error:can not access
return dest;
}
}
public static void main(String[] args) {
MDestination destination = new MDestination("peking");
}
}
与普通内部类不同的是,静态内部类不再能访问外部类的普通方法和普通变量(第20和第21行)。但如果外部类包含静态方法或者是静态变量,静态内部类中依然是可以访问的。
如果需要创建静态内部类的对象,不再需要先创建外部类的对象。
4. 为什么需要内部类?
外部类可以继承一个子类外加N个接口,为什么还需要内部类呢?因为Java里是单继承体系,内部类是为了解决多重继承的问题,有了内部类,就可以创建N个内部类分别实现不同的子类,去做不同的事情。而且Java语言的内部类和接口的实现方式,要比c++的直接多重继承要好。
public static abstract class BaseClass1 {
}
public abstract class BaseClass2 {
}
public class aaa extends BaseClass1 {
public class bbb extends BaseClass2 {
}
}
aaa类中继承自BaseClass1,需要做一些事情,但其中有些事情需要BaseClass2中的方法来做。那么我们就可以创建一个内部类bbb继承自BaseClass2,在内部类中做这部分事情,做好后再把结果回调给外部类。
总结:
内部类的实现看起来很诡异,一开始的感觉很奇怪。但作用却是很大的,像类的多重继承只能通过内部类来解决。