{学习笔记}[类库系列——commons.bag]

源代码:
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.collections4;

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

/**
 * Defines a collection that counts the number of times an object appears in
 * the collection.
 * <p>
 * Suppose you have a Bag that contains <code>{a, a, b, c}</code>.
 * Calling {@link #getCount(Object)} on <code>a</code> would return 2, while
 * calling {@link #uniqueSet()} would return <code>{a, b, c}</code>.
 * <p>
 * <i>NOTE: This interface violates the {@link Collection} contract.</i>
 * The behavior specified in many of these methods is <i>not</i> the same
 * as the behavior specified by <code>Collection</code>.
 * The noncompliant methods are clearly marked with "(Violation)".
 * Exercise caution when using a bag as a <code>Collection</code>.
 * <p>
 * This violation resulted from the original specification of this interface.
 * In an ideal world, the interface would be changed to fix the problems, however
 * it has been decided to maintain backwards compatibility instead.
 *
 * @param <E> the type held in the bag
 * @since 2.0
 * @version $Id: Bag.java 1477779 2013-04-30 18:55:24Z tn $
 */
public interface Bag<E> extends Collection<E> {

    /**
     * Returns the number of occurrences (cardinality) of the given
     * object currently in the bag. If the object does not exist in the
     * bag, return 0.
     *
     * @param object  the object to search for
     * @return the number of occurrences of the object, zero if not found
     */
    int getCount(Object object);

    /**
     * <i>(Violation)</i>
     * Adds one copy of the specified object to the Bag.
     * <p>
     * If the object is already in the {@link #uniqueSet()} then increment its
     * count as reported by {@link #getCount(Object)}. Otherwise add it to the
     * {@link #uniqueSet()} and report its count as 1.
     * <p>
     * Since this method always increases the size of the bag,
     * according to the {@link Collection#add(Object)} contract, it
     * should always return <code>true</code>.  Since it sometimes returns
     * <code>false</code>, this method violates the contract.
     *
     * @param object  the object to add
     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
     */
    boolean add(E object);

    /**
     * Adds <code>nCopies</code> copies of the specified object to the Bag.
     * <p>
     * If the object is already in the {@link #uniqueSet()} then increment its
     * count as reported by {@link #getCount(Object)}. Otherwise add it to the
     * {@link #uniqueSet()} and report its count as <code>nCopies</code>.
     *
     * @param object  the object to add
     * @param nCopies  the number of copies to add
     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
     */
    boolean add(E object, int nCopies);

    /**
     * <i>(Violation)</i>
     * Removes all occurrences of the given object from the bag.
     * <p>
     * This will also remove the object from the {@link #uniqueSet()}.
     * <p>
     * According to the {@link Collection#remove(Object)} method,
     * this method should only remove the <i>first</i> occurrence of the
     * given object, not <i>all</i> occurrences.
     *
     * @param object  the object to remove
     * @return <code>true</code> if this call changed the collection
     */
    boolean remove(Object object);

    /**
     * Removes <code>nCopies</code> copies of the specified object from the Bag.
     * <p>
     * If the number of copies to remove is greater than the actual number of
     * copies in the Bag, no error is thrown.
     *
     * @param object  the object to remove
     * @param nCopies  the number of copies to remove
     * @return <code>true</code> if this call changed the collection
     */
    boolean remove(Object object, int nCopies);

    /**
     * Returns a {@link Set} of unique elements in the Bag.
     * <p>
     * Uniqueness constraints are the same as those in {@link java.util.Set}.
     *
     * @return the Set of unique Bag elements
     */
    Set<E> uniqueSet();

    /**
     * Returns the total number of items in the bag across all types.
     *
     * @return the total size of the Bag
     */
    int size();

