java 如何将一个 ArrayList 的内容移动到另一个?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10022441/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 23:18:17  来源:igfitidea点击:

How to move contents of one ArrayList to another?

javacollectionsarraylist

提问by sinharaj

Is there a way to move the entire contents of an ArrayList to another instance of ArrayList in O(1)?

有没有办法将 ArrayList 的全部内容移动到 O(1) 中的另一个 ArrayList 实例?

I.e.: only the reference to the backing array is passed from one instance to the other (elements are not copied one by one).

即:只有对后备数组的引用从一个实例传递到另一个实例(元素不会一一复制)。

For example:

例如:

ArrayList<String> a = new ArrayList<>(Arrays.asList("A", "B", "C"));
ArrayList<String> b = new ArrayList<>();
a.moveContentsTo(b);
// 'a' is now empty, while 'b' contains everything that 'a' did before and 'a != b'
// It is desired that the 'moveContentsTo' method is O(1)

Even better, is there an ArrayList#swapContents(ArrayList)method?

更好的是,有ArrayList#swapContents(ArrayList)什么方法吗?



Further explanation and use-case:

进一步解释和用例

Further explanation1: the references of 'a' and 'b' must not be exchanged. I am not looking for tmp = a; a = b; b = tmp;type of solutions.

进一步说明1:“a”和“b”的引用不得互换。我不是在寻找tmp = a; a = b; b = tmp;解决方案的类型。

Further explanation2: The operation must be ~O(1) in time.

进一步解释2:操作必须及时~O(1)。

The use-case: This is useful when an object wants to encapsulate a list constructed outside:

用例:当对象想要封装在外部构造的列表时,这很有用:

public class A {
    private ArrayList<String> items = new ArrayList<>();

    /**
     * This method takes the sole ownership of the contents. Whoever
     * passed the list from the outside will not be able to modify
     * contents of 'this.items' from outside the class.
     */ 
    public AnImmutableObject(ArrayList<String> items) {
        if (items != null) {
            items.moveContentsTo(this.items);
        }
    }

    /**
     * Other collections that do not provide the 'move' functionality
     * must be copied. If we just stored the reference to 'items' we
     * would break encapsulation as whoever called the constructor
     * still have write capabilities to the collection.
     */ 
    public A(Collection<String> items) {
        if (items != null) {
            this.items.addAll(items);
        }
    }

    public List<String> getItems() {
        return Collections.unmodifiableList(items);
    }
}

Notice that we want to avoid making a copy (to increase speed and decrease memory usage). The crucial bit is that the callee must lose the ability to modify the (now encapsulated) ArrayList.

请注意,我们希望避免复制(以提高速度并减少内存使用量)。关键的一点是被调用者必须失去修改(现在封装)的能力ArrayList

回答by Kiril

This should do it:

这应该这样做:

ArrayList<String> a = new ArrayList<>(Arrays.asList("A", "B", "C"));
ArrayList<String> b = a;
a = new ArrayList<>();

Conceptually speaking, ais now empty and bcontains what acontained before. There was a single assignment and no copying of data, which is about the fastest you can do it. Does that satisfy your requirement, or do you actually want ato still reference the same array except that the given array should now be empty?

从概念上讲,a现在是空的,b包含a之前包含的内容。有一个单一的分配,没有数据的复制,这是你能做到的最快的。这是否满足您的要求,或者您实际上是否a仍想引用相同的数组,只是给定的数组现在应该为空?

Update

更新

I don't believe that in C++ the time complexity for the move operation is O(1) either.It's also prudent to point out that "because classes in Java use reference semantics, there are never any implicit copies of objects in those languages. The problem move semantics solve does not and has never existed in Java." (see the answer by FredOverflow: C++ Rvalue references and move semantics)

