Reputation: 69
Please explain what are the differences between List
- raw type and List<Object>
.
The below code gives run time error:
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42));
String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
And this gives compile time error:
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42));
String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List<Object> list, Object o) {
list.add(o);
}
Upvotes: 3
Views: 371
Reputation: 19936
However it looks the same, it is not.
List
(raw type) does not care what you insert into it.
List<String>
is not compatible with List<Object>
. You may do this:
String s = "Hello";
Object o = s;
but you must not do this:
List<String> ls = ...;
List<Object> lo = ls; // Compilation error!
Your example is a good illustration why the Java language does not allow it. By allowing such an assignment a malicious method would be able to put anything into a list which a client consider as a list of Strings.
Consider the following code:
public void method changeObject(Object o) {
o = 42;
}
public void method changeList(List<Object> lo) {
lo.add(42);
}
...
String str = "Hello";
changeObject(str);
// Here it is still safe to use str, its value has not been modified
String str2 = str; // OK
List<String> list = new ArrayList<>();
changeList(list); // it is not allowed, but let's assume it is
// here the list variable would violate its contract - everybody has a right
// to expect it is a list of Strings
String str3 = list.get(0); // Ouch! :(
Upvotes: 0
Reputation: 246
Java has not inheritance for parametric types. So List<Integer>
is not a subclass of List<Object>
, then you can't use List<Integer>
or List<String>
as parameter for the unsafeAdd
method. But you can write:
private static <T> void unsafeAdd(List<T> list, T o) {
list.add(o);
}
and safelly call it:
List<String> strings = ...
unsafeAdd(string, "42");
and get error while:
List<String> strings = ...
unsafeAdd(strings, 42); // error!
You can see more information in the Oracle Generics Tutorial, Generics, Inheritance, and Subtypes
Upvotes: 2
Reputation: 88707
As Peter already said, in the first example you're telling the compiler to use raw types and thus not to perform any checks on the list. Thus it will allow you to add any object to the passed list, even if it is defined to just allow for strings.
In the second example you tell the compiler that it should assume the list to allow any object, thus the add operation would compile. However, passing a List<String>
as a List<Object>
is not allowed, since the list of strings has more specific restrictions than the contents just being objects and hence the compiler knows that this is unsafe and error-prone.
If you'd define the parameter to be List<? extends Object> list
instead, the compiler would accept passing a List<String>
since you tell it that the minimum requirement is that the list must accept objects, but it could also impose harder constraints. However, the add operation wouldn't compile now, since the compiler doesn't know if there are harder constraints and if so what these constraints are. Hence it can't assure that the add operation is safe and refuses to compile that line.
Upvotes: 0
Reputation: 15770
In the first case you pass unparametrized List to unsafeAdd, so compiler has no way to figure out something is wrong.
Passing List<String>
to method which expects List
is ok. Adding object to List
is ok.
In the second case, you are passing List<String>
to method which expects List<Object>
- and that's not ok. Because this way you are implicitely allowing to add non-String to List<String>
- compiler can figure it out in this case and raises an error.
Upvotes: 0
Reputation: 533492
In the second case, you are doing something the compiler can workout is not safe. In the first case, you are using raw types so the compiler doesn't perform the same checks.
Upvotes: 7