    /**
     * <i>(Violation)</i>
     * Returns <code>true</code> if the bag contains all elements in
     * the given collection, respecting cardinality.  That is, if the
     * given collection <code>coll</code> contains <code>n</code> copies
     * of a given object, calling {@link #getCount(Object)} on that object must
     * be <code>&gt;= n</code> for all <code>n</code> in <code>coll</code>.
     * <p>
     * The {@link Collection#containsAll(Collection)} method specifies
     * that cardinality should <i>not</i> be respected; this method should
     * return true if the bag contains at least one of every object contained
     * in the given collection.
     *
     * @param coll  the collection to check against
     * @return <code>true</code> if the Bag contains all the collection
     */
    boolean containsAll(Collection<?> coll);

    /**
     * <i>(Violation)</i>
     * Remove all elements represented in the given collection,
     * respecting cardinality.  That is, if the given collection
     * <code>coll</code> contains <code>n</code> copies of a given object,
     * the bag will have <code>n</code> fewer copies, assuming the bag
     * had at least <code>n</code> copies to begin with.
     *
     * <p>The {@link Collection#removeAll(Collection)} method specifies
     * that cardinality should <i>not</i> be respected; this method should
     * remove <i>all</i> occurrences of every object contained in the
     * given collection.
     *
     * @param coll  the collection to remove
     * @return <code>true</code> if this call changed the collection
     */
    boolean removeAll(Collection<?> coll);

    /**
     * <i>(Violation)</i>
     * Remove any members of the bag that are not in the given
     * collection, respecting cardinality.  That is, if the given
     * collection <code>coll</code> contains <code>n</code> copies of a
     * given object and the bag has <code>m &gt; n</code> copies, then
     * delete <code>m - n</code> copies from the bag.  In addition, if
     * <code>e</code> is an object in the bag but
     * <code>!coll.contains(e)</code>, then remove <code>e</code> and any
     * of its copies.
     *
     * <p>The {@link Collection#retainAll(Collection)} method specifies
     * that cardinality should <i>not</i> be respected; this method should
     * keep <i>all</i> occurrences of every object contained in the
     * given collection.
     *
     * @param coll  the collection to retain
     * @return <code>true</code> if this call changed the collection
     */
    boolean retainAll(Collection<?> coll);

    /**
     * Returns an {@link Iterator} over the entire set of members,
     * including copies due to cardinality. This iterator is fail-fast
     * and will not tolerate concurrent modifications.
     *
     * @return iterator over all elements in the Bag
     */
    Iterator<E> iterator();

    // The following is not part of the formal Bag interface, however where possible
    // Bag implementations should follow these comments.
//    /**
//     * Compares this Bag to another.
//     * This Bag equals another Bag if it contains the same number of occurrences of
//     * the same elements.
//     * This equals definition is compatible with the Set interface.
//     *
//     * @param obj  the Bag to compare to
//     * @return true if equal
//     */
//    boolean equals(Object obj);
//
//    /**
//     * Gets a hash code for the Bag compatible with the definition of equals.
//     * The hash code is defined as the sum total of a hash code for each element.
//     * The per element hash code is defined as
//     * <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>.
//     * This hash code definition is compatible with the Set interface.
//     *
//     * @return the hash code of the Bag
//     */
//    int hashCode();

}
实现源代码的抽象类
    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.apache.commons.collections4.bag;

    import java.util.Set;

    import org.apache.commons.collections4.Bag;
    import org.apache.commons.collections4.collection.AbstractCollectionDecorator;

    /**
     * Decorates another <code>Bag</code> to provide additional behaviour.
     * <p>
     * Methods are forwarded directly to the decorated bag.
     *
     * @since 3.0
     * @version $Id: AbstractBagDecorator.java 1686855 2015-06-22 13:00:27Z tn $
     */
    public abstract class AbstractBagDecorator<E>
            extends AbstractCollectionDecorator<E> implements Bag<E> {

        /** Serialization version */
        private static final long serialVersionUID = -3768146017343785417L;

        /**
         * Constructor only used in deserialization, do not use otherwise.
         * @since 3.1
         */
        protected AbstractBagDecorator() {
            super();
        }

        /**
         * Constructor that wraps (not copies).
         *
         * @param bag  the bag to decorate, must not be null
         * @throws NullPointerException if bag is null
         */
        protected AbstractBagDecorator(final Bag<E> bag) {
            super(bag);
        }

        /**
         * Gets the bag being decorated.
         *
         * @return the decorated bag
         */
        @Override
        protected Bag<E> decorated() {
            return (Bag<E>) super.decorated();
        }

        @Override
        public boolean equals(final Object object) {
            return object == this || decorated().equals(object);
        }

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

        //-----------------------------------------------------------------------

        @Override
        public int getCount(final Object object) {
            return decorated().getCount(object);
        }

        @Override
        public boolean add(final E object, final int count) {
            return decorated().add(object, count);
        }

        @Override
        public boolean remove(final Object object, final int count) {
                return decorated().remove(object, count);
        }

        @Override
        public Set<E> uniqueSet() {
            return decorated().uniqueSet();
        }

    }
