使用对象的n个克隆创建java集合

使用对象的n个克隆创建java集合,java,collections,Java,Collections,在Java中,是否有一种单行方式来创建一个集合,该集合使用对象的n个克隆进行初始化 我想要这个的等价物: foo=vector(10) C++,创建10个不同的空向量 [[]对于范围内的i(10)]Python,一个由10个不同的空数组组成的数组 Array.new(10){[]}Ruby,与Python相同 在Java中,我只找到了 new ArrayList<ArrayList<Integer> >(Collections.nCopies(10, new Arra

在Java中,是否有一种单行方式来创建一个集合,该集合使用对象的n个克隆进行初始化

我想要这个的等价物:

  • foo=vector(10) C++,创建10个不同的空向量
  • [[]对于范围内的i(10)]
    Python,一个由10个不同的空数组组成的数组
  • Array.new(10){[]}
    Ruby,与Python相同
在Java中,我只找到了

new ArrayList<ArrayList<Integer> >(Collections.nCopies(10, new ArrayList<Integer>()))

新建ArrayList?

如果您使用的是Java 8,则可以使用其流:

Stream.generate(ArrayList<Integer>::new)
    .limit(10).collect(Collectors.toList());
Stream.generate(ArrayList::new)
.limit(10).collect(collector.toList());
该方法采用一个知道如何生成值的函数,并生成这些值的无限流(每个值都是通过再次调用供应商获得的,因此它们都不同于
Collections.nCopies()
)。在流上放置一个
limit()
,然后将结果收集到一个列表中,从而生成一个不同条目的列表。

  • vector=新向量(10)
    在语法上是不正确的,但是假设你的意思是
    vectorfoo(10)。您正在使用,它将初始化容器大小,然后将每个元素初始化为
    value\u type
    参数的副本(如果未指定任何内容,则为默认构造函数)。这将使用一个循环

  • [[]用于范围(10)中的i
    数组。新的(10){[]}
    只是在1行上执行循环,并在中复制空列表类型结构

正如您所指出的,
nCopies
方法不是等效的,因为结果是不可变的,并且您没有创建副本(或克隆)。访问每个索引时使用对同一元素的引用。有关参考信息,请参阅

有些困难是不能保证像C++那样的默认构造函数,语法与大多数脚本语言有点不同。这可能是一个很好的机会,让我们花一点时间来了解幕后发生了什么,以确保您的解决方案不会做过多的工作。要问自己的一些后续问题:

  • 除了循环之外,还有什么其他的构造?我相信在某种程度上会有一个循环
  • 您真的希望如何初始化外部ArrayList中的ArrayList对象?例如,您希望它们是多大尺寸?它们最初是否应该填充任何内容?你预计它们会增长到多大?它们是否需要统一的尺寸,或者对于一些更大/更小的尺寸是否有意义?懒洋洋地初始化这些列表有意义吗
为了帮助回答这些问题,最好为用例编写自己的通用静态初始值设定项。在您完成简单用例之后,如果您的用例发生了变化,那么使用初始化内部列表可能会使您的解决方案更加通用。正如你所看到的,有很多问题需要考虑,在简单的情况下,你可能会得到一些类似的东西:

public static <T> List<List<T>> newListofLists(int outerSize, int innerSize, T value) {
    List<List<T>> outer = new ArrayList<List<T>>(outerSize);
    for (int i = 0; i < outer.size(); ++i) {
        List<T> inner = new ArrayList<T>(innerSize);
        outer.add(inner);
        for (int j = 0; j < inner.size(); ++j) {
            inner.add(value);
        }
    }
    return outer;
}
公共静态列表newlistofList(int-outerSize、int-innerSize、T值){
列表外部=新的ArrayList(outerSize);
对于(int i=0;i
然后可以使用该命令在一行中初始化列表,如:

List<List<Integer>> myList = newListofLists(10, 5, -1);
List myList=newListofLists(10,5,-1);

尽管引入了Java8,但遗憾的是没有像
nCopies
那样简洁的一行程序。老实说,我不知道为什么。(尽管@DavidConrad已经表明,
Stream
可以做到这一点。)

您可以自己轻松创建一个,例如:

public static <E, L extends List<? super E>> L fill(
        L list, Supplier<E> sup, int n) {
    for(; n > 0; --n)
        list.add(sup.get());
    return list;
}
但它是一个
void
方法,因此不能在单个语句中使用。(个人评论:为什么JavaAPI不能是流体?)


在Java8之前,没有一个库方法来实现这一点,创建一个库方法更麻烦。由于
clone
受到保护,因此不能一般调用它。反射可以做到这一点,但反射相当麻烦。

对于那些想要传递构造函数参数的人(这在前面提到的和供应商中是不可能的)-您可以使用以下方法(我不知道是否有更好的解决方案,但它至少满足了我的需要):

final List result=IntStream.range(0,n)
.mapToObj(索引->新建MyObject(…)
.collect(Collectors.toList());
然而,您将使用要填充列表的元素数替换
n
,并分别使用type和ctor调用替换
MyObject
newmyobject(…)


这将创建一个从0到n(n互斥)的整数流,将每个“索引”映射到lambda expr返回的任何对象。在
mapToObj
中,最后将流转换为一个列表,其中将包含
n
不同的
MyObject
实例,谢谢!我纠正了C++语法。关于你的其他评论:我不一定认为列表理解是一个循环——尽管它们在语义上是等价的。C++版本可以很好地使用窗帘后面的MEMCPY,这是一个循环(或者一个特殊的CPU指令),但也有一些不同。无论如何这更多的是关于简洁的代码,而不是其他考虑因素。。。但是你能引起他们的注意是很好的。你可以用它来代替内部循环。但是,这可能会受到堆内存的限制。使用direct ByteBuffer可以直接使用memcpy之类的操作。啊,我没想到你可以编写
ArrayList::new
。这在代码中简化了我的供应商+1,谢谢。@DavidConrad请随意从我这里偷走它。。)就这么做了。这就是我喜欢StackOverflow的地方。如果你需要索引的话,这当然是最好的
List<List<Integer>> list = ArrayUtils.fill(
    new ArrayList<>, ArrayList<Integer>::new, 10
);
Integer[] oneToTen = new Integer[10];
Arrays.setAll(oneToTen, i -> i + 1);
List<Integer> asList = Arrays.asList(oneToTen);
final List<MyObject> result = IntStream.range(0, n)
   .mapToObj(index -> new MyObject(...))
   .collect(Collectors.toList());