1.内部类的继承
因为内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,必须使用特殊的语法来明确说清它们之间的关联:
public class WithInner {
class Inner{
}
}public class IntheritInner extends WithInner.Inner{
IntheritInner(WithInner wi){
wi.super();
}
public static void main(String[] args) {
WithInner withInner = new WithInner();
IntheritInner ii = new IntheritInner(withInner);
}
}
可以看到,IntheritInner只继承自内部类,而不是外围类。但是当要生成一个构造器时,默认的构造器并不算好,而且不能只是传递一个指向外围类对象的引用。此外,必须在构造器内使用如下语法:enclosingClassReference.super();这样才提供了必要的引用,才不会报错。
2.内部类可以为覆盖吗
创建一个内部类,然后继承其外围类并重新定义此内部类,也就是“覆盖”内部类,但是内部类就好像是外围类的一个方法,其实并不起什么作用。例子如下:
public class Egg {
private Yolk y;
protected class Yolk{
public Yolk() {
System.out.println("Egg.Yolk()");
}
}
public Egg() {
System.out.println("new Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk() {
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
输出:new Egg()
Egg.Yolk()
这个例子说明,当继承了某个外围类的时候,内部类并没有发生什么特别神器的变化。这两个内部类时完全独立的两个实体,各自在自己的命名空间内。
3.局部内部类
可以在代码块里创建内部类,典型的方式是在一个方法体里面创建内部类。局部内部类不能有访问说明符,因为它不是外围类的一部分;但是它可以访问当前代码块内的常量,以及此外围类的所有成员。下面的例子对局部内部类与匿名内部类的创建进行了比较,例子如下:
public interface Counter {
int next();
}
public class LocalInnerClass {
private int count = 0;
Counter getCounter(final String name){
class LocalCounter implements Counter{
public LocalCounter(){
System.out.println("LocalCounter()");
}
@Override
public int next() {
System.out.println(name);
return count++;
}
}
return new LocalCounter();
}
Counter getCounter2(final String name){
return new Counter() {
{
System.out.println("Counter()");
}
@Override
public int next() {
System.out.println(name);
return count++;
}
};
}
public static void main(String[] args) {
LocalInnerClass lic = new LocalInnerClass();
Counter c1 = lic.getCounter("Local inner");
Counter c2 = lic.getCounter2("Anonymous inner");
for (int i = 0; i < 5; i++) {
System.out.println(c1.next());
}
for (int i = 0; i < 5; i++) {
System.out.println(c2.next());
}
}
}
Counter 返回的是系列中的下一个值。我们分别使用局部内部类和匿名内部类实现了这个功能,它们具有相同的行为和能力。既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类而不是匿名内部类呢?唯一的理由是,我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。所以使用局部内部类而不使用匿名内部类的另一个理由就是,需要不止一个该内部类的对象。
4.为什么加上final后的局部变量就可以在内部类中使用了?
因为加上final后,编译器是这样处理内部类的:如果这个外部局部变量是常量,则在内部类代码中直接用这个常量;如果是类的实例,则编译器将产生一个内部类的构造参数,将这个final变量传到内部类里,这样即使外部局部变量无效了,还可以使用,所以调用的实际是自己的属性而不是外部类方法的参数或局部变量。这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。