可以将一个类的定义放在另一个类的定义内部,这就是内部类。(摘自Thinking in Java)
内部类(Inner Class)与外部类的联系
内部类不仅仅是一种名字隐藏和组织代码的模式,它可以能访问外部类的所有成员,可而且不需要任何特殊条件。可以通过 "外部类.this" 获得外部类的引用。
外部类也可以通过.new的方式去创建内部类的对象。在拥有外部类对象之前是不可能创建内部类对象的,因为内部类对象会暗暗地连接到创建它的外部类对象上。
public class Outer { int attr = 1; class Inner{ public void func(){ System.out.println(Outer.this.attr); } } public static void main(String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); Outer.Inner inner2 = new Outer.Inner(); //这样是不行的 } }
方法和作用域中的内部类(Inner class in methods and scopes)
有时候你可以定义在一个方法内部或者任何作用域中定义一个内部类,通常这样做的目的有两个:
(1)内部类实现了某类型的接口,于是可以创建并返回对其的引用。
interface IBehavior{ void say(String sth); } public class Outer { public IBehavior showBehavior(){ class Dog implements IBehavior{ @Override public void say(String sth) { System.out.println("wang!wang! " + sth); } } return new Dog(); } public static void main(String[] args) { Outer outer = new Outer(); IBehavior behavior = outer.showBehavior(); behavior.say("hello"); } }
(2)你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不想对外暴露它。
public class Outer2 { public double calculate(double num){ if(num > 0){ class InnerCal{ public double calculate(){ //复杂的计算 //内部方法的调用 return 0; } } return new InnerCal().calculate(); } return -1; } }
匿名内部类
匿名内部类做法是创建一个继承自XXX类型(具体类、接口、抽象类都可以)的匿名类的对象。通过new表达式返回的引用被自动向上转型为对XXX类型的引用。
abstract class Animal{ private String name; public Animal(String name){ this.name = name; } abstract void say(); } public class Outer3 { public Animal makeAnimal(final String name){ return new Animal(name) { private int cost; { //实例初始化 cost = 200; } @Override public void say() { System.out.println(name + " wang wang!"); } }; } }
(1)如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用时final的。如上实例。如果你忘记了,会得到一个编译时错误消息。
(2)匿名内部类是没有命名构造器的,怎么能做些构造器的行为呢,实例初始化能够达到这种效果。如上实例。
(3)匿名内部类的限制:匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备。而且如果是实现接口,也只能实现一个接口。
嵌套类(Nested Class)
如果不需要内部类对象与其外部类对象之间有联系,那么可以讲内部类声明为static,这个类就称作嵌套类,或者静态嵌套类。嵌套类有如下特点:
(1)嵌套类对象内部没有外部类对象引用
(2)不能从嵌套类的对象中访问非静态的外围类对象。
(3)普通内部类不能有static数据或static字段,也不能包含嵌套类,但是嵌套类可以包含。
另外我们知道,正常情况下,不能再接口内部放置任何代码,但嵌套类可以作为接口的一部分。你放到接口的任何类都自动是public和static的。一般这样做的目的是,如果你想要创建某些公共的代码,使得它们可以被某个接口的所有不同实现所共有,那么使用接口内部的嵌套类会显得很方便。
为什么需要内部类
通过学习内部类的特性,我们可以知道每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类其实是“多重继承”的一种补充。因为内部类允许继承多个非接口类型(类和抽象类),因此对于类或抽象类只能使用内部类才能实现多重继承。
另外除了“多重继承”的特点,内部类还有一些其他特性。
(1)内部类可以有多个实例,每个实例都有自己的状态信息,并且与外围类对象的信息相互独立。
(2)创建内部类对象的时刻并不依赖与外围类对象的创建(如嵌套类的创建)。
(3)内部类不是一种“is-a”的关系,它是一个独立的实体。
另外我自己的一点理解是,对于一个类,它有属性和方法,有属于对象的,有属于类的(static类型)。普通内部类扩展了对象属性和方法的使用,嵌套类扩展了类的属性和方法的使用。当然有些理解狭窄,但对于内部类的学习理解有些帮助。