可以将一个类放在另一个类的内部定义,这就是内部类。内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可见性。内部类看起来就像是一种代码隐藏机制:将类置于其他类的内部。但是内部类远不止如此,它了解外围类,并与之通信。
下面这个例子我们可以看出SequenceSelector 是一个内部类,他实现了Selector 接口,并实现了其中的方法,我们发现end(),current(),和 next() 方法都使用到了items,这是一个引用,它并不是SequenceSelector 的一部分,而是外围类Sequence 类的一个private 属性。然而内部类却可以访问其外部类的方法和字段,就像是拥有其外围类的属性似的,这样有极大的方便。因此外部类自动拥有对其外部类的所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类的对象时,此内部类对象必定会秘密的捕捉一个指向那个外部类的对象的引用。然后,当你访问外部类的成员时,就是那个引用来选择外部类的成员。
public class Sequence {
private Object [] items;
private int next = 0;
public Sequence(int size){
items = new Object[size];
}
public void add(Object o){
if(next < items.length){
items[next++] = o;
}
}
private class SequenceSelector implements Selector{
private int i = 0;
@Override
public boolean end() {
return i == items.length;
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if(i < items.length){
i++;
}
}
}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args) {
Sequence sequence = new Sequence(10);
for(int i = 0 ; i < 10; i++)
sequence.add(Integer.toString(i));
Selector selector = sequence.selector();
while (!selector.end()){
System.out.print(selector.current() +" ") ;
selector.next();
}
}
}
interface Selector{
boolean end();
Object current();
void next();
}
输出
0 1 2 3 4 5 6 7 8 9
内部类返回外部类的引用:
当你想要在任意位置创建某个内部类的对象,就需要具体指明这个对象的类型(就像下面这样): OuterClassName.InnerClassName。如果你想要生成外部类的对象的引用,可以使用外部类的名字后紧跟圆点和this。这样产生的引用具有正确的类型,这一点在编译器就被知晓并接受检查,因此没有任何运行时的开销。
public class Outer {
void f(){
System.out.println("Outer class f()......");
}
class Inner{
public Outer outer(){
return Outer.this;
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.inner();
inner.outer().f();
}
}
输出
Outer class f()……
外部类创建内部类对象:
如果你想要告知某个对象,去创建某个内部类对象,要想实现这个目的你就必须要使用外部类的对象去创建该内部类的对象,需要用到.new 语法。
public class Outer {
class Inner{
public void f(){
System.out.println("Inner class f().....");
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.f();
}
}
输出
Inner class f()…..
在方法和作用域的内部类:
我们可以在一个方法里面或者在任意的作用域定义内部类,这么做的理由有两个:一个是如果你实现了某类型的接口,你可以创建并返回对其的引用;另一个就是有时候你需要解决一个复杂的问题,想要创建一个类来辅助你的解决方案,但是又不希望这个类是公用的。下面就是一个在方法内定义的一个内部类,返回了一个实现Inner 接口的对象的引用。作用域内定义内部类同理。
public class Outer {
public Inner inner(){
class InnerImpl implements Inner{ }
return new InnerImpl();
}
public static void main(String[] args) {
Inner inner = new Outer().inner();
}
}
interface Inner{}
内部类有一个最吸引人的地方:每一个类都可以独自的继承一个实现,所以无论外围类是否已经继承了某个实现,对于内部类都没有任何影响,即内部类有效地实现了“多重继承”。
下一篇: Java 匿名内部类
参考书籍:
《Java 编程思想》Bruce Eckel 著 陈昊鹏 译