数组的浅表副本,但不是引用的副本

时间:2019-07-06 16:48:49

标签: java

我偶然发现了一个问题,我必须创建一个不接受任何输入并返回此购物篮MarketProduct的数组的浅表副本(而不是引用的副本)的方法。

我知道解决方法如下

public class Basket {
    private MarketProduct[] marketproducts;

    public Basket() {
        this.marketproducts = new MarketProduct[0];
    }

    public MarketProduct[] getProducts() {
        return this.marketproducts.clone();

我不明白的是 1.如果是浅表副本,那么它是引用权的副本? 2.我可以对Java中的任何对象使用克隆方法吗?它会复制参考对象或实际对象吗?如果是这样,那么可以简化以下内容(代替使用for循环,我可以使用clone?)?

public void add(MarketProduct input) {
        MarketProduct[] list = new MarketProduct[marketproducts.length];
        for(int i = 0; i < marketproducts.length; i++) {
            list[i] = marketproducts[i];
        }
        list[list.length-1] = input;
        this.marketproducts = list;
    }

2 个答案:

答案 0 :(得分:1)

  
      
  1. 如果是浅表副本,那么它是引用权的副本?
  2.   

不。这是一个新数组,其中包含与原始数组相同的对象的引用

  
      
  1. 我可以对Java中的任何对象使用克隆方法吗?
  2.   

不。阅读Object.clone()Cloneable的Javadoc来了解规则。

  

如果是这样,那么可以简化以下内容(代替使用for循环,我可以使用克隆吗?)?

否,因为clone()将为您提供相同长度的新数组,因此您将无法在该数组的末尾添加新元素。

答案 1 :(得分:1)

  
      
  1. 如果它是浅表副本,那么它是参考权的副本?
  2.   

否,它是对具有该对象属性副本的新对象的新引用。详细信息取决于clone的实现。

  
      
  1. 我可以对Java中的任何对象使用克隆方法吗?它会复制引用对象还是实际对象?
  2.   

首先,clone不是用于数组浅拷贝的正确工具。您可以改用System.arraycopy。对于您的情况,您需要为新条目分配一个末尾有空间的数组,然后将arraycopy原始数组放入其中,然后添加条目。

public void add(MarketProduct input) {
    MarketProduct[] list = new MarketProduct[marketproducts.length + 1];
    System.arraycopy(marketproducts, 0, list, 0, marketproducts.length);
    list[list.length-1] = input;
    this.marketproducts = list;
}

显然,这有点贵,您可以考虑使用List类之一(也许是ArrayList),这样就不必每次都增加数组。

关于clone,请参见the JavaDoc

  创建并返回此对象的副本。确切含义    “副本”的类型可能取决于对象的类。一般    目的是,对于任何对象x,表达式:    
 
 x.clone() != x
   将为真,并且该表达式:    
 
 x.clone().getClass() == x.getClass()
   将为true,但这不是绝对要求。    通常情况是:    
 
 x.clone().equals(x)
   将为true,这不是绝对要求。    

   按照惯例,返回的对象应通过调用    super.clone。如果一个类及其所有超类(除    Object)遵守这一约定,情况就是这样    x.clone().getClass() == x.getClass()。    

   按照惯例,此方法返回的对象应该是独立的    此对象(正在克隆)的对象。为了实现这种独立性,    可能需要修改返回对象的一个​​或多个字段    super.clone之前返回。通常,这意味着    复制构成内部“深度结构”的任何可变对象    被克隆的对象并替换对这些对象的引用    引用副本的对象。如果一个类仅包含    基本字段或对不可变对象的引用,那么通常    super.clone返回的对象中没有字段的情况    需要修改。    

   类clone的方法Object执行    具体的克隆操作。首先,如果此对象的类    没有实现接口Cloneable,然后    抛出CloneNotSupportedException。注意所有数组    被认为实现了Cloneable接口,并且    数组类型clone的{​​{1}}方法的返回类型    是T[],其中T是任何引用或原始类型。    否则,此方法将创建此类的新实例。    对象并使用确切的内容初始化其所有字段    该对象的相应字段,就像通过分配;的    字段的内容本身不会被克隆。因此,这种方法    执行此对象的“浅表复制”,而不是“深表复制”操作。    

   类T[]本身并不实现接口    Object,因此在对象上调用Cloneable方法    其类为clone的结果将引发    运行时出现异常。

因此,您不能在未实现Object的objets上使用它,但是可以在具有此功能的对象上使用它。