第10章 内部类(java编程思想)

10.1 创建内部类

典型的应用情况是,外部类将会有一个方法,该方法返回以内部类的引用。就像在to()和content()中看到的那样。

//: innerclasses/Parcel2.java
// Returning a reference to an inner class.

public class Parcel2 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  public Destination to(String s) {
    return new Destination(s);
  }
  public Contents contents() {
    return new Contents();
  }
  public void ship(String dest) {
    Contents c = contents();
    Destination d = to(dest);
    System.out.println(d.readLabel());
  }
  public static void main(String[] args) {
    Parcel2 p = new Parcel2();
    p.ship("Tasmania");
    Parcel2 q = new Parcel2();
    // Defining references to inner classes:
    Parcel2.Contents c = q.contents();
    Parcel2.Destination d = q.to("Borneo");
  }
} /* Output:
Tasmania
*///:~

10.2 链接到外部类

当生成一个内部类的对象是,此对象与制造他的外围对象之间就有一种联系,所以他能访问其外围对象的所有成员,而不需要任何特殊条件,此外,内部类还拥有其外围类的所有元素的访问权。下面的例子就说明了这一点。

 //: innerclasses/Sequence.java
// Holds a sequence of Objects.

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;
    public boolean end() { return i == items.length; }
    public Object current() { return items[i]; }
    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.print(selector.current() + " ");
      selector.next();
    }
  }
} /* Output:
0 1 2 3 4 5 6 7 8 9
*///:~

内部类的对象只能在与其外部类对象相关联的情况下才可以被创建(就像所看到的,当内部类不是static时),创建内部类需要一个指向其外部类的引用,如果编译器访问不到这个引用就会报错。

10.4 内部类和向上转型

因为不能访问其名字,private内部类给类的设计则提供了一种途径,通过这种方式可以完全阻止依赖于此类型的编码,并且完全隐藏了实现的细节,此外,从客户端程序员的角度来康,由于不能访问任何新增的,原本不属于公共接口的方法,所以扩展接口是没有任何价值的,这也给java编译器生成了更高效代码的机会。
外部类可以访问内部类的private方法。

//: innerclasses/TestParcel.java

class Parcel4 {
  private class PContents implements 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 destination(String s) {
    return new PDestination(s);
  }
  public Contents contents() {
    return new PContents();
  }
}

public class TestParcel {
  public static void main(String[] args) {
    Parcel4 p = new Parcel4();
    Contents c = p.contents();
    Destination d = p.destination("Tasmania");
    // Illegal -- can't access private class:
    //! Parcel4.PContents pc = p.new PContents();
  }
} ///:~

10.5 在方法和作用域内的内部类

你可以在一个方法或任意的作用域内定义内部类,这么做有两个理由:
1)你实现了某类型的接口,于是可以创建并返回他的引用。
2)你要解决一个复杂的问题,想创建一个类来辅助解决你的方案,但是又不希望这个类是公共可用的。
第一个例子展现了在方法的作用域内(而不是类的作用域内),创建一个完整的类,这被称为局部内部类。

//: innerclasses/Parcel5.java
// Nesting a class within a method.

public class Parcel5 {
  public Destination destination(String s) {
    class PDestination implements Destination {
      private String label;
      private PDestination(String whereTo) {
        label = whereTo;
      }
      public String readLabel() { return label; }
    }
    return new PDestination(s);
  }
  public static void main(String[] args) {
    Parcel5 p = new Parcel5();
    Destination d = p.destination("Tasmania");
  }
} ///:~

PDestination是destination()方法的一部分,而不是Parcel5的已不够,除了destination()方法外不能访问PDestination,你可以在同一个子目录下的任意类中对某个内部类使用类标识符PDestination,这样不会有命名冲突。

10.6 匿名内部类

package SourceCode;

//: innerclasses/Parcel8.java
//Calling the base-class constructor.

public class Parcel8 {
public Wrapping wrapping(int x) {
 // Base constructor call:
 return new Wrapping(x) { // Pass constructor argument.
   public int value() {
     return super.value() * 47;
   }
 }; // Semicolon required
}
public static void main(String[] args) {
 Parcel8 p = new Parcel8();
 Wrapping w = p.wrapping(10);
}
} ///:~

//: innerclasses/Wrapping.java
public class Wrapping {
  private int i;
  public Wrapping(int x) { i = x; }
  public int value() { return i; }
} ///:~

在匿名内部类的末尾的分号,并不是用来标记此内部类结束的,实际上,他标记的是表达式的结束,只不过这个表达式正巧包含了内部匿名类罢了,因此,这与别的地方使用的分号是一致的。
在匿名类中定义字段时,还可以对其进行初始化操作。

在这里插入代码片

如果定义一个匿名内部类,并且希望它使用一个定义在其外部定义的对象,那么编译器会要求这个对象的参数引用是final的,就像你在destination()的参数引用中看到的那样,如果你忘记了,那么编译器会报错。
10.6.1 再返工厂方法
现在用于Implementation1和Implementation2的构造器都可以是private,并且没有任何必要去创建作为工厂的别名。

//: innerclasses/Factories.java
import static net.mindview.util.Print.*;

interface Service {
  void method1();
  void method2();
}

interface ServiceFactory {
  Service getService();
}	

class Implementation1 implements Service {
  private Implementation1() {}
  public void method1() {print("Implementation1 method1");}
  public void method2() {print("Implementation1 method2");}
  public static ServiceFactory factory =
    new ServiceFactory() {
      public Service getService() {
        return new Implementation1();
      }
    };
}	

class Implementation2 implements Service {
  private Implementation2() {}
  public void method1() {print("Implementation2 method1");}
  public void method2() {print("Implementation2 method2");}
  public static ServiceFactory factory =
    new ServiceFactory() {
      public Service getService() {
        return new Implementation2();
      }
    };
}	

public class Factories {
  public static void serviceConsumer(ServiceFactory fact) {
    Service s = fact.getService();
    s.method1();
    s.method2();
  }
  public static void main(String[] args) {
    serviceConsumer(Implementation1.factory);
    // Implementations are completely interchangeable:
    serviceConsumer(Implementation2.factory);
  }
} /* Output:
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
*///:~

10.7 嵌套类

如果不需要内部对象与外围对象有任何联系,可以将内部对象声明为static,这通常称为嵌套类,想要理解static应用于内部类是的含义,就必须记住,普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象,然而,当内部类是static时,就不是这样了,嵌套类意味着
1)要创建嵌套类的对象,并不需要外围类的对象。
2)不能从嵌套类的对象中访问非静态的外围类对象。

10.8 为什么需要内部类

内部类提供了可以继承多个具体或抽象的类的能力,内部类使多重继承的功能变得完整,接口解决了部分问题,而内部类有效的实现了多重继承,也就是说,内部类允许继承多个非接口类型,内部了的特性:
1)内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围·对象的信息相独立。
2) 在单个外围类中可以让多个内部类一不同的方式实现同一个接口,或继承同一个类。
3)创建内部类的时刻并不依赖于外围类对象的创建。
10.8.1 闭包与回调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值