What's the difference between raw types, unbounded wild cards and using Object in generics

I am reading the chapter on Generics in Effective Java.

Help me understand difference between Set, Set<?> and Set<Object>?

The following paragraph is taken from the book.

As a quick review, Set<Object> is a parameterized type representing a set that can contain objects of any type, Set<?> is a wildcard type representing a set that can contain only objects of some unknown type, and Set is a raw type, which opts out of the generic type system.

What is meant by "some unknown type"? Are all unknown types of type Object? In that case what is the specific difference between Set<?> and Set<Object>?


  • a raw type (Set) treats the type as if it had no generic type information at all. Note the subtle effect that not only will the type argument T be ignored, but also all other type arguments that methods of that type might have. You can add any value to it and it will always return Object.
  • Set<Object> is a Set that accepts all Object objects (i.e. all objects) and will return objects of type Object.
  • Set<?> is a Set that accepts all objects of some specific, but unknown type and will return objects of that type. Since nothing is known about this type, you can't add anything to that set (except for null) and the only thing that you know about the values it returns is that they are some sub-type of Object.

At runtime, the JVM will just see Set because of type erasure.

At compile-time, there's a difference:

Set<Object> parameterized a type E with Object thus, Set.add(E element) will be parameterized to Set.add(Object element).

Set<?> on the other hand, adds a wildcard on a type E so Set.add(E element) is translated to Set.add(? element). Since this is not compilable, java instead "translates" it as Set.add(null element). It means that you cannot add anything to that set (except a null). The reason is that the wildcard is referencing to an unknown type.


what is meant by "some unknown type"

Exactly what it means - the Set has some generic parameter, but we don't know what it is.

So the set assigned to a Set<?> variable might be a Set<String>, or a Set<Integer>, or a Set<Map<Integer, Employee>> or a set containing any other specific type.

So what does that mean for how you can use it? Well, anything you get out of it will be an instance of the ?, whatever that is. Since we don't know what the type parameter is, you can't say anything more specific than that elements of the set will be assignable to Object (only because all classes extend from it).

And if you're thinking of adding something to the set - well, the add method takes a ? (which makes sense, since this is the type of objects within the set). But if you try to add any specific object, how can you be sure this is type-safe? You can't - if you're inserting a String, you might be putting it into a Set<Integer> for example, which would break the type-safety you get from generics. So while you don't know the type of the generic parameter, you can't supply any arguments of this type (with the single exception of null, as that's an "instance" of any type).


As with most generics-related answers, this has focused on collections because they're easier to comprehend instinctively. However the arguments apply to any class that takes generic parameters - if it's declared with the unbounded wildcard parameter ?, you can't supply any arguments to it, and any values you receive of that type will only be assignable to Object.


Set: No generics here, unsafe. Add what you want.

Set<?>: A set of a certain type we don't know from our scope. The same as Set<? extends Object>. Can reference to Sets of any type, but that type must be defined at the point where the set is actually instantiated. With the wildcarded reference, we can´t modify the set (we can't add or remove with anything not null). Is like a view.

Set<Object>: Set containing Objects (base class only, not subclasses). I mean you can instance the set using Collections of type Object, like HashSet<Object> but not with HashSet<String>. You can of course add elements of any type to the set, but just because it happens that everything is an Object or a subclass of Object. If the set were defined as Set, you can only add Numbers and subclasses of Number, and nothing more.


The difference between Set<Object> and Set<?> is that a variable of type Set<?> can have a more specific generic type assigned to it, as in:

Set<?> set = new HashSet<Integer>();

while Set<Object> can only be assigned Set<Object>:

Set<Object> set = new HashSet<Integer>(); // won't compile

The Set<Object> is still useful, since any object can be put into it. It is much like the raw Set in that sense, but works better with the generic type system.