Reputation: 15119
Why do we lose type safety when using List
and not while using List<Object>
? Aren't they basically the same thing?
EDIT: I found that the following gives a compilation error
public class TestClass
{
static void func(List<Object> o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
whereas this doesn't
public class TestClass
{
static void func(List o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
Why?
Upvotes: 15
Views: 7745
Reputation: 21
Type Erasure is one answer and the backward compatibility to pre Java 1.5 and tighter type check in case of first one.
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods. Insert type casts if necessary to preserve type safety. Generate bridge methods to preserve polymorphism in extended generic types. Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
Upvotes: 0
Reputation: 120576
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.
Upvotes: 5
Reputation: 210755
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.
Upvotes: 8
Reputation: 16282
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.
Upvotes: 3
Reputation: 91931
The reason you have a compiler warning when you use List
instead of List<Object>
is that when you have a List
the compiler doesn't know what type of List it is, so while you could treat it as a List<Object>
, the compiler can't ensure that at some other point in the code it wasn't set to reference a List<String>
and the type safety of the Generics cannot be checked. That is really the compiler warning here - it is saying it can't help ensure the type safety of the generics, and it won't happen at runtime either (until at some later point there is an actual cast in the code).
Upvotes: 1
Reputation: 66891
For purposes here, you could say they're the same thing. But presumably you almost never actually fill a List
with pure instance of Object
. They're String
s or something. In this example, List<Object>
is technically using generics but not really taking any advantage of it. So, it loses the compile-time type checking of generics.
Upvotes: 0