实现抽象类的类
    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.apache.commons.collections4.bag;

    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.Collection;
    import java.util.Iterator;

    import org.apache.commons.collections4.Bag;

    /**
     * Decorates another {@link Bag} to comply with the Collection contract.
     * <p>
     * By decorating an existing {@link Bag} instance with a {@link CollectionBag},
     * it can be safely passed on to methods that require Collection types that
     * are fully compliant with the Collection contract.
     * <p>
     * The method javadoc highlights the differences compared to the original Bag interface.
     *
     * @see Bag
     * @param <E> the type held in the bag
     * @since 4.0
     * @version $Id: CollectionBag.java 1686855 2015-06-22 13:00:27Z tn $
     */
    public final class CollectionBag<E> extends AbstractBagDecorator<E> {

        /** Serialization version */
        private static final long serialVersionUID = -2560033712679053143L;

        /**
         * Factory method to create a bag that complies to the Collection contract.
         *
         * @param <E> the type of the elements in the bag
         * @param bag  the bag to decorate, must not be null
         * @return a Bag that complies to the Collection contract
         * @throws NullPointerException if bag is null
         */
        public static <E> Bag<E> collectionBag(final Bag<E> bag) {
            return new CollectionBag<E>(bag);
        }

        //-----------------------------------------------------------------------
        /**
         * Constructor that wraps (not copies).
         *
         * @param bag  the bag to decorate, must not be null
         * @throws NullPointerException if bag is null
         */
        public CollectionBag(final Bag<E> bag) {
            super(bag);
        }

        //-----------------------------------------------------------------------
        /**
         * Write the collection out using a custom routine.
         *
         * @param out  the output stream
         * @throws IOException
         */
        private void writeObject(final ObjectOutputStream out) throws IOException {
            out.defaultWriteObject();
            out.writeObject(decorated());
        }

        /**
         * Read the collection in using a custom routine.
         *
         * @param in  the input stream
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws ClassCastException if deserialised object has wrong type
         */
        @SuppressWarnings("unchecked") // will throw CCE, see Javadoc
        private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
            in.defaultReadObject();
            setCollection((Collection<E>) in.readObject());
        }

        //-----------------------------------------------------------------------
        // Collection interface
        //-----------------------------------------------------------------------

        /**
         * <i>(Change)</i>
         * Returns <code>true</code> if the bag contains all elements in
         * the given collection, <b>not</b> respecting cardinality. That is,
         * if the given collection <code>coll</code> contains at least one of
         * every object contained in this object.
         *
         * @param coll  the collection to check against
         * @return <code>true</code> if the Bag contains at least one of every object in the collection
         */
        @Override
        public boolean containsAll(final Collection<?> coll) {
            final Iterator<?> e = coll.iterator();
            while (e.hasNext()) {
                if(!contains(e.next())) {
                    return false;
                }
            }
            return true;
        }

        /**
         * <i>(Change)</i>
         * Adds one copy of the specified object to the Bag.
         * <p>
         * Since this method always increases the size of the bag, it
         * will always return <code>true</code>.
         *
         * @param object  the object to add
         * @return <code>true</code>, always
         */
        @Override
        public boolean add(final E object) {
            return add(object, 1);
        }

        @Override
        public boolean addAll(final Collection<? extends E> coll) {
            boolean changed = false;
            final Iterator<? extends E> i = coll.iterator();
            while (i.hasNext()) {
                final boolean added = add(i.next(), 1);
                changed = changed || added;
            }
            return changed;
        }

        /**
         * <i>(Change)</i>
         * Removes the first occurrence of the given object from the bag.
         * <p>
         * This will also remove the object from the {@link #uniqueSet()} if the
         * bag contains no occurrence anymore of the object after this operation.
         *
         * @param object  the object to remove
         * @return <code>true</code> if this call changed the collection
         */
        @Override
        public boolean remove(final Object object) {
            return remove(object, 1);
        }

        /**
         * <i>(Change)</i>
         * Remove all elements represented in the given collection,
         * <b>not</b> respecting cardinality. That is, remove <i>all</i>
         * occurrences of every object contained in the given collection.
         *
         * @param coll  the collection to remove
         * @return <code>true</code> if this call changed the collection
         */
        @Override
        public boolean removeAll(final Collection<?> coll) {
            if (coll != null) {
                boolean result = false;
                final Iterator<?> i = coll.iterator();
                while (i.hasNext()) {
                    final Object obj = i.next();
                    final boolean changed = remove(obj, getCount(obj));
                    result = result || changed;
                }
                return result;
            } else {
                // let the decorated bag handle the case of null argument
                return decorated().removeAll(null);
            }
        }

        /**
         * <i>(Change)</i>
         * Remove any members of the bag that are not in the given collection,
         * <i>not</i> respecting cardinality. That is, any object in the given
         * collection <code>coll</code> will be retained in the bag with the same
         * number of copies prior to this operation. All other objects will be
         * completely removed from this bag.
         * <p>
         * This implementation iterates over the elements of this bag, checking
         * each element in turn to see if it's contained in <code>coll</code>.
         * If it's not contained, it's removed from this bag. As a consequence,
         * it is advised to use a collection type for <code>coll</code> that provides
         * a fast (e.g. O(1)) implementation of {@link Collection#contains(Object)}.
         *
         * @param coll  the collection to retain
         * @return <code>true</code> if this call changed the collection
         */
        @Override
        public boolean retainAll(final Collection<?> coll) {
            if (coll != null) {
                boolean modified = false;
                final Iterator<E> e = iterator();
                while (e.hasNext()) {
                    if (!coll.contains(e.next())) {
                        e.remove();
                        modified = true;
                    }
                }
                return modified;
            } else {
                // let the decorated bag handle the case of null argument
                return decorated().retainAll(null);
            }
        }

        //-----------------------------------------------------------------------
        // Bag interface
        //-----------------------------------------------------------------------

        /**
         * <i>(Change)</i>
         * Adds <code>count</code> copies of the specified object to the Bag.
         * <p>
         * Since this method always increases the size of the bag, it
         * will always return <code>true</code>.
         *
         * @param object  the object to add
         * @param count  the number of copies to add
         * @return <code>true</code>, always
         */
        @Override
        public boolean add(final E object, final int count) {
            decorated().add(object, count);
            return true;
        }

    }

与算法第四版定义的基础包的不同:

实现了remove
add 的实现?
对这个问题感兴趣是因为bag的链表实现在取出时还是顺序的,但是在算法第四版中的定义,bag是无序的(一些书中也说了,有序无序都可)但是怎么实现无序?
在这个抽象类中,通过源代码可以看到,对add的实现,是通过decorated实现的。

搁置问题

问题来了,decorated到底在哪出来的。。。。
其他实现bag接口的抽象类的add实现是什么样的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值