如何使用复制构造函数在不实现 cloneable() 或 arraycopy() 的情况下创建 Object 数组内容的深层副本?

How to use a copy constructor to create a deep-copy of an Object array's contents without implementing cloneable() or arraycopy()?

提问人:Gray 提问时间:3/2/2023 最后编辑:Gray 更新时间:3/2/2023 访问量:113

问:

我需要创建一个数组内容的副本,该数组内容由不同类型的各种对象组成。但是,我不能使用显式强制转换来检查对象的类型,也不能使用可克隆的接口/arraycopy 方法。

首先,我创建了一个所有其他类扩展的超类,但我不确定如何使用特定类的复制构造函数。我最初的尝试是:

public Building(Object obj) {
    try {
        this.windows= ((House)obj).windows; 
        this.basement = ((House)obj).basement; 
    } catch (ClassCastException ex) {
        this.windows = 0; 
        this.basement = false;
    }
    ... (various other try-catch blocks here)
}

驱动程序是:

public static Building[] copyBuildings(Building[] objects) {

    Building[] objList = new Building[objects.length];
        
    for (int i = 0; i < objects.length; i++) {    
        objList[i] = new Building(objects[i]);
    }
        
    return objList; 
}

但是,这并没有像我想要的那样正确地调用子类的复制构造函数,因为它根本没有引用它们。我不知道如何继续。

请记住,缺少显式类型转换,如果我在运行时不知道对象的显式类型,是否可以调用 Object 的复制构造函数(我是否需要更改当前的代码)?还是多态性不以这种方式起作用?

任何帮助将不胜感激!(以及一般反馈,我不太习惯使用 stackoverflow)

Java 复制构造函数

评论

0赞 Abra 3/2/2023
我在您的问题的 [伪] 代码中没有看到任何数组。你能发布一个更具体的例子吗?像一个最小的可重复的例子
0赞 Gray 3/2/2023
@Abra 对不起!我添加了我正在使用的当前版本来(尝试并)调用复制构造函数。
0赞 Abra 3/2/2023
也许尝试反思

答:

1赞 Stephen C 3/2/2023 #1

显然,您有一个包含各种子类型的子类型。并且您想要创建深层副本。Building[]Building

不能通过实现复制构造函数来执行此操作。Building

为什么?

因为构造函数 for 只能构造一个实例。它无法构造实例...或或 a 或 ...BuildingBuildingHouseHotelChurch


但是,有多种替代方法可以奏效:

  • 在 和 它的每个子类型中实现。CloneableBuilding

  • 实现一个工厂方法或类,以便从另一个工厂方法或类创建。让它使用(或 Java 18+ 模式开关)来区分子类,然后为每个子类型使用适当的构造函数;例如:Buildinginstanceof

    if (building instanceof House) {
        return new House((House) building);
    } else if (building instanceof Hotel) {
        return new Hotel((Hotel) building);
    } else ...
    
  • 使用反射。这很复杂,但您不需要为层次结构中的每个类或子类编写代码。

每种替代方案都有优点和缺点,我们无法建议哪一种最适合每种用例。当然,它们都不是所有用例的完美选择。

评论

0赞 Gray 3/3/2023
非常详细的答案,我很感激。如果我考虑我不能在任何地方(无论是在驱动程序中还是在 Building 类中)进行类型转换的限制,请导入任何外部类,也不使用 Cloneable 接口。还有可能吗?
1赞 Stephen C 3/3/2023
不。不可能。即使是反射方法也需要类型转换,而开关模式是 + 类型转换的一种花哨形式。(虽然我想这取决于你所说的“类型转换”的确切含义;即你是否在谈论语法......或者语法导致发生什么。instanceof
0赞 Gray 3/3/2023
通过类型转换,我指的是语法本身。我在查找被复制对象的实际类型方面受到限制。虽然多亏了你,现在更清楚了,但我不确定有什么样的隐藏解决方案(如果有的话)。再次感谢!