有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java clone():ArrayList。克隆人()我认为它是一个肤浅的复制品

ArrayList<Integer> a=new ArrayList<Integer>();
a.add(5);
ArrayList<Integer> b=(ArrayList<Integer>)a.clone();
a.add(6);
System.out.println(b.toString());

在上面的代码中,我认为clone()做了一个肤浅的复制。所以,ba应该指向相同的内存位置。然而,当我做b.toString()时,答案只是5。如果clone()进行浅层复制,为什么6也不显示


共 (6) 个答案

  1. # 1 楼答案

    这确实是一个浅拷贝,这里是对克隆的注释,来自ArrayList源代码

    Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)

    为了理解这一点,让我们看看ArrayList中克隆方法中的一个片段

    v.elementData = Arrays.copyOf(elementData, size);
    

    正如我们所知,当我们将一个对象分配给一个变量时,JAVA并不会生成一个全新的 那个物体。相反,该变量成为指向原始对象的另一个引用

    因此,elementData实际上存储了对放入该ArrayList的对象的引用。克隆 复制这些引用时,不会创建对象的副本

    当然,您可以删除或添加对克隆ArrayList的新引用

    但是,修改一个ArrayList中的旧对象会影响原始ArrayList。因为整数是不可变的,所以很难用你的例子来说明

    要查看副作用,可以定义自定义可变对象

    class Person {
            private int a;
    
            public void setA(int a) {
                this.a = a;
            }
            public int getA() {
                return a;
            }
            @Override
            public String toString() {
                return String.valueOf(a);
            } 
       } 
    

    然后可以使用以下代码进行测试

            Person p1 = new Person();
            Person p2 = new Person();
    
            ArrayList<Person> tt = new ArrayList<Person>();
            tt.add(p1);
            tt.add(p2);
    
            ArrayList<Person> yy = (ArrayList<Person>) tt.clone();
            Person vv = yy.get(yy.indexOf(p2));
            vv.setA(12);
            yy.remove(p1);
    
            System.out.println("tt: " + tt);
            System.out.println("yy: " +yy);
    

    输出应该是

    tt: [0, 12]
    yy: [12]

    看到副作用了吗?我们只改变yy中的元素,但它也反映在tt中

  2. # 2 楼答案

    我们不能像这样动态地选择要添加字符串的位置吗

    int r=k.nextInt();
    Integer i6=new Integer(r);
    System.out.println("Enter the address");
    String p6=k.nextLine();
    ar3.add(i6,p6);
    

    它不是在读取整数后执行

  3. # 3 楼答案

    如果它像你想的那样,那么clone方法将是完全无用的,因为在这种情况下,以下几行将是等效的:

    ArrayList<Integer> b = (ArrayList<Integer>)a.clone();
    ArrayList<Integer> b = a;
    

    与现实场景一样,克隆是一个创建两个属性完全相同的实体的过程(在克隆操作时)

    正如Bozho提到的——避免Java{}概念。即使是作者提到的,它也坏了

    This question and it's answers非常有价值,并提供一个链接,链接到Josh Blochs自己对其作品的评论;-)

  4. # 4 楼答案

    浅拷贝并不意味着它们指向同一个内存位置。那只是一个任务:List b = a;

    克隆会创建一个新的实例,其中包含相同的元素。这意味着你有两个不同的列表,但它们的内容是相同的。如果在第一个列表中更改对象的状态,它将在第二个列表中更改。(因为您使用的是不可变类型-Integer,所以无法观察到这一点)

    但是,您应该考虑不使用^ {CD3>}。它适用于收藏,但通常被认为是破损的。使用复制构造函数-new ArrayList(originalList)

  5. # 5 楼答案

    Arraylist中的clone函数与将一个Arraylist复制到另一个Arraylist不同,如果使用clone(),它会保留原始Arraylist的副本,但如果在使用clone()后对原始Arraylist进行任何更改,则不会影响复制的Arraylist。。 例如:

    public static void main(String[] a) {
    
    List list = new ArrayList();
    
    list.add("A");
    
    List list2 = ((List) ((ArrayList) list).clone());
    
    System.out.println(list);
    System.out.println(list2);
    
    list.clear();
    
    System.out.println(list);
    System.out.println(list2);
    }
    

    输出:-

    [A]

    [A]

    []

    [A]

  6. # 6 楼答案

    浅层克隆Object.clone()提供的默认克隆策略。 object类的clone()方法创建一个新实例,并将可克隆对象的所有字段复制到该新实例(要么是基元实例,要么是引用实例)。因此,在引用类型的情况下,只有引用位被复制到新实例,因此,两个对象的引用变量将指向同一个对象。我们上面看到的例子是一个浅层克隆的例子

    深度克隆顾名思义,深度克隆意味着从一个对象克隆到另一个对象。为了实现这一点,我们需要欺骗我们的clone()方法来提供我们自己的克隆策略。我们可以通过实现Cloneable接口,在对象层次结构中的每个引用类型中重写clone()方法,然后在对象的clone方法中调用super.clone()和这些clone()方法来实现

    但是,如果你在源代码中查看ArrayList的clone()方法,你会发现它在调用super.clone()后从外部复制v.elementData = Arrays.copyOf(elementData, size);,这意味着ArrayList的clone()会深度复制它的内容

    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
    

    要阅读有关克隆及其类型(如深度克隆和浅层克隆)的更多信息,请阅读Java Cloning and Types of Cloning (Shallow and Deep) in Details with Example