我们都知道java的类能够由public、default(缺省、不写)来修饰,分别表示的含义是同意公开訪问以及仅仅同意包内其他类訪问,而同一包内的类一般是为完毕同一个功能而协作。
除此之外,我们还会遇到一些类,它们仅仅是其他某个类的实现或组成的一部分,它们不应该被独立的创建出来。当它们创建的时候须要跟"宿体"连在一块,这就是内部类。就好像人类的心脏。你没法单独的new一个出来,它仅仅能依赖于人体而存活(这本来就是它存在的目的),至少现代医学做不到离体存活。现代医学能做的仅仅是把一个心脏取出来,立刻换到另外一个人身上。
内部类
内部类一般是宿主类实现的一部分或者是宿主对外提供的一种工具。
假设内部类仅仅是为宿主的实现服务,能够将内部类修饰为private,这样也就限制了外部类的訪问。而作为工具的内部类。一般訪问修饰符为public或default。
为了使用方便。java同意在内部类中直接訪问宿主类的成员(这也就决定你没法在宿主类外单独直接new一个内部类对象)。
以下是一个简易的用内部类实现容器迭代器的样例。
interface Selector { boolean end(); Object current(); void next();}public class Sequence { private Object[] items; private int next = 0; public Sequence(int size) { items = new Object[size]; } public void add(Object x) { if(next < items.length) { items[next++] = x; } } 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.println(selector.current()); selector.next(); } }}
.this和.new
因为内部类能够直接訪问宿主类的成员,所以它自身就拥有对宿主类的引用。假设你须要生成对外部类对象的引用。能够使用外部类的名字后面紧跟圆点和this。
public class DotThis { void f() {System.out.println("DotThis.f()");} public class Inner{ public DotThis outer() { return DotThis.this; }}public Inner inner() {return new Inner(); }; public static void main(String[] args) { DotThis dt = new DotThis(); DotThis.Inner dti = dt.inner(); dti.outer().f(); }}
有时你须要创建其某个内部类的对象,而非通过成员方法返回,在这样的情况下必须直接使用某个外部类的对象来创建该内部类的对象。使用.new语法。
public class DotNew { public class Inner{}; public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner(); }}
匿名内部类
匿名内部类与内部类最大差异在于,因为它是匿名的,你没法在任何位置,任意的去new这样一个对象。所以它经常使用于仅仅使用一次的类或者说仅仅在某个地方(方法、对象成员)能new的类,从这个角度来看它是类訪问最严格的控制:仅仅在某个位置能够创建类。而内部类至少能在宿主类中任意创建。
匿名内部类支持直接訪问所在方法的局部引用,因为引用和基本类型出了方法就无法訪问到了,所以要求在匿名内部类中訪问的在方法中的外部对象必须是final的。可是。匿名内部类訪问的类成员对象不必是final的。
由于匿名类中不可能有命名构造器(由于它根本没有名字),但通过初始化代码段,就行达到为匿名内部类创建一个构造器的效果。
abstract class Base{ public Base(int i) { System.out.println("Base constructor, i = " + i); } public abstract void f();}public class AnonymousConstructor { private static int w = 7; public static Base getBase(int i,final int j) { return new Base(i) { { System.out.println("Inside instance initial"); } private int pj = j; private int pw = w; public void f() { System.out.println("In anonymous f()"); } }; } public static void main(String[] args) { Base base = AnonymousConstructor.getBase(47, 39); base.f(); }}
嵌套类
嵌套类也是定义在一个类中的类。只是它和宿主类除此之外并没有特别直接的关系。在使用形式上。一个内部类用static来改动就成为了一个嵌套类。在嵌套类中你不能直接訪问宿主类中的非静态成员。嵌套类在实际工作中,使用非常少,既然它跟一个普通类对宿主类的訪问权限相似又何必放在一个宿主类中定义呢?而通常嵌套类又同意外部类直接定义该嵌套类的对象。这和普通类也就更相似了。