Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<Object> variable being assignment compatible with other generic Lists like List<String> in Java

I've been trying to get my head around java generics for the last few days. From what I understand, Java generics are not covariant so List<Object> is not assignment compatible with other generics Lists

But here in the following program, nameAndPhone.collect() method returns a List of type List<NamePhone> and when I replace reference variable List<NamePhone> npList with List<Object> npList the program still compiles without warnings.

I tried this with a similar method returning List<String> as well, and using List<Object> reference variable did not result in any error.

Why is List<Object> assignment compatible with List<NamePhone> here?

import java.util.*;
import java.util.stream.*;

class NamePhoneEmail
{
    String name;
    String phonenum;
    String email;

    NamePhoneEmail(String n, String p, String e)
    {
        name = n;
        phonenum = p;
        email = e;
    }
}

class NamePhone
{
    String name;
    String phonenum;

    NamePhone(String n, String p)
    {
        name = n;
        phonenum = p;
    }
}

public class CollectDemo
{
    public static void main(String[] args)
    {

        ArrayList<NamePhoneEmail> myList = new ArrayList<>();
        myList.add(
            new NamePhoneEmail("Larry", "555-5555", "[email protected]"));

        myList.add(
            new NamePhoneEmail("James", "555-4444", "[email protected]"));

        Stream<NamePhone> nameAndPhone =
            myList.stream().map((a) -> new NamePhone(a.name, a.phonenum));

        List<NamePhone> npList = nameAndPhone.collect(Collectors.toList());
    }
}
like image 921
Arjun Avatar asked May 23 '18 19:05

Arjun


People also ask

Can we assign list of String into a list of object variable?

Any Collection can be passed as an argument to the constructor as long as its type extends the type of the ArrayList , as String extends Object . The constructor takes a Collection , but List is a subinterface of Collection , so you can just use the List<String> .


1 Answers

The type parameter of what gets returned by the collect method does not need to be the same type as the stream. Here, the result type R is different than the stream type T.

<R,A> R collect​(Collector<? super T,A,R> collector)

Next, Java 8 and later have improved target type inference. That means that the compiler will use the target type to infer type parameters. In this case, when you have

List<NamePhone> npList = nameAndPhone.collect(Collectors.toList());

the compiler sees NamePhone and infers that type as the type parameter R to collect (and to Collectors.toList()).

When you change it to

List<Object> npList = nameAndPhone.collect(Collectors.toList());

the compiler sees Object and infers that type as the type parameter R.

This compiles and works as expected, because you can certainly place any kind of object, including a NamePhone, into a List<Object>.

It's not that a List<NamePhone> is assignment compatible with List<Object>. What is happening is that when you say List<Object> npList, there never was a List<NamePhone>, only a List<Object>.

Note that the objects in your list will have a runtime type of NamePhone in either case.

like image 167
rgettman Avatar answered Oct 19 '22 20:10

rgettman