Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does HashSet<E> not restrict type of argument to E in contains() and remove() [duplicate]

Tags:

java

Possible Duplicate:
What are the reasons why Map.get(Object key) is not (fully) generic
Why does Java's TreeSet<E> remove(Object) not take an E

Why does HashSet not restrict type of argument to E here:

public boolean contains(Object o)
public boolean remove(Object o)

like it does for add()

public boolean add(E e)

I mean if the compiler is enforcing that only objects of type E are being added, then the set can't contain/remove any other type

like image 984
user674669 Avatar asked Oct 09 '12 20:10

user674669


People also ask

Can HashSet contain duplicates?

Duplicates: HashSet doesn't allow duplicate values. HashMap stores key, value pairs and it does not allow duplicate keys.

How does a HashSet avoid duplicate elements How does it work internally?

And the contains method, would use equals/hashcode. In TreeSet, the elements are stored in a Red-Black Tree, whereas HashSet, uses a HashMap. Infact, the way it is added to the container is specific to the element (the spot on the tree, bucket in the hashtable), thus the adding itself uses equals/hashcode.

What does HashSet do with duplicates?

HashSet doesn't allow duplicates. If you try to add a duplicate element in HashSet, the old value would be overwritten. HashSet allows null values, however if you insert more than one nulls, it would override the previous null value.

Does HashSet have Contains method?

HashSet. contains() method is used to check whether a specific element is present in the HashSet or not. So basically it is used to check if a Set contains any particular element. Parameters: The parameter element is of the type of HashSet.


3 Answers

The difference is that adding must be type-safe to preserve the integrity of the collection, while item checking/removal can afford to be "type-forgiving" without the risk of harming type safety of the collection. In other words, if you add an element of a wrong type, the set will become invalid; on the other hand, if you check for a presence of an element of a wrong type, you'll simply get back a false. Same goes for remove: if you pass an element of an incompatible type, it's not going to be in the set +, so the removal is going to be a no-op.


+ Unless you put it in through a hack that exploits type erasure.
like image 106
Sergey Kalinichenko Avatar answered Oct 14 '22 22:10

Sergey Kalinichenko


then the set can't contain/remove any other type

Of course it can. Read about type erasure or cast your HashSet<E> to non-generic HashSet and add an object which is not of type E to it.

Check out this code:

Integer testInt = new Integer(3);

// First, create a generic set of strings
HashSet<String> set = new HashSet<String>();
set.add("abc");

// Then make it non-generic and add an integer to it
((HashSet) set).add(testInt);

// Now your set-of-strings contains an integer!
System.out.println(set); // prints: [abc, 3]

// Remove the integer
set.remove(testInt);
System.out.println(set); // prints: [abc]

The reason of this weirdness is that the information of generic types is erased in runtime and your set becomes a simple set of objects.

like image 42
npe Avatar answered Oct 14 '22 23:10

npe


The parameter of contains and remove cannot be restricted to E because you should be able to give them just equal objects, which is quite useful. More precisely, the API of HashSet.remove says:

... More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this set contains such an element.

Object.equals takes Object as parameter, which is also quite useful to enable equality between different types.

Thus, to enable the more general functionality of contains and remove (on equivalence classes instead of only object identity), they have to take Object as parameter.


Example:

    HashSet<ArrayList<String>> set = new HashSet<ArrayList<String>>();
    ArrayList<String> list = new ArrayList<String>();
    list.add("foo");
    LinkedList<String> equalList = new LinkedList<String>();
    equalList.add("foo");
    set.add(list);

    System.out.println(list.equals(equalList)); // prints: true
    System.out.println(set.contains(equalList)); // prints: true

    System.out.println(set); // prints: [[foo]]
    set.remove(equalList);
    System.out.println(set); // prints: [[]]
like image 27
DaveFar Avatar answered Oct 15 '22 00:10

DaveFar