Varun Achar
Varun Achar

Reputation: 15119

List vs List<Object>

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

Answers (6)

Anil Singh
Anil Singh

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

Mike Samuel
Mike Samuel

Reputation: 120576

Why do we lose type safety when using List and not while using List<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

user541686
user541686

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

RHSeeger
RHSeeger

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

Yishai
Yishai

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

Sean Owen
Sean Owen

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 Strings 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

Related Questions