Type difference between similar ArrayList declarations

I am trying to create List instance using the following ways:

List<String> listOne = new ArrayList<String>();

List<String> listTwo = new ArrayList<String>(){};

List<String> listThree = new ArrayList<String>() {{}};

Only listOne is initialized as java.util.ArrayList, but listTwo and listThree are not.

What happens in initializing listTwo and listThree and how to understand it better?

My test example is as follows:

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

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

        List<String> listOne = new ArrayList<String>();

        List<String> listTwo = new ArrayList<String>(){};

        List<String> listThree = new ArrayList<String>() {{}};

        System.out.printf("listOne.getClass() == listTwo.getClass() is %b \n",
                listOne.getClass() == listTwo.getClass());

        System.out.printf("listOne.getClass() == listThree.getClass() is %b \n",
                listOne.getClass() == listThree.getClass());

        System.out.printf("listThree.getClass() == listTwo.getClass() is %b \n",
                listThree.getClass() == listTwo.getClass());

        System.out.printf("listOne.getClass() is %s \n",listOne.getClass());

        System.out.printf("listTwo.getClass() is %s \n",listTwo.getClass());

        System.out.printf("listThree.getClass() is %s \n",listThree.getClass());

    }
}

Its output in console is as follows:

listOne.getClass() == listTwo.getClass() is false
listOne.getClass() == listThree.getClass() is false
listThree.getClass() == listTwo.getClass() is false
listOne.getClass() is class java.util.ArrayList
listTwo.getClass() is class Test$1
listThree.getClass() is class Test$2


List<String> listTwo = new ArrayList<String>(){};

This creates an anonymous class that extends ArrayList<String>. If you do listTwo instanceof ArrayList, you'll see that it is, in fact, an ArrayList (well, a subclass of one). It's like you made the following class:

private class SomeClass extends ArrayList<String>
{
}


List<String> listThree = new ArrayList<String>() {{}};

This creates an anonymous class like before, but with an initialization block (which happens to be empty). It's like you created this class:

private class SomeClass2 extends ArrayList<String>
{
    {
        // some code could go here...
    }
}

This could be used in a clever-but-confusing way, e.g.

List<String> listThree = new ArrayList<String>()
{{
    add("hello");
}};

This, as you might expect, creates a new list and adds "hello" to it. I'd recommend against this, due to the "confusing" part of that.

In your example, though, all the classes function the same, so you should just use:

List<String> listOne = new ArrayList<String>();