随笔-204  评论-149  文章-0  trackbacks-0
重点理解Java引入内部类的原因以及好处
内部类能让你再逻辑上将相互从属的类组织起来,并且在类的内部控制访问权限。但是切记,内部类和合成时截然不同的,这一点非常重要。

几个有代表性的代码块
接口可以嵌套在类或其它接口中
接口的嵌套

返回内部类引用

内部类在隐藏实现方面的作用
内部类隐藏机制


匿名内部类的几种使用形式
  1. A class defined within a method 在方法的内部定义一个类
  2. A class defined within a scope inside a method 在方法的某个作用域里定义一个类
  3. An anonymous class implementing an interface 一个实现了某个接口的匿名类
  4. An anonymous class extending a class that has a nondefault constructor 一个继承了“某个有着非默认构造函数”的类匿名类
  5. An anonymous class that performs field initialization一个进行数据成员初始化的匿名类
  6. An anonymous class that performs construction using instance initialization (anonymous inner classes cannot have constructors)一个通过实例初始化(匿名内部类不能有构造函数)来进行构建的匿名类
某个有着非默认构造函

对数据成员进行初始化的匿名类

实例初始化来构建匿名内部类
//: c08:AnonymousConstructor.java
// Creating a constructor for an anonymous inner class.
import com.bruceeckel.simpletest.*;

abstract class Base {
  
public Base(int i) {
    System.out.println("Base constructor, i = " + i);

  }

  
public abstract void f();
}


public class AnonymousConstructor {
  
private static Test monitor = new Test();
  
public static Base getBase(int i) {
    
return new Base(i) {
      {
        System.out.println("Inside instance initializer");
      }

      
public void f() {
        System.out.println(
"In anonymous f()");
      }

    }
;
  }

  
public static void main(String[] args) {
    Base base 
= getBase(47);
    base.f();
    monitor.expect(
new String[] {
      "Base constructor, i = 47",
      "Inside instance initializer",
      "In anonymous f()"
    }
);
  }

}
 ///:~

In this case, the variable i did not have to be final. While i is passed to the base constructor of the anonymous class, it is never directly used inside the anonymous class. 




实例初始化来构建的匿名内部类


内部类与宿主类的关系
上面讲的内部类还只是一种隐藏名字和组织代码的方式,但是内部类还有一种用法。如果你创建了一个内部类,那么这个内部类的对象,就与创建它的“宿主类的对象(enclosing object)”产生了某种联系,这样它就能访问宿主类对象的成员了---不需要任何特别的授权。此外,内部类还能访问宿主类的所有元素。
内部类访问宿主类的成员

内部类里肯定会有一个指向“要负责创建它的”宿主类对象的reference。这样,当你引用宿主类的成员的时候,就会使用那儿(隐蔽的)reference来选取成员。编译器会为你打理着一切,但是你还是应该知道,内部类对象的创建时与宿主类对象有关的。创建内部类对象的前提就是要获得宿主类对象的reference,如果编译器得不到这个引用,它就会报错,绝对大多数情况下,这个过程无需程序员的干预。最好的方式就是通过在宿主类里的非static方法里定一个getInnerClassName(){new InnerClassName();}

在宿主类static方法及宿主类外定义内部类的对象



Java嵌套类(static 内部类)和普通内部类的区别

如果你不需要这种“内部类对象和宿主类对象之间的”联系,那么你可以吧内部类定义为static的,这通常被称作“嵌套类nested class"。要想理解static用于内部类时的意思,你就必须记住,普通的内部类对象都默认保存“它的宿主类对象,也就是创建它的那个对象的reference。但是将内部类声明为static的时候,情况就不是这样了。嵌套类的意思是:
1,无需宿主类的对象就能创建嵌套类的对象。
2,不能在嵌套类的对象里面访问非static的宿主类对象

此外,嵌套类同普通的内部类还有一点不同。普通内部类的成员数据和方法只能到类的外围这一层,因此普通的内部类不能有static数据,static数据成员或嵌套类。但是这些东西static 嵌套类里都可以有。

但是如果创建的是嵌套类static innerclass的对象的话,就不需要宿主类对象的reference了


局部内部类
前面提到过,可以在代码块里创建内部类,典型的方式是在一个方法体的里面创建,局部内部类不能有访问说明符,因为它不是外围类的一部分;但是它可以访问当前代码块内的常量final定义的.以及宿主类的所有成员。
局部内部类


继承内部类
如下,可以看到InheritInner继承的只是内部类,而不是它的宿主类。但是等到要创建构造函数的时候,默认的构造函数玩不转了,你必须传给他宿主类对象的reference。此外,你还必须在构造函数里面使用这种语法 enclosingClassReference.super();
继承内部类


为什么要使用内部类
在一定程度上解决Java中多重继承的问题
内部类解决多重继承问题

即使无需解决”多重实现的继承multiple implementation inheritance)"这类问题,那么即使没有内部类,你也完全可以解决问题。但是有了内部类,你就得到如下的附加特性:

1,内部类可以有多个实例,而每个又都可以有它自己的,与宿主类对象无关的状态信息
2,一个宿主类里可以放上好几个内部类,它们可以用各自不同的方式来实现同一个interface或继承同一个类。举例来说,要是Sequence.java没有使用内部类,那么牛就只能说"Sequence是一个Selector”,于是每个Sequence里面就只能邮购一个Selector。但是现在,你可以很方便地再定义一个getRSelector()方法,让它返回一个会倒过来访问这个序列的Selector。显然只有内部类才能提供这种灵活性。
3,内部类对象创建的时机与宿主类对象的创建没有什么关系。
4,内部类不存在什么让人头晕的“是”关系;他是一个独立的实体



闭包和回调
闭包和回调
这段程序还进一步揭示了“让宿主类去实现接口”和“交给内部类去做”之间的区别
Callee2继承了MyIncrement,而MyIncrement已经包括了一个它自己的increment(),而且这个方法的功能同Incrementable接口所定义的毫无相关。所以Callee2继承MyIncrement之后,就不能靠实现Incrementable接口来覆写increment()了,这就逼着你只能使用内部类来提供一个独立的实现了。

注意一下创建匿名内部类的不一定一定是Interface和abstract class,具体的类也可以,比如new Thread(){run(){}}.start();
posted on 2009-05-24 22:52 Frank_Fang 阅读(1013) 评论(0)  编辑  收藏 所属分类: Java编程