Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between ? and Object in Java generics?

Tags:

java

generics

People also ask

Why do we use generics instead of object?

Generics could be used to develop a better solution using a container that can have a type assigned at instantiation, otherwise referred to as a generic type, allowing the creation of an object that can be used to store objects of the assigned type.

What is a generic object in Java?

The Java Generics allows us to create a single class, interface, and method that can be used with different types of data (objects). This helps us to reuse our code. Note: Generics does not work with primitive types ( int , float , char , etc).

What is the difference between T and object?

List<T> is a name of a generic class. List<Object> is its concrete instantiation. List<T> is not a class yet (it's a generic class, a template you can create concrete classes from but not a class you can use right away), List<Object> is a class. This doesn't make sense at all.

What is a generic object?

Generic objects are structures for storing and interacting with data in an app. They are the primary type of entity through which the engine provides access to the components of an app.


An instance of HashMap<String, String> matches Map<String, ?> but not Map<String, Object>. Say you want to write a method that accepts maps from Strings to anything: If you would write

public void foobar(Map<String, Object> ms) {
    ...
}

you can't supply a HashMap<String, String>. If you write

public void foobar(Map<String, ?> ms) {
    ...
}

it works!

A thing sometimes misunderstood in Java's generics is that List<String> is not a subtype of List<Object>. (But String[] is in fact a subtype of Object[], that's one of the reasons why generics and arrays don't mix well. (arrays in Java are covariant, generics are not, they are invariant)).

Sample: If you'd like to write a method that accepts Lists of InputStreams and subtypes of InputStream, you'd write

public void foobar(List<? extends InputStream> ms) {
    ...
}

By the way: Joshua Bloch's Effective Java is an excellent resource when you'd like to understand the not so simple things in Java. (Your question above is also covered very well in the book.)


Another way to think about this problem is that

HashMap<String, ?> hash1;

is equivalent to

HashMap<String, ? extends Object> hash1;

Couple this knowledge with the "Get and Put Principle" in section (2.4) from Java Generics and Collections:

The Get and Put Principle: use an extends wildcard when you only get values out of a structure, use super wildcard when you only put values into a structure, and don't use a wildcard when you both get and put.

and the wild card may start making more sense, hopefully.


It's easy to understand if you remember that Collection<Object> is just a generic collection that contains objects of type Object, but Collection<?> is a super type of all types of collections.


The answers above covariance cover most cases but miss one thing:

"?" is inclusive of "Object" in the class hierarchy. You could say that String is a type of Object and Object is a type of ?. Not everything matches Object, but everything matches ?.

int test1(List<?> l) {
  return l.size();
}

int test2(List<Object> l) {
  return l.size();
}

List<?> l1 = Lists.newArrayList();
List<Object> l2 = Lists.newArrayList();
test1(l1);  // compiles because any list will work
test1(l2);  // compiles because any list will work
test2(l1);  // fails because a ? might not be an Object
test2(l2);  // compiled because Object matches Object