【问题标题】:shallow copy of the array but not a copy of the reference [duplicate]数组的浅表副本,但不是引用的副本[重复]
【发布时间】:2019-11-16 20:26:12
【问题描述】:

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

我知道解决方法如下

public class Basket {
    private MarketProduct[] marketproducts;

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

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

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

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;
    }

【问题讨论】:

  • 不,您不能只“克隆()”任何 Java 对象。是的,Java 数组实现了接口Cloneable,因此您可以 克隆它们。您的 Basket 引用了数组 margetProducts。 marketProducts 中的每个元素都有一个对MarketProduct 对象的引用。当您克隆 marketProducts 时,您保留对元素的原始引用。 “克隆”或“for 循环”,都复制 reference。看here 和here

标签: java


【解决方案1】:
  1. 如果是浅拷贝,那么它是引用的拷贝,对吗?

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

  1. 我可以对java中的任何对象使用clone方法吗?

没有。阅读Object.clone()和Cloneable的javadoc了解规则。

如果是这样,那么以下可以简化正确(而不是使用 for 循环我可以使用克隆?)?

不,因为clone() 会给你一个相同长度的新数组,因此你不能在数组末尾添加新元素。

【讨论】:

    【解决方案2】:
    1. 如果是浅拷贝,那么它就是引用的拷贝,对吗?

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

    1. 我可以对java中的任何对象使用clone方法吗?它是复制引用还是实际对象?

    首先,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返回的对象中没有字段的情况 需要修改。

    类Object 的方法clone 执行一个 具体的克隆操作。首先,如果这个对象的类 不实现接口Cloneable,然后一个 CloneNotSupportedException 被抛出。请注意,所有数组 被认为实现了接口Cloneable,并且 数组类型T[] 的clone 方法的返回类型 是T[],其中 T 是任何引用或原始类型。 否则,此方法会创建 this 类的新实例 对象并用完全的内容初始化它的所有字段 这个对象的对应字段,好像通过赋值一样;这 字段的内容本身不会被克隆。因此,这种方法 执行此对象的“浅拷贝”,而不是“深拷贝”操作。

    Object 类本身并不实现接口 Cloneable,因此在对象上调用 clone 方法 其类是Object 将导致抛出一个 运行时异常。

    所以你不能在没有实现Cloneable的对象上使用它,但是你可以在实现的对象上使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-25
      • 2021-04-12
      • 1970-01-01
      • 2013-12-16
      • 1970-01-01
      • 2016-02-15
      相关资源
      最近更新 更多