What is the difference between ? and Object in Java generics?
?
(wildcard) is used to represent an unknown type in generic code, providing maximum flexibility. It enables methods to operate on sets of varying types.
Object
, on the other hand, is a type parameter that indicates a list can contain objects of any class, but lacks the type safety and specificity afforded by generics.
Wildcards are generally preferred in generic methods and classes where type invariance is necessary, whereas Object
though more lenient is less instructive about collection content or operation intention.
Delving into Flexibility and Type Safety
The Flexibility of Wildcards
Using ?
in generics permits interaction with a collection without being concerned about the particular type it contains. Such as, a HashMap<String, ?>
allows any value type, providing immense flexibility:
This is mainly useful when you only care about keys or if value types are heterogeneous.
Bounded Wildcards for Type Safety
By deploying ? extends T
or ? super T
, generics enhance type safety through type constraints. For example, List<? extends InputStream>
only takes in InputStreams or subtypes:
Here, the added advantage is that operations on the streamList can be conducted knowing everything within is an InputStream
.
Adopting the Get and Put Principle
Follow the "Get and Put Principle", use ? extends T
when you plan to extract values from a collection and ? super T
for adding values to it. This approach maintains strong type safety ensuring your intentions are clear.
Parsing Array Covariance vs. Generic Invariance
Covariance in Arrays
Java arrays are covariant. This means that an array of a subtype like (String[]
) can be assigned to an array of its supertype (Object[]
), but this could lead to runtime exceptions.
Invariance in Generics
However, generics are invariant, meaning a List<String>
is not considered a subtype of List<Object>
, and trading them yields compile-time errors, thus providing type safety at compile-time.
When Wildcards Should Take a Vacation
Writing to a Collection
Avoid using wildcards in generics when planning to both read and write a collection, as it jeopardizes type safety. Instead, be explicit about the type:
Narrower is Better for Method Parameters
Narrow down your generic type when designing methods to ensure maximum type safety and specificity:
Storage vs. Holding: Place for Everyone
Any Object's Storage
A Collection<Object>
can store any type of object, but can't be assigned from a collection of a specified type like Collection<String>
.
Holding Any Collection
Conversely, a Collection<?>
can retain any type of collection irrespective of its type parameters— the very portrait of polymorphism.
Enhancing Broader Compatibility with ?
A HashMap<?, ?>
can host any type for key and values— a useful feature when you need a map but the types are unknown or varied.
Driving Code Design with ? and Object
For Collection APIs
Appreciating the nuances between ?
and Object
is central for architecting flexible APIs for collections. Sticking with ?
, your collections can offer greater adaptability to differing types:
In Stream Operations
Working with Java Streams, employing wildcards keeps operations like filtering and mapping general, promoting fluency:
References
Was this article helpful?