`

读《Effective java 中文版》(19)

 
阅读更多

第18条:优先考虑静态成员类
  嵌套类(nested class)是指被定义在另一类的内部的类,它只为它的外围类服务。如果一个嵌套类可能会用于其它的某个环境,那就应为一个顶层类(top-level class)。嵌套类有四种:静态成员类(static member class)、非静态成员类(nonstatic member class)、匿名类(anonymous class)和局部类(local class),其中后三种称为内部类(inner class)。

  静态成员类是一种最简单的嵌套类,最后把它看作一个普通的类,碰巧被声明在另一个类的内部而已,它可以访问外围类的所有成员,包括那些声明为私有的成员。静态成员类是外围类的一个静态成员,与其他的静态成员一样,遵守同样的可访问性规则。如果它被声明为私有的,则只能在外围类的内部才可以被访问。静态成员类的一种通常用法是作为公有的辅助类,仅当它与它的外部类一起使用时才有意义。
  从语法上,非静态成员类与静态成员类的差别在于后者有一个static。非静态成员类的每一个实例,都隐含着与外围类的一个外围实例紧密联系在一起。在非静态成员类的实例方法内部,调用外围实例上的方法是可能的,或者使用一个经过修饰的this也可以得到个指向外围实例的引用。在没有外围实例的情况下,要想创建非静态成员类的实例是不可能的。非静态成员类的一种通常用法是定义一个Adapter,它允许外部类的一个实例被看作另一个不相关的类的实例。如Map接口的实现往往使用非静态成员类来实现它们的“集合”视图,这些“集合”视图是由Map的keySet、entrySet、Value方法返回。再看Set集合接口实现迭代器的例子:
//Typical use of a nonstatic member class
public class MySet extends AbstractSet{
// bulk of the class omitted
public Iterator interator(){
return new MyIterator();
}
private class MyIterator implements Iterator{
...
}
}
  如果声明的成员类不要求访问外围实例,那么就把static修饰符放到成员类的声明中。这会减少维护成员类实例对外围实例对象的引用的开销。
  私有静态成员类的一种通常用法是用来代表外围类对象的组件。例如:Map实例把一些Key和Value关联起来,其内部通常有一个Entry对象对应于每个键值对。每个Entry对象都与一个Map对象关联,但Entry的方法(getKey、getValue、setValue)都不需要外围的Map。此时,用私有的静态成员类是最佳选择。
  匿名类没有名字,它不是外围类的一个成员。它并不与其它的成员一起被声明,而在被使用的点上同时声明和被实例化。匿名类可以出现在代码中任何允许表达式出现的地方。匿名类的行为与成员类非常类似,具体取决于它所在环境:如果匿名类出现在一个非静态的环境中,则它有一个外围实例。
  匿名类的适用性有一些限制:

  • 匿名类只能被用在代码中它将被实例化的那个点上。
  • 它没有名字,实例化后不能 再 对它进行引用
  • 匿名通常只实现了其接口或者超类中方法,不会声明新的方法,因为没有访问新方法的途径。
  • 因为匿名类出现于表达中,故它们应该非常短(20行或更少),以增强程序的可读性

  匿名类的常见用法:

  1.   匿名类的一通常用法是创建一个函数对象(function object),如:
    //typical use of an anonymous class
    //Arrays.sort(args,new comparator(){
    public int compare(Object o1,Object o2){
    return ((String)o1).length()-((String)o2).length();
    }
    });
  2. 另一个常见用法是创建一个过程对象(process object),如Thread、Runnable、TimerTasker实例。
  3. 在一个静态工厂方法的内部(参见第16条)
  4. 用在复杂的类型安全枚举类型(它要求为每个实例提供单独的子类)
      例子:
      //typical use of a public static member class
      public class Calculator{
      public static abstract class Operation{
      private final String name;
      Operation(String name){ this.name=name;}
      public String toString(){ return this.name};
      //perform arithmetic op represented by this constant
      abstract double eval(double x,double y);

      //doubly nested anonymous classes
      public static final Operation PLUS = new Operation("+"){
      double eval(double x,double y){return x+y;}
      }
      public static final Operation MINUS= new Operation("-"){
      double eval(double x,double y){return x-y;}
      }
      public static final Operation TIMES= new Operation("*"){
      double eval(double x,double y){return x*y;}
      }
      public static final Operation DIVIDE=new Operation("/"){
      double eval(double x,double y){return x/y;}
      }
      }
      //Return hte results of the specified calculation
      public double calculate(double x,Operation op,double y){
      return op.eval(x,y);
      }
      }

        局部类是四种嵌套类中最少使用的类。在任何“可以声明局部变量”的地方,都可以声明局部类。与成员类一样,局部类有名字,可以被重复使用。与匿名类一样,当且仅当局部类被用于非静态环境下的进修,它们才有外围实例。与匿名类一样,它必须非简短,以不会损害外围方法或者初始化器的可读性。
        总之,如果一个嵌套类需要在单个方法之外仍是可见的,或者它太长了,不适合于放在一个方法内部,则应该使用成员类。如果成员类的每个实例都需要一个指向其外围的实例的引用,则把成员类做成非静态的;否则做成静态的。假设一个嵌套类属于一方法的内部,如果只需要在一个地方创建它的实例,并且已经有了一个预先存在的类型可以说明这个类的特征,则把它做成匿名类;否则变成局部类。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics