如约书亚·布洛赫(Joshua Bloch)所述,包装器类如何等于组成? [英] How is having a wrapper class equals composition as described Joshua Bloch?

查看:62
本文介绍了如约书亚·布洛赫(Joshua Bloch)所述,包装器类如何等于组成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读Joshua Bloch撰写的有效Java书籍。在偏重于继承的组合第16项中,他给出了一个示例,该示例使用HashSet并查询自创建以来已添加了多少个元素(不要与当前大小混淆,当前大小会在删除元素时下降)。他提供了以下代码,这里提供了getAddCount返回值6,据我所知。这实际上应该返回3。 (这是因为HashSet的addAll方法是在其add方法之上实现的)

I am reading the book effective java by Joshua Bloch. on the item 16 of "favor composition over inheritance", he gives an example of using HashSet and querying how many elements have been added since it was created(not to be confused with current size, which goes down when an element is removed). he provided the following code and here the getAddCount return 6, which I can understand. This should return 3 actually. (this is because HashSet's addAll method is implemented on top of its add method)

import java.util.HashSet;

public class InstrumentedHashSet<E> extends HashSet<E> {
    // The number of attempted element insertions
    private int addCount = 0;

    public InstrumentedHashSet() {
    }

    public InstrumentedHashSet(int initCap, float loadFactor) {
        super(initCap, loadFactor);
    }

    @Override
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);
    }

    public int getAddCount() {
        return addCount;
    }

    public static void main(String[] args) {
        InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
        s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
        System.out.println(s.getAddCount());
    }
} 

现在,他介绍了使用包装器解决此问题的方法类(合成和转发)。这是我很难理解的地方。他提供了以下两个类

Now he explains a way to fix this, using wrapper classes (composition and forwarding). here is where I am having hard time to understand. he provides the following two classes

    public class ForwardingSet<E> implements Set<E> {
    private final Set<E> s;

    public ForwardingSet(Set<E> s) {
        this.s = s;
    }

    public void clear() {
        s.clear();
    }

    public boolean contains(Object o) {
        return s.contains(o);
    }

    public boolean isEmpty() {
        return s.isEmpty();
    }

    public int size() {
        return s.size();
    }

    public Iterator<E> iterator() {
        return s.iterator();
    }

    public boolean add(E e) {
        return s.add(e);
    }

    public boolean remove(Object o) {
        return s.remove(o);
    }

    public boolean containsAll(Collection<?> c) {
        return s.containsAll(c);
    }

    public boolean addAll(Collection<? extends E> c) {
        return s.addAll(c);
    }

    public boolean removeAll(Collection<?> c) {
        return s.removeAll(c);
    }

    public boolean retainAll(Collection<?> c) {
        return s.retainAll(c);
    }

    public Object[] toArray() {
        return s.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return s.toArray(a);
    }

    @Override
    public boolean equals(Object o) {
        return s.equals(o);
    }

    @Override
    public int hashCode() {
        return s.hashCode();
    }

    @Override
    public String toString() {
        return s.toString();
    }
}

AND

import java.util.*;
    public class InstrumentedSet<E> extends ForwardingSet<E> {
        private int addCount = 0;

        public InstrumentedSet(Set<E> s) {
            super(s);
        }

        @Override
        public boolean add(E e) {
            addCount++;
            return super.add(e);
        }

        @Override
        public boolean addAll(Collection<? extends E> c) {
            addCount += c.size();
            return super.addAll(c);
        }

        public int getAddCount() {
            return addCount;
        }

        public static void main(String[] args) {
            InstrumentedSet<String> s = new InstrumentedSet<String>(
                    new HashSet<String>());
            s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
            System.out.println(s.getAddCount());
        }
    }

这是如何工作的?在main方法中,我创建了HashSet的实例,并使用addAll方法添加了list的所有元素。但是HashSet调用其addAll方法(依次使用其add方法),该方法应该与正确示例中的第一个方法相同,并且我应该获得6的值,但这给了我3。

how this works? In the main method, I create an instance of HashSet and using addAll method, I add all the elements of list. but the HashSet invokes its addAll method (which in turn uses its add method), which should be the same as in the first in correct example and I should get value of 6, however this gives me 3.

推荐答案

public class InstrumentedHashSet<E> extends HashSet<E> {

您直接添加到 HashSet 因为 addAll()委托给超级实现

you're adding directly to the HashSet because the addAll() is delegating to the super implementation

InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
System.out.println(s.getAddCount());

addAll()内部调用 add()对应于您的 add() @Override 实现>由于多态性

The addAll() internally calls add() which defers to your @Override implementation of add() because of polymorphism

@Override
public boolean add(E e) {
    addCount++;
    return super.add(e);
}

可增加计数并打印 6 (3 +1 + 1 +1)。

that increments the count and prints 6 (3 + 1 + 1 + 1).

In

public class InstrumentedSet<E> extends ForwardingSet<E> {

您要添加到的

private final Set<E> s;

因为 addAll()委托给

public static void main(String[] args) {
    InstrumentedSet<String> s = new InstrumentedSet<String>(
                new HashSet<String>());
    s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
    System.out.println(s.getAddCount());
}

并打印 3 。在这里,在 Set< E>上调用 add()。 s ,而不是您的实例。

and prints 3. Here the add() is being called on the Set<E> s, not on your instance.

结论是,如果要继承,则需要了解其副作用。 super 方法调用是否在内部调用其他任何方法调用?如果是这样,您需要采取适当的行动。

The conclusion is that if you are inheriting, you need to understand the side-effects. Do the super method calls invoke any other method calls internally? If so, you need to act appropriately.

继承(从底部开始)

s.add() // s is your InstrumentedHashSet instance, because of polymorphism (inheritance), this adds to the count
this.add() // this is the internal call inside the HashSet#addAll()
super.addAll(...) // this calls the HashSet implementation of addAll which calls add() internally
s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); // s is your InstrumentedHashSet instance

组成

this.add() // this is the internal call to add() inside the Set implementation
s.addAll() // s is the Set<E> instance
super.addAll(...) // this calls the ForwardingSet implementation of addAll()
s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); // s is your InstrumentedSet instance

这篇关于如约书亚·布洛赫(Joshua Bloch)所述,包装器类如何等于组成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