如何将一个ArrayList的内容移动到另一个?
有没有办法将ArrayList的全部内容移动到O(1)中的另一个ArrayList实例?
即:只有对后备数组的引用从一个实例传递到另一个实例(元素不会逐个复制)。
例如:
ArrayList a = new ArrayList(Arrays.asList("A", "B", "C")); ArrayList 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)
更好的是,是否有一个ArrayList#swapContents(ArrayList)
方法?
进一步说明和用例 :
进一步说明 1:不得交换“a”和“b”的引用。 我不是在寻找tmp = a; a = b; b = tmp;
tmp = a; a = b; b = tmp;
解决方案的类型。
进一步说明 2:操作必须是〜O(1)及时。
用例 :当一个对象想要封装外部构造的列表时,这很有用:
public class A { private ArrayList 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 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 items) { if (items != null) { this.items.addAll(items); } } public List getItems() { return Collections.unmodifiableList(items); } }
请注意,我们希望避免复制(以提高速度并减少内存使用量)。 关键的一点是被调用者必须失去修改(现在封装的) ArrayList
。
@Lirik回答是greate +1。 但是,如果您正在寻找一个真正的ArrayList#swapContents(ArrayList)
,请按以下步骤操作:
public static void swapContents(ArrayList listA, ArrayList listB) { List temp = new ArrayList (listA); listA.clear(); listA.addAll(listB); listB.clear(); listB.addAll(temp); }
AFAIK,跟踪引用的“所有权”(至少在程序员方面)并不像Java那样,这就是为什么我怀疑你会发现你想要的类似std::move()
的function。 它在Java中并不常见。 我猜C ++需要明确跟踪对象所有权,因为没有垃圾收集。
我认为最好的办法是在构造函数中创建一个防御性副本,并依赖于不可变对象的复制构造函数来节省空间:
public class AnImmutableObject { private final List 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 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 (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 getItems() { return items; } }
此时,你可以在你自己的不可变对象之间“在O(1)中传递数组(真正地分享它们):
ImmutableObject a = new ImmutableObject(Arrays.asList("A", "B", "C")); // O(n) ImmutableObject b = new ImmutableObject(a); // O(1)
希望这样的事情能够满足你的目的。
你可以去的另一条路线是使用Guava的ImmutableList 。 由于这些是不可变的,因此您可以安全地将引用复制到构造函数中的ImmutableList
。
主要方法是使您可以安全地复制对列表的引用,而不是对它们拥有所有权。
这应该这样做:
ArrayList a = new ArrayList<>(Arrays.asList("A", "B", "C")); ArrayList b = a; a = new ArrayList<>();
从概念上讲, a
现在是空的, b
包含之前包含的内容。 只有一个任务,没有数据复制,这是你能做到的最快的。 这是否满足您的要求,或者您是否真的希望仍然引用相同的数组,除了给定的数组现在应该为空?
更新
我不相信在C ++中,移动操作的时间复杂度也是O(1)。 同样谨慎地指出“因为Java中的类使用引用语义,所以在这些语言中永远不会有任何对象的隐式副本。移植语义解决的问题在Java中从来没有存在过。 ”(请参阅FredOverflow的答案: C ++ Rvalue引用和移动语义 )
有没有办法将ArrayList的全部内容移动到另一个ArrayList,以便只有对后备数组的引用从一个传递到另一个(即,不会逐个复制元素)。
鉴于上述语句,如果您在Java中将某些内容从数组a
复制到数组b
,则两个数组都将引用相同的数据。 您在C ++中使用移动语义所做的就是保存需要创建的临时对象以进行这样的复制:
X foo(); X x; // perhaps use x in various ways x = foo();
最后一个做了:
destructs the resource held by x, clones the resource from the temporary returned by foo, destructs the temporary and thereby releases its resource.
移动语义确实:
swap resource pointers (handles) between x and the temporary, temporary's destructor destruct x's original resource.
你保存了一个destruct,但只在C ++中… Java中不存在上述问题! 有关移动语义的更多详细信息,请参阅此文章: http : //thbecker.net/articles/rvalue_references/section_02.html