我不相信在 C++ 中,移动操作的时间复杂度也不是 O(1)。指出“因为 Java 中的类使用引用语义,这些语言中从不存在任何对象的隐式副本。移动语义解决的问题在 Java 中不存在,也从未存在过。”(参见 FredOverflow 的回答:C++ 右值引用和移动语义

Is there a way to move the entire contents of an ArrayList to another ArrayList so that only the reference to the backing array is passed from one to the other (i.e., so that elements are not copied one by one).

有没有一种方法可以将一个 ArrayList 的全部内容移动到另一个 ArrayList 以便只有对支持数组的引用从一个传递到另一个(即,元素不会一个一个地复制)。

Given the above statement, then if you copy something from array ato array bin Java, both arrays will reference the same data. All that you do with move semantics in C++ is that you save the temporary object which needs to be created in order to make such a copy:

鉴于上述语句,如果您在 Java 中从一个数组复制a到另一个数组b,两个数组将引用相同的数据。在 C++ 中使用移动语义所做的一切就是保存需要创建的临时对象,以便进行这样的复制:

X foo();
X x;
// perhaps use x in various ways
x = foo();

The last one does:

最后一个是:

destructs the resource held by x,
clones the resource from the temporary returned by foo,
destructs the temporary and thereby releases its resource. 

Move semantics does:

移动语义:

swap resource pointers (handles) between x and the temporary,
temporary's destructor destruct x's original resource.

You save one destruct, but only in C++... the above problem does not exist in Java! See this article for more details on move semantics: http://thbecker.net/articles/rvalue_references/section_02.html

你省了一个destruct,但只能在C++中……Java中不存在上述问题!有关移动语义的更多详细信息,请参阅本文:http: //thbecker.net/articles/rvalue_references/section_02.html

回答by Eng.Fouad

@Lirik answer is greate +1. However, if you are looking for a real ArrayList#swapContents(ArrayList), here is how you can do it:

@Lirik 的回答很棒 +1。但是,如果您正在寻找真正的ArrayList#swapContents(ArrayList),您可以这样做:

public static void swapContents(ArrayList<String> listA, ArrayList<String> listB)
{
    List<String> temp = new ArrayList<String>(listA);
    listA.clear();
    listA.addAll(listB);
    listB.clear();
    listB.addAll(temp);
}

回答by trutheality

AFAIK, it's very not Java-like to keep track of "ownership" of references (at least on the programmer's side) which is why I doubt that you'll find the std::move()-like functionality that you want. It just isn't very commonly needed in Java. I guess C++ needs to keep track of object ownership explicitly because there is no garbage collection.

AFAIK,跟踪引用的“所有权”(至少在程序员方面)非常不像Java,这就是为什么我怀疑您是否会找到std::move()想要的类似功能。它只是在 Java 中不是很常用。我猜 C++ 需要明确跟踪对象所有权,因为没有垃圾收集。

I think that your best bet is to create a defensive copy in your constructor and save space by relying on copy constructors of immutable objects:

我认为最好的办法是在构造函数中创建一个防御性副本,并通过依赖不可变对象的复制构造函数来节省空间:

public class AnImmutableObject {

    private final List<String> items;

    /**
     * Creates a new immutable object with the given list of items.
     * Always deep copy from an outside source, because we can't know if the
     * calling code will modify that collection later.
     */ 
    public AnImmutableObject(Collection<String> items) {
        // It's a constructor. We know items needs to be set.
        // We are creating a new array list, using its constructor which deep
        // copies the collection, and immediately wrapping it to make it truly
        // immutable. We are guaranteed that no one will hold a reference to the
        // mutable view of the new ArrayList.
        this.items = Collections.unmodifiableList(new ArrayList<String>(items));
    }

    /**
     * Creates a new immutable object with the same items as another.
     * Copying the reference here is completely safe because we
     * enforce the immutability of the items array.
     */ 
    public AnImmutableObject(AnImmutableObject source) {
        items = source.items;
    }

    public List<String> getItems() {
        return items;
    }
}

At this point, you can "pass the arrays around" (really share them) in O(1) between your own immutable objects:

此时,您可以在您自己的不可变对象之间以 O(1) 的方式“传递数组”(真正共享它们):

ImmutableObject a = new ImmutableObject(Arrays.asList("A", "B", "C")); // O(n)
ImmutableObject b = new ImmutableObject(a); // O(1)

Hopefully, something like this can suit your purposes.

希望这样的事情可以满足您的目的。

Another route you could go is use Guava's ImmutableList. Since these are immutable, you can safely copy the reference to the ImmutableListin a constructor.

您可以采用的另一条路线是使用GuavaImmutableList。由于这些是不可变的,您可以安全地将引用复制到ImmutableList构造函数中。

The main approach is about making it safe for you to copy references to the lists rather than taking ownership over them.

主要方法是让您可以安全地复制对列表的引用,而不是对它们拥有所有权。