java.util.Set add and remove method signature diff

2019-05-06 01:54发布

问题:

When I see the Set.java file in JDK,

/**
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @param <E> the type of elements maintained by this set
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see Collection
 * @see List
 * @see SortedSet
 * @see HashSet
 * @see TreeSet
 * @see AbstractSet
 * @see Collections#singleton(java.lang.Object)
 * @see Collections#EMPTY_SET
 * @since 1.2
 */
public interface Set<E> extends Collection<E> {
    /**
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     *         element
     * @throws UnsupportedOperationException if the <tt>add</tt> operation
     *         is not supported by this set
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this set
     * @throws NullPointerException if the specified element is null and this
     *         set does not permit null elements
     * @throws IllegalArgumentException if some property of the specified element
     *         prevents it from being added to this set
     */
    boolean add(E e);

     /**
     * @param o object to be removed from this set, if present
     * @return <tt>true</tt> if this set contained the specified element
     * @throws ClassCastException if the type of the specified element
     *         is incompatible with this set
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if the specified element is null and this
     *         set does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
     *         is not supported by this set
     */
    boolean remove(Object o);

    //other methods
}

I am not getting, why add method is taking E parameter and remove method is taking Object parameter as a input argument?

Any help or reference link to understand this behavior would be appreciate.

回答1:

Because your Set will always return E, but you may want to check if an object (not necessarily E) is in the Set.



回答2:

I agree, it's wierd, but it allows you to do the following:

Set<String> stringSet = new HashSet<String>();
stringSet.add("blah");

Object blah = "blah";
stringSet.remove(blah);


回答3:

In public boolean add(E e) E means the the type of elements maintained by this set. You can only permitted element of type in collection. Inernally its maps at work

 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

In public boolean remove(Object o) Removes the specified element from this set if it is present. You dont need to check what type of element it is - just check if its there take it out.

again maps at work internally

 public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }


回答4:

The add method of collections is 'covariant', which means that you can add any element of type E or of a subtype of E. The remove method however is contravariant, you can remove any object that is a either of type E or of a supertype of E. Normally, the syntax would have to be

public boolean remove(? super E element)

But since this syntax is not valid in Java (unfortunately), the type of the parameter is Object, which is always a super type of E, no matter what E is.

This also allows you to remove an object from the collection whose runtime type is E while its compile-time type is a supertype of E. For example, take a look at this simple piece of code

List<String> list = new ArrayList();
list.add("abc");

Object o = "abc";
list.remove(o);

This code shows that you should be able to remove any object from the collection that has the same or a supertype of the collection. Due to the syntactic limitation of Java, the method would also accept any other object that could never be in the collection due to its type:

list.remove(1);

This example compiles perfectly fine, but it makes no sense: You could never have an Integer in your List<String>.

Conclusion

The parameter type of remove is Object because it represents the supertype of all types, and it lets you remove an element that has been upcasted to Object while it could still be an element in the collection due to its runtime type. The signature remove(? super E) is neither possible nor necessary, but it would warn the programmer when an operation can never succeed, like remove(1) on a List<String>.



标签: java set