【问题标题】:Initializing List<T> with given number of nulls without loop?在没有循环的情况下使用给定数量的空值初始化 List<T>?
【发布时间】:2011-11-22 07:06:03
【问题描述】:

可以将List&lt;T&gt; 初始化为包含给定数量的nulls,其中T 是列表所属类的类型参数吗?我当然可以通过循环来做到这一点,但想知道是否可以不使用。

List<T> myList = new ArrayList<T>(numEls);

创建一个给定容量的列表,但大小为 0,因此 myList.get(x) 对所有 x 都失败,因此也是如此,例如myList.set(numEls-1,null).

myList = Arrays.asList(new T[numEls]);

不编译,并且

 myList = (List<T>) Arrays.asList(new Object[numEls]);

在 Eclipse 中编译(带有 Unchecked cast 警告),但不使用 javac。


更新:感谢您的回答!然而,我发现了另一个非常简短的解决方案,接近我上面的最后一次尝试,它可以在 eclipse 和我们的自动构建系统中编译:转换数组,而不是列表!

myList = Arrays.asList((T[]) new Object[numEls]);

【问题讨论】:

  • 为什么需要在没有循环的情况下解决这个问题?这很不合理。只需拨打ensureCapacity,然后拨打nadd(null)
  • @RolandIllig 我不需要在没有循环的情况下解决它,我只是想知道它是否可能。
  • 你为什么要用更复杂的东西代替它来避免单行循环?如果你知道你想要的尺寸可以包裹一个Object[]
  • 也不是解决方案:但您可以编写List 的实现,它表现为一个稀疏列表并为所有get(i) | i &lt; size() 返回null。恕我直言,“初始化List”没有意义,因为List 只是一个接口。
  • @AlistairIsrael 公平点。我的意思是“初始化实现列表的东西”,可以是普通的ArrayList,也可以是Arrays.asList(...)返回的列表类型,或者其他,以效果最好的为准。

标签: java list initialization


【解决方案1】:

如果您不需要改变列表...

List<T> result = Collections.nCopies(num, (T) null);

...或交替

List<T> result = new ArrayList<T>(Collections.nCopies(num, (T) null));

【讨论】:

  • 请解释第二个选项。当我尝试访问列表时使用它会给我 NullPointerException。我的代码 List psDTOs = new ArrayList(Collections.nCopies(15, (ProfileSectionDTO) null));
  • 您是如何尝试访问该列表的?它充满了空值。
  • 是的。愚蠢的我。谢谢。
【解决方案2】:

不是真正的解决方案,但您想避免循环。

void fillNullList(List<T> list, count) {
   if (count > 0) {
       list.add(null);
       fillNullList(list, count - 1);
   }
}

说真的,为什么要避免循环?可能,您想要一个复杂度为 O(1) 的解决方案,而不是复杂度为 O(n) 的解决方案,无论是否使用循环。

