2008-10-25 82 views
2

我正在重读Effective Java(第2版)第18项prefer interfaces to abstract classes。在该项目乔希布洛赫提供的骨干实现Map.Entry<K,V>接口的一个例子:接口的骨架实现中的抽象方法

// Skeletal Implementation 
public abstract class AbstractMapEntry<K,V> 
     implements Map.Entry<K,V> { 
    // Primitive operations 
    public abstract K getKey(); 
    public abstract V getValue(); 

// ... remainder omitted 
} 

两个问题从这个例子干:

  1. 为什么信息getKey和getValue明确声明这里的抽象方法?它们是Map.Entry接口的一部分,所以我没有看到抽象类中冗余声明的原因。
  2. 为什么用布洛赫先生提到的这些原始方法来表达抽象的成语?为什么不这样做:

    //骨架实现 public abstract class AbstractMapEntry implements Map.Entry { private K key;私人V值为 ;

    // Primitive operations 
        public K getKey() {return key;} 
        public V getValue() {return value;} 
    
    // ... remainder omitted 
    

    }

这样做的好处是,每个子类没有定义自己的字段集,并且仍然可以访问他们的存取键和值。如果一个子类真的需要为访问者定义自己的行为,那么它可以直接实现Map.Entry接口。另一个缺点是,在由骨骼实现提供的equals方法,将抽象访问被称为:

// Implements the general contract of Map.Entry.equals 
@Override public boolean equals(Object o) { 
    if (o == this) 
     return true; 
    if (! (o instanceof Map.Entry)) 
     return false; 
    Map.Entry<?,?> arg = (Map.Entry) o; 
    return equals(getKey(), arg.getKey()) && 
      equals(getValue(), arg.getValue()); 
} 

布洛赫警告不要从设计继承的类调用重写的方法(17项),因为它离开超容易由子类进行的更改。 也许这是一个意见问题,但我希望能够确定是否有更多的故事,因为布洛赫在书中没有详细说明这一点。

回答

0

AbstractMapEntry#getKeygetValue是抽象(即未实现)的一个原因是Map.EntryMap的内部接口。使用嵌套类/接口是Java实现组合的方式。构图中的想法是组成部分不是一流的概念。相反,组成部分只有在整体中才有意义。在这种情况下,组成部分是Map.Entry,组合的根对象是Map。显然表达的概念是Map有许多Map.Entry s。

因此,AbstractMapEntry#getKeygetValue的语义将基本上取决于我们正在讨论的Map的实现。正如你写的一个简单的旧的getter实现将工作得很好,为HashMap。它不适用于需要线程安全的ConcurrentHashMap之类的东西。 ConcurrentHashMapgetKeygetValue的执行很可能成为防御性副本。 (建议您自己检查源代码)。

另一个原因不执行getKeygetValue是实现Map字符是完全不同的范围从那些不应该让属于(即Properties)以完全不同的宇宙从Map直观impls(例如ProviderTabularDataSupport)。

总之,实现,因为API设计的这条黄金法则的AbstractMapEntry#getKeygetValue,:

如果有疑问,离开它(见here

+0

错误,你似乎完全忽略了这个问题... – 2008-10-25 23:39:22

0
  1. 我没有看到任何理由

  2. 允许实现定义键和值的存储方式。

1
  1. 我会说这有助于强调什么具体的类旨在应对,而不是只留给了编译器告诉你(或你有比较既要看到什么是丢失) 。一种自我记录的代码。但是,我可以看到,它当然没有必要,它更像是一种风格的东西。
  2. 返回这些值的逻辑比简单的getter和setting更有意义。我在标准JDK(1.5)中检查过的每个类都至少在其中一个方法上做了非简单的事情,所以我猜测他认为这样的实现太幼稚了,它会鼓励子类使用它,而不是通过思考这个问题靠自己解决。

关于与平等的问题,如果抽象类实现它们,因为这个问题是overrid 能够没有什么会改变。在这种情况下,我会说平等正在试图仔细实施以预测实施。由于协方差问题,通常等于一般不应该被实现为在它自己和它的子类之间返回真(尽管有很多事情是这样做的)(超类将认为它等于子类,但子类不会认为它等于超类) ,所以无论你做什么,这种类型的equals实现都很棘手。

1

布洛赫警告说,不要叫从 类设计继承 重写的方法(17项),因为它 树叶子类

他警告有关调用在重写的方法做出的超容易 变化构造函数,而不是其他方法。