Java内部类与相关的设计模式(一)

内部类是定义在类的内部的类,是从JDK1.1开始引入的。在最初的版本里,是没有内部类的。由于在JDK1.1之后引入了消息机制,需要有一个类可以访问另一个类的私有成员,于是引入了内部类,并完善了内部类的体系,来实现目标。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。我在这里试图比较详细的讲解一下。      先看这个例子:

abstract class Contents {
  abstract public int value();
}

interface Destination {
   String readLabel();
}

public class Parcel3 {
  private class PContents extends Contents {
    private int i = 11;
    public int value() { return i; }
  }
 
  protected class PDestination implements Destination {
    private String label;
    private PDestination(String whereTo) {
      label = whereTo;
    }
    public String readLabel() { return label; }
  }

  public Destination dest(String s) {
    return new PDestination(s);
 }
  public Contents cont() {
    return new PContents();
 }
}

class Test {
  public static void main(String[] args) {
    Parcel3 p = new Parcel3();
    Contents c = p.cont();
    Destination d = p.dest(”Tanzania”);
// Illegal — cant access private class:
//Parcel3.PContents a = p.new PContents();这是另一种在外部类得到内部类对象的语法
  }
} ///:~

     在这个例子中,类PContents和PDestination被定义在类Parcel3里,并分别有private和protected来控制访问级别。在类Parcel3里,类PContents和PDestination和方法dest()一样,都是类Parcel3的成员,也就具有一样的属性,因此和成员函数一样,这两个成员类(也就是内部类的函数)也能访问外部类的私有变量;另外,还能在内部类的声明的前面加上public、protected、private等修饰词,来实现对内部类的访问控制;从这个思路上走,如果在内部类的声明前加上static,就可以把原来属于外部类对象的内部类变成属于外部类的内部类,变成类成员,这就改变了类的初始化顺序。

     以上说明了关于内部类的基本知识,再回到上面的程序,两个内部类分别实现了两个接口。在后面的main()方法中,直接使用了Contents c和Destination d进行操作,你甚至连两个内部类的名字都没有看见!在Contents c = p.cont();和Destination d = p.dest(”Tanzania”);语句中,表面上使用的是外部的Contents和Destination的对象来操作,但其实操作的是自己定义的内部类的对象,但别人根本不知道调用的是另一个类的对象,但结果却一样。使用这种方法的理论依据是子类的对象总是可以被父类所调用(Upcasting)。使用这种方法有两个理由:
1.我们准备实现某种形式的interface,使自己能创建和返回一个句柄。
2.要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序,同时不愿意把类的细节公开。
这实际上就是一种设计模式。

     同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。另外见程序注释处,为另一种得到内部类对象的一种方法,其语法为:

outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);

     注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。至于原因,也就引出了我们下一个话题–非静态内部类对象有着指向其外部类对象的引用,对刚才的例子稍作修改:

public class Parcel3 {
  private valueRate=2;
  private class PContent implements Contents {
    private int i = 11*valueRate;
    public int value() { return i; }
 }

  protected class PDestination implements Destination {
  private String label;
  private PDestination(String whereTo) {label = whereTo;}
  public String readLabel() { return label; }
  }

  public Destination dest(String s) {
    return new PDestination(s);
  }
  public Contents cont() {
  return new PContent();
  }
}

      在这里我们给Parcel3类增加了一个private成员变量valueRate,我们发现,value()可以访问valueRate,这也是内部类的第二个好处–一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。

  和普通的类一样,内部类也可以有静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。

原文地址:https://www.cnblogs.com/huqingyu/p/558511.html