【问题标题】:Type difference between similar ArrayList declarations类似 ArrayList 声明之间的类型差异
【发布时间】:2013-12-06 05:20:48
【问题描述】:

我正在尝试使用以下方式创建 List 实例:

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

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

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

只有listOne 被初始化为java.util.ArrayList,但listTwolistThree 不是。

初始化listTwo和listThree会发生什么以及如何更好地理解它?

我的测试示例如下:

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());

    }
}

它在控制台的输出如下:

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 

【问题讨论】:

标签: java list arraylist


【解决方案1】:

在此创建类 ArrayList 的新实例

List&lt;String&gt; listOne = new ArrayList&lt;String&gt;();

在这里你定义一个从 ArrayList 扩展的匿名类并创建它的新实例

List&lt;String&gt; listTwo = new ArrayList&lt;String&gt;(){};

在这里你定义了另一个匿名类,它从 ArrayList 扩展并在初始化块中声明并创建它的实例

List&lt;String&gt; listThree = new ArrayList&lt;String&gt;() {{}};

【讨论】:

    【解决方案2】:

    符号new ArrayList&lt;String&gt;(){}; 实例化一个扩展ArrayList 的匿名类的对象。

    这就是为什么您的第二个和第三个变量的classTest$1Test$2(这就是JVM 命名匿名类的方式)

    【讨论】:

      【解决方案3】:
      List<String> listTwo = new ArrayList<String>(){};
      

      这会创建一个扩展ArrayList&lt;String&gt;anonymous class。如果您执行listTwo instanceof ArrayList,您会发现它实际上是一个ArrayList(嗯,它的一个子类)。就像你做了以下课程:

      private class SomeClass extends ArrayList<String>
      {
      }
      

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

      这会像以前一样创建一个匿名类,但带有 initialization block(恰好是空的)。就像你创建了这个类:

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

      这可以以clever-but-confusing 的方式使用,例如

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

      正如您所料,这会创建一个新列表并在其中添加“hello”。我建议不要这样做,因为其中的“令人困惑”的部分。

      但是,在您的示例中,所有类的功能都相同,因此您应该使用:

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

      【讨论】:

      • 感谢您的解释。这是有道理的。
      【解决方案4】:

      后两者是ArrayList 的匿名子类。在大括号内,您可以覆盖通常的原始类的行为,就像使用普通继承一样。

      例如:

      List<String> listTwo = new ArrayList<String>(){
          this.add("hello user!"); //list is automatically initialized with one element
          @Override
          public int size() {
              return super.size() + 1; //this naughty list lies about its size!
          }
      };
      

      第三个与第二个几乎相同,只是在匿名类内部有一个空代码块。

      【讨论】:

        【解决方案5】:

        list1 是一个ArrayListlist2ArrayList 的匿名子类。 list3 是一个带有初始化块的匿名子类。这意味着涉及三个类,其中两个是匿名的,称为Test$1Test$2。 1 和 2 指的是它们的声明顺序,Test 指的是封闭类。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-10-05
          • 1970-01-01
          • 2020-07-18
          • 2011-10-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多