2

What is the difference between the last two statements ? why does one statement work and the other doesn't ?

package Main;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {

    public static void printIt(List<Object> l)
    {
        System.out.println(l);
    } 

    public static void main(String[] args) {
        List<String> l =new ArrayList<>();
        l.add("A");

        //what is the differance between the following statments ? 

        printIt(Arrays.asList("A")); // it compiles successfully
        printIt(l); // it does not compile

    }
}
Igoranze
  • 1,506
  • 13
  • 35
  • 1
    Possible duplicate of [Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?](http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicitly-p) – Tom Jun 27 '16 at 12:54
  • List l=new ArrayList<>(); does not compile anyway because the ArrayList has no Type declared. – Jankapunkt Jun 27 '16 at 12:56
  • 1
    @Jankapunkt It does compile, this is the diamond operator introduced in Java 7. – Tunaki Jun 27 '16 at 12:57
  • `List` is not assignable to `List`, e.g. if you have `List` you can add e.g. value 3 which doesn't make sense for list of strings – csharpfolk Jun 27 '16 at 13:02
  • @csharpfolk : according to what you have just said both statement should not compile !! –  Jun 27 '16 at 13:05
  • @Nour.kotmawi why, compiler can use target type to infer type of `Arrays.asList("A")` expression just like in `List x = Arrays.asList("A")` – csharpfolk Jun 27 '16 at 13:18
  • 1
    @Nour.kotmawi call `printIt(Arrays.asList("A"));` defaults to `printIt(Arrays.asList("A"));` not to `printIt(Arrays.asList("A"));` – csharpfolk Jun 27 '16 at 13:24

4 Answers4

4

The problem is printIt() method expects List<Object> as parameter but we are passing List<String> to it, that's why there is compilation problem. Replace the parameter List in method printIt() as below:

    public static void printIt(List<? extends Object> l)
    {
        System.out.println(l);
    }

Now both will compile,

pbajpai
  • 1,303
  • 1
  • 9
  • 24
  • @Nour, I am using Java-7, and on my machine, both lines are not compiling and giving the same compilation error, saying that : printIt() requires List and List cannot be applied, – pbajpai Jun 27 '16 at 13:20
  • You get that because type inference was still a bit weak in Java 7. It has been improved in Java 8. You need to use `printIt(Arrays.asList("A"));` instead to work with Java 7. – Tom Jun 27 '16 at 13:33
3

This is because your method expects a List<Object> and you give it a List<String>.

As weird as it can appear the first time you read this, a List<String> is not a List<Object>.

In your example, you don't modify the content of the lists but let's imagine a method where you want to add a new element.

public static void addIt(List<Object> l, Object o)
{
    l.add(o);
} 
public static void main(String[] args) {
    List<String> l =new ArrayList<>();
    l.add("A");
    addIt(l, new Integer(1)); // What?! you want to add an Integer to a List<String>!!!!
}

You will have to use wildcards (?) or to solve your problem so your your List .

public static void printIt(List<?> l) //or printIt(List<? extends Object> l)
{
    System.out.println(l);
} 

The case of printIt(Arrays.asList("A")) is a bit different. It is due to the fact that the generic is determined dynamically, by type inference on a generic method.

List<Object> l = Arrays.asList("A"); //this is valid, the generic type is determined from the type we expect in this declaration.
C.Champagne
  • 5,381
  • 2
  • 23
  • 35
2

To help you grok this, here is another compiling code example that demonstrated type inference from return type:

import java.util.*;

// our main class becomes a file but the main method is still found
public class HelloWorld
{
  public static void main(String[] args)
  {
    foo(createList()); // T must be Object
  }

  private static void foo(List<Object> objs) { }

  private static <T> List<T> createList() { return new ArrayList<>(); }
}
csharpfolk
  • 4,124
  • 25
  • 31
0

so as @csharpfolk mentioned it is all about "Type Inference"!
the following document could be helpful to understand the idea behind that!

https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html