【讨论】:

    【解决方案3】:

    流的新选项:

    List resultColumn = IntStream.range(0, 10000).mapToObj(i -> null).collect(Collectors.toList());

    【讨论】:

      【解决方案4】:

      如果你想要ArrayList,你可以使用反射来作弊

      ArrayList<T> myList = new ArrayList<T>(numEls);
      Field f = ArrayList.class.getField("size");//cache this
      f.setAccessible(true);
      f.setInt(myList, numEls);
      

      【讨论】:

      • 没有 Class 对象参数或不必要的数组副本的解决方案!谢谢你。 Nitpick:getField(String) 仅用于公共字段,getDeclaredField 是必需的。
      • 这看起来很危险;因为它根本不更新(假定的)后备数组,所以以后可能会抛出一个 AIOOBE - 例如当内部容量仍然足够时,add 之后会发生什么?这不是我想要处理的有时会咬我的错误。
      • @pst note 我使用了容量构造函数,所以它会匹配,但它确实是一个小众应用
      • 干预外国班级的内部结构在很多层面上都是错误的。很少有例外情况是可以辩护的。避免循环显然不是其中之一。
      【解决方案5】:

      你可能想要的是这样的......

      final int maxSize = 50;
      
      List<T> v = new Vector<T>() {{setSize(maxSize);}};
      

      向量允许您设置大小,用null 填充它们。

      【讨论】:

      • 不错的一个!我会使用 Vector 来初始化一个 ArrayList,类似于 List&lt;T&gt; v = new ArrayList&lt;T&gt;(new Vector&lt;T&gt;() {{setSize(maxSize);}}); 但很好的想法。
      • 确实很有趣!据我所见,使用额外的变量而不是双括号初始化,这里没有隐藏循环:Vector&lt;T&gt; tmp = new Vector&lt;T&gt;(maxSize); 创建一个所需大小的内部数组,tmp.setSize(maxSize); 确保向量的toArray() 返回一个数组只是那个大小,并且这个数组被@Paul 的建议中的ArrayList 构造函数使用! (不过,该数组不必要地复制了一次。)
      • 确实,Vector 经常被开发人员忽视,因为它只是 ArrayList 的同步版本,并且出于同样的原因不予考虑,但它确实启用了像这样的小宝石。
      【解决方案6】:

      您需要使用反射来实例化支持数组T[],使用Array.newInstance()

      public static <T> List<T> getListWithNulls(Class<T> componentType, int length) {
         T[] array = (T[])Array.newInstance(componentType, length);
         return new ArrayList<T>(Arrays.asList(array));
      }
      

      如你所见,这需要引用代表T类型的Class&lt;T&gt;对象:

      List<String> strListWithNulls = getListWithNulls(String.class, 100);
      

      还要确保不要混淆此处使用的 java.lang.reflect.Arrayjava.util.Arrays 类。

      最后,请注意,反射比仅使用循环要慢得多。

      【讨论】:

      • 为什么需要新的 ArrayList? Arrays.asList 已经返回了一个 List 实例。
      • @dmeister - That method 返回由数组支持的 List。为了有一个可调整大小的列表,需要将其复制到另一个 List 实现。
      • @KublaiKhan 谢谢!事实上,dmeister 的建议符合目的,因为列表大小在我的情况下是固定的(但我没有在问题中这么说)。无论如何,我希望有一个代码比循环更短的解决方案,但如果我做不到,我不会责怪信使。 ;-)
      【解决方案7】:

      我只会使用循环,它更简单,也可能更快。

      List<T> list = 
      while(list.size()<size) list.add(null);
      

      您使用的任何其他方法都可能为您使用循环。如果这没问题,只需编写自己的方法来隐藏所使用的循环。

      【讨论】:

        【解决方案8】:

        试试这个:

        List<String> list = new ArrayList<String>(Arrays.asList(new String[100]));
        for(String string : list){
            System.out.println(string);
        }
        

        好吧,你可以写一个层次结构:

        class Base<T>{
            protected List<T> list; 
        
            public List<T> getList(){
               return list;
            }
        }
        
        class Child extends Base<String>{
            public Child(){
                list = new ArrayList<String>(Arrays.asList(new String[100]));
            }
        }
        

        可以按以下方式使用:

        Base<String> base = new Child();
        base.getList();
        

        【讨论】:

        • 但我不想要List&lt;String&gt;,我想要一个List&lt;T&gt;,其中对T 一无所知(至少与列表创建无关)。
        • 这篇文章没有回答这个问题。显然,具体类型是可能的,但@arme.b 想为 generic 类型编写代码。
        • 您的更新有什么变化?您仍然没有在需要的地方创建列表,而是在具体类型已知的地方(这不是我的类或其任何子类)。
        • 我不恳求您接受我的回答。这种方式在某些情况下可以使用,它使用抽象,而不是特定类型。
        【解决方案9】:

        我做的是

        MyClass[] array = {new MyClass(), new MyClass(), new MyClass(), new MyClass(), new ProfileSectionDTO(), new MyClass()};
        List<MyClass> MyClassList = Arrays.asList(array);
        

        脏,但工作:)

        【讨论】:

          猜你喜欢
          • 2011-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-10
          • 1970-01-01
          • 2021-07-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多