List vs List<Object>
List
is a list of some type you don't know. It could be a List<String>
, List<Integer>
, etc.
It's effectively equivalent to List<?>
, or List<? extends Object>
, except that it doesn't document that fact. It's only supported for backwards compatibility.
List<Object>
is a list of Objects. Any object of any type can be put inside it, contrary to a List<String>
, for example, which only accepts strings.
So no, they're not the same thing.
Why do we lose type safety when using
List
and not while usingList<Object>
? Aren't they basically the same thing?
No they are not the same thing.
If you are providing an API,
class API {
static List<Object> getList() { ... }
static void modifyList(List<Object> l) { ... }
}
and a client uses it improperly
List<Integer> list = API.getList();
API.modifyList(list);
for (Integer i : list) { ... } // Invalid
then when your API specifies List<Object>
they get a compile-time error, but they don't when API.getList()
returns a List
and API.modifyList(list)
takes a List
without generic type parameters.
EDIT:
In comments you mentioned changing
void func(List<Object> s, Object c) { s.add(c); }
to
void func(List s, Object c) { s.add(c); }
so that
func(new List<String>(), "");
would work.
That is violating type safety. The type-safe way to do this is
<T> void func(List<? super T> s, T c) { s.add(c); }
which is basically saying that func
is a parameterized function that takes a List
whose type can be any super class of T, and a value of type T, and adds the value to the list.
A List<Object>
isn't really any more typesafe than a List
. However, the Object
in the code does imply intent. When someone else looks at it later, they can see that you purposefully chose Object
as the type, rather than wondering if you just forgot to put a type or are storing something else and typecasting it elsewhere.
Since code gets read more than it gets written, hints at the intent of the code can be very valuable later on.