我创建一个ArrayList,我克隆它,并在原始元素中添加一个元素,它似乎不会显示在克隆中。根据VS文档,Clone执行浅拷贝。
def _do_overwrite(fs, path, copy_data):
"""
Atomically (best-effort) save the specified data to the given path
on the filesystem.
"""
# TODO(todd) Should probably do an advisory permissions check here to
# see if we're likely to fail (eg make sure we own the file
# and can write to the dir)
# First write somewhat-kinda-atomically to a staging file
# so that if we fail, we don't clobber the old one
path_dest = path + "._hue_new"
# Copy the data to destination
copy_data(path_dest)
# Try to match the permissions and ownership of the old file
cur_stats = fs.stats(path)
try:
fs.do_as_superuser(fs.chmod, path_dest, stat_module.S_IMODE(cur_stats['mode']))
except:
logging.exception("Could not chmod new file %s to match old file %s" % (path_dest, path))
# but not the end of the world - keep going
try:
fs.do_as_superuser(fs.chown, path_dest, cur_stats['user'], cur_stats['group'])
except:
logging.exception("Could not chown new file %s to match old file %s" % (path_dest, path))
# but not the end of the world - keep going
# Now delete the old - nothing we can do here to recover
fs.remove(path, skip_trash=True)
# Now move the new one into place
# If this fails, then we have no reason to assume
# we can do anything to recover, since we know the
# destination shouldn't already exist (we just deleted it above)
fs.rename(path_dest, path)
这是输出
using System.Collections;
using System;
namespace WhatDoesCloneDo
{
class Program
{
static void Main(string[] args)
{
ArrayList a, b;
a = new ArrayList();
a.Add("Chocolate");
a.Add("Vanilla");
a.Add("Crumb");
b = (ArrayList) a.Clone();
// What's in b and a?
a.Add("Cheese");
Console.WriteLine(a.Count);
Console.WriteLine(b.Count);
}
}
}
答案 0 :(得分:1)
当你Clone
时,你有一个新对象,它不是同一个引用。
在您添加的示例中,您克隆a
a生成一个指向引用ArrayList
的新b
实例。您在a
处添加了一个新元素,该元素与b
不同。这就是你获得输出的原因:
4
3
如果您这样做:
ArrayList b = a;
您没有克隆对象。它将在引用a
和b
上提供相同的对象。你会得到输出:
4
4
来自ArrayList.Clone
MSDN文档:
集合的浅表副本仅复制集合的元素 集合,无论它们是引用类型还是值类型,但它 不会复制引用引用的对象。参考文献 在新集合中指向与引用相同的对象 原始集合指向。
答案 1 :(得分:1)
浅拷贝仍然是副本,因此是列表的第二个实例。将项添加到数组a
不会将其添加到数组b
。
浅层副本意味着 in 每个数组引用相同的实例。深层副本将为数组中的每个项创建新实例。
答案 2 :(得分:0)
因为克隆不是参考,克隆攻击中的克隆不是Boba Fett的浅拷贝。
答案 3 :(得分:0)
您有一个浅副本(ArrayList
项无法克隆):
var a = new ArrayList();
a.Add("Chocolate");
a.Add("Vanilla");
a.Add("Crumb");
var b = (ArrayList) a.Clone();
bool deep = false;
for (int i = 0; i < a.Count; ++i)
if (!object.ReferenceEquals(a[i], b[i])) {
// If we have at least one b[i] instance
// which doesn't share the corresponding a[i] reference
// we can suspect that we perform deep copy
deep = true;
break;
}
Console.Write(deep ? "Deep" : "Shallow");
最后,让我们在ArrayList.Clone()
源代码上有一个llok:
https://referencesource.microsoft.com/#mscorlib/system/collections/arraylist.cs,46e5b8aaeb6679f2
// Clones this ArrayList, doing a shallow copy. (A copy is made of all
// Object references in the ArrayList, but the Objects pointed to
// are not cloned).
public virtual Object Clone()
{
Contract.Ensures(Contract.Result<Object>() != null);
ArrayList la = new ArrayList(_size);
la._size = _size;
la._version = _version;
Array.Copy(_items, 0, la._items, 0, _size);
return la;
}
为了找出Clone
是浅层副本。
答案 4 :(得分:0)
浅层副本正在创建对象ArrayList
的副本,其副本与原始副本相同。
集合中的引用是共享的,因此它不是“深层”副本。
public class Food
{
public Food(string name)
{
Name = name;
}
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
ArrayList a, b;
a = new ArrayList();
a.Add(new Food("Cocoa"));
b = (ArrayList)a.Clone();
// a, b now have "Chocolate" instead of "Cocoa"
((Food)b[0]).Name = "Chocolate";
Console.WriteLine(a[0]); // Prints "Chocolate"
Console.WriteLine(b[0]); // Prints "Chocolate"
答案 5 :(得分:0)
似乎你可能会误认为浅拷贝和深拷贝之间的区别。
在浅层副本中,将创建一个新对象,并复制原始成员的所有值。
ArrayList a = new ArrayList(); // Creates a reference variable and a new
// object and places a reference to it in a
ArrayList b = a; // Creates a new reference variable and copies the
// reference in a to b. They both refer to the same new ArrayList();
b = (ArrayList)a.Clone(); // Clone() creates a new object and copies the
// values from a into it, then assigns the reference to b.
// a and b now refer to different objects with the same values
使用值类型和不可变的字符串时,这一切都非常简单。当它开始处理作为引用类型的成员时,它开始显着不同。
不要像在原始帖子中那样分配字符串,而是创建一个简单的Person类,我们将详细介绍该场景中发生的事情。
public class Person
{
public string Name { get; set; }
}
ArrayList a = new ArrayList(); // New object, reference in a
a.Add(new Person(){Name = "Jack"}); // New person object, reference added to a.
a.Add(new Person(){Name = "Jill"}); // New person object, reference added to a.
ArrayList b = (ArrayList)a.Clone(); // New ArrayList object created, references
// to both Person objects are copied to it,
// then the reference to the new ArrayList
// is stored in b.
此时,a和b都引用不同的ArrayList对象,这些对象引用了相同的Person对象。浅拷贝会复制每个成员的值,该值是对Person对象的引用,而不是对象本身。
因此,对一个Person对象所做的任何更改都将反映在a和b中:
Console.WriteLine(((Person)a[0]).Name); // Prints "Jack"
Console.WriteLine(((Person)b[0]).Name); // Prints "Jack"
((Person)a[0]).Name = "Not Jack"; // Changes the value of the object, which is
// referenced by both a and b.
Console.WriteLine(((Person)a[0]).Name); // Prints "Not Jack"
Console.WriteLine(((Person)b[0]).Name); // Prints "Not Jack"
这就是浅拷贝的行为方式。
深层复制的行为略有不同。当您在ArrayList上执行浅表复制时,它会创建一个新的ArrayList对象并复制原始值。当它是深层副本时,它会像在浅层副本中一样创建一个新的ArrayList对象,但它不是仅仅应对值,而是递归地对每个成员执行复制操作。
以下是深层复制幕后内容的简要说明:
完成该操作后,您现在可以更改a或b中的任何内容,而不会影响其他ArrayList中的对象。