InnerClass 备忘录
参考资料:
java核心技术
http://www.javabeat.net/tips/124-inner-classes-in-java.html innerclass 示例
http://download.oracle.com/javase/tutorial/java/javaOO/innerclasses.html 内部迭代器实现
http://java.sun.com/developer/Books/certification/certbook.pdf 官方InnerClass PDF
InnerClass:
普通内部类:
1 编译器将编译为: OuterClass$InnerClass.class文件,并在这个编译后的Class中加入一个构造方法并添加一个final的OuterClass引用;
InnerClass(OuterClass){
...
}
final OuterClass out;
2 编译器在OuterClass中添加关于私有域的access方法: static <private_prperty_type> access$0(OuterClass),使得内部类能够通过此方法访问到OuterClass的私有域.
3 确实存在安全的一些问题在access方法上;
4 若权限足够,使用下面的方式创建内部类;
Outer outer=new Outer();
out.new Inner();
5 内部类可继承其他类和实现相关接口, 这部分可以参考Java JDK 集合中的ListIter这些内部迭代器的实现;
6 内部类可使用static final ,不能缺少final;
下面给出一个实例代码类说明外部资源[并非指外部类]如何较好的使用一个内部类:
class ToplevelClass {
private String msg = "Shine the inner light.";
//负责创建内部类
public NonStaticInnerClass makeInstance() {
return new NonStaticInnerClass();
}
//内部类
public class NonStaticInnerClass {
// private static int staticVar; // (6) Not OK.
private String string;
public NonStaticInnerClass() { string = msg; }
public void printMsg() { System.out.println(string); }
}
}
//外部资源访问
public class Client {
public static void main(String args[]) {
//具体内部类的创建
ToplevelClass topRef = new ToplevelClass();
ToplevelClass.NonStaticInnerClass innerRef1 = topRef.makeInstance();
innerRef1.printMsg();
// ToplevelClass.NonStaticInnerClass innerRef2 =
// new ToplevelClass.NonStaticInnerClass(); // (15) Not OK.
ToplevelClass.NonStaticInnerClass innerRef3 = topRef.new NonStaticInnerClass();
}
}
如果不用上面的实例来创建内部类,也可以使用下面的方式:
TLClassA a = new TLClassA("1");
TLClassA.InnerB b = a.new InnerB("1");
TLClassA.InnerB.InnerC c = b.new InnerC("1");
代码说明: TLClassA 中有一个内部类InnerB,而InnerB中又存在一个内部类InnerC.
上述的两个示例表明在获取内部类的实例时候,要通过外部类的实例创建.
下面是关于内部类继承的例子:
class B {
protected double x = 2.17;
}
class A { // Top-level Class
private double x = 3.14;
class C extends B { // Non-static inner Class
// private double w = x; // Compile time error
private double y = this.x; // x from superclass
private double z = A.this.x; // x from enclosing class
public void printX() {
System.out.println("this.x: " + y);
System.out.println("A.this.x: " + z);
}
}
}
//客户端调用;
public class Client4 { // (7)
public static void main(String args[]) {
A.C ref = new A().new C();
ref.printX();
}
}
局部内部类:
1 在使用了普通内部类的情况下, 如果这个普通内部类的使用仅仅是在外部类的一个方法中使用一次, 并且代码比较简洁,可以考虑使局部内部类;
2 局部内部类不能使用public private 作为修饰;
3 局部内部类的隐蔽性要好于统统内部类;
4 局部内部类不仅仅能够访问外部类,并且能够访问方法的局部变量, 但是这些局部变量必须是final的.原因是局部内部类的周期要大于这个局部变量;在这种时候,编译器将在内部类的构造器中传入局部变量, 并在内部类添加一个fiannal <function_var_type> propertyName; 有些时候, 当局部的变量需要更新的时候,不能使用final字段来限制基本类型,可以开去使用一个fnnal的array : final int[1] inMutableValue = new int[1]; 这样在内部类就能使用inMutableValue[1]了, 同时,改变其值就使用inMutableVale[1]=...,final只是限定了应用不可改变,但是并不限定了引用的内容不能改变,这个就相当于在并发中使用final StringBuffer为什么也不是很安全的原因.
匿名内部类:
1 匿名内部类是在局部内部类的基础上发现了只需要这个类的一个对象,就不用命名. 类似的有:
Action listenner = new ActionListener(){
public void actionPerformed(ActionEvent event){
....
}
}
静态内部类:
1 有时候只是希望把内部类隐藏,并不是想要内部类能够访问外部类对象,则可以使用static 内部类. 一般的, 这种内部类的结构比较简单,方法的代码都比较简洁. 这方面的例子,可以参考JDK LinkedList 中的私有静态内部类Entry<E>的使用.
2 一般的,使用staitc 内部类的时候更多是用private 和 default的访问修饰.
3 可以使用OuterClass.InnerClass inner = OuterClass.factoryMethod();方式来创建一个能够访问到的静态内部类;
下是JDK LinkedList中的使用静态类的源代码
【友情提示 : 注意属性的控制权限和内部类本身的控制权限】
private static class Entry<E> { //私有的内部静态类 E element; Entry<E> next; Entry<E> previous; // 包默认 Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } } 使用如下: private Entry<E> addBefore(E e, Entry<E> entry) { Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; size++; modCount++; return newEntry; } 上述的代码能够达到简化代码量以及提高可读性的目的.