34

Consider below method doSomething(List<Object>) which accepts List<Object> as parameter.

private void doSomething(List<Object> list) {
    // do something
}

Now consider below code snippet which tries to call doSomething() where I try to pass List<String> to doSomething()

List<Object> objectList;
List<String> stringList;

doSomething(stringList); // compilation error incompatible types
doSomething(objectList); // works fine 

Even below code throws compilation error

objectList = stringList;  // compilation error incompatible types

My question is why List<String> can not be passed to a method which accepts List<Object>?

Nerssi
  • 53
  • 6
user3374518
  • 1,359
  • 3
  • 11
  • 11

7 Answers7

53

Because while String extends Object, List<String> does not extend List<Object>

Update:
In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar>.

This is because collections do change. In your case, If List<String> was a subtype of List<Object>, then types other than String can be added to it when the list is referenced using its supertype, as follows:

List<String> stringList = new ArrayList<String>;
List<Object> objectList = stringList;// this does compile only if List<String> where subtypes of List<Object>
objectList.add(new Object());
String s = stringList.get(0);// attempt to assign an Object to a String :O

and the Java compiler has to prevent these cases.

More elaboration on this Java Tutorial page.

Ahmad Y. Saleh
  • 3,309
  • 7
  • 32
  • 43
17

You could put an object of a wrong type into the list IF this worked:

private void doSomething(List<Object> list) {
    list.add(new Integer(123)); // Should be fine, it's an object
}

List<String> stringList = new ArrayList<String>();
doSomething(stringList); // If this worked....
String s = stringList.get(0); // ... you'd receive a ClassCastException here
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • 2
    P.S.: The supertype/subtype relationships with generics are explained very well at http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ207 – Marco13 Mar 03 '14 at 13:50
11

This generic question in Java may look confusing to any one who is not very familiar with Generics as in first glance it looks like String is object so List<String> can be used where List<Object> is required but this is not true. It will result in compilation error.

It does make sense if you go one step further because List<Object> can store anything including String, Integer etc but List<String> can only store Strings.

Also have a look at: Why not inherit from List<T>?

Community
  • 1
  • 1
Shishir Kumar
  • 7,981
  • 3
  • 29
  • 45
  • 5
    The problem is not exactly that the called can store anything: the real problem is, if it would be allowed, the caller would not be sure of having a String instance, so would have to handle it as in pre-generics days (instanceof operator). – robermann Mar 03 '14 at 11:18
5

The reason for these limitations have to do with variance considerations.

Take the following code:

public void doSomething(List<Object> objects)
{
  objects.add(new Object());
}

Expanding your example, you could try to do the following:

List<String> strings = new ArrayList<String>();
string.add("S1");

doSomething(strings);

for (String s : strings)
{
  System.out.println(s.length);
}

Hopefully it's obvious why this would break if the compiler allowed this code to be compiled (which it doesn't) - a ClassCastException would occur for the second item in the list when trying to cast the Object to a String.

To be able to pass generalized collection types, you need to do this:

public void doSomething(List<?> objects)
{
  for (Object obj : objects)
  {
    System.out.println(obj.toString);
  }
}

Again, the compiler is watching your back and were you to replace the System.out with objects.add(new Object()) the compiler wouldn't allow this because objects could have been created as List<String>.

For more background on Variance see the Wikipedia artical Covariance and contravariance

Nick Holt
  • 33,455
  • 4
  • 52
  • 58
3

It is sometimes expected that a List<Object> would be a supertype of a List<String> , because Object is a supertype of String .

This expectation stems from the fact that such a type relationship exists for arrays:

Object[] is a supertype of String[] , because Object is a supertype of String . (This type relationship is known as covariance .)

The super-subtype-relationship of the component types extends into the corresponding array types.

No such a type relationship exists for instantiations of generic types. (Parameterized types are not covariant.)

Check here for more details

Abimaran Kugathasan
  • 31,165
  • 11
  • 75
  • 105
3

From Java Tutorials of Generics:

Let's test your understanding of generics. Is the following code snippet legal?

List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2 

Line 1 is certainly legal. The trickier part of the question is line 2. This boils down to the question: is a List of String a List of Object. Most people instinctively answer, "Sure!"

Well, take a look at the next few lines:

lo.add(new Object()); // 3
String s = ls.get(0); // 4: Attempts to assign an Object to a String!

Here we've aliased ls and lo. Accessing ls, a list of String, through the alias lo, we can insert arbitrary objects into it. As a result ls does not hold just Strings anymore, and when we try and get something out of it, we get a rude surprise.

The Java compiler will prevent this from happening of course. Line 2 will cause a compile time error.

Source : Generics and Subtyping

earthmover
  • 4,395
  • 10
  • 43
  • 74
0

If you are not sure what datatype it will take in you can make use of Generics in Java as follows

public static void doSomething(List<?> data) {

}

public static void main(String [] args) {
    List<Object> objectList = new ArrayList<Object>();
    List<String> stringList = new ArrayList<String>();
    doSomething(objectList);
    doSomething(stringList);
}

But while using the data, you will be required to specify proper data type as a Type Cast

rsakhale
  • 1,018
  • 13
  • 26