当前位置: 首页 > 知识库问答 >
问题:

克隆与仅仅赋值有何不同(为什么要费心实现接口可克隆)?

田博远
2023-03-14
import java.util.ArrayList;
import java.util.List;

public class catalog implements Cloneable{

    List<product> cat = new ArrayList<>();
    int counter;
    final int capacity = 2;

    public void addProduct(product x){
        cat.add(x);
    }
    public void addProduct(String name, int id, int price, int stock) throws Exception{
        for(int i = 0; i < cat.size(); i++){
                product temp = cat.get(i);
                if(temp.name == name){
                    temp.stock = temp.stock + stock;
                    return;
                }
                if(temp.id == id){
                    System.out.println("Product with this ID already exists");
                    return;
                }
        }
        if(cat.size() >= capacity){
            //throw new customException("Not enough capacity");
            throw new customException();
        }
        product temp = new product();
        temp.name = name;
        temp.id = id;
        temp.price = price;
        temp.stock = stock;
        cat.add(temp);
        }
    public void showSelection(){
        for(product temp : cat){
            System.out.println("Product " + temp.name + " ID: " + temp.id
                    + " Price: " + temp.price + " In stock: " + temp.stock);
        }
    }
    public void removeFromStock(String name){
        for(int i = 0; i < cat.size(); i++){
            product temp = cat.get(i);
            if(temp.name == name){
                temp.stock = temp.stock - 1;
                cat.set(i, temp);
            }
        }
    }

    public Object clone(){
        catalog b = new catalog();
        for(int i = 0; i <= cat.size(); i++){
            product temp, temp1;
            temp1 = cat.get(i);
            temp = (product)temp1.clone();
            b.addProduct(temp);
        }
        return b;
    }
}
public class testMoney {

    public static void main(String[] args) {

        automatasklase test = new automatasklase();
        test.addMoney(50);
        System.out.println(test.getMoney());
        product cola = new product();
        cola.id = 1;
        cola.price = 2;
        cola.name = "Cola";
        productsExpire Milk = new productsExpire();
        Milk.name = "Milk";
        Milk.id = 2;
        Milk.price = 10;
        Milk.stock = 10;
        Milk.isExpired = true;
        catalog menu = new catalog();
        menu.addProduct(cola);
        menu.addProduct(Milk);
        menu.showSelection();
        try{
        menu.addProduct("Pepsi" ,3, 5, 108);
        }catch(Exception e){
            System.out.println("Exception occured = " +e);
        }
        try {
            menu.addProduct("Cola", 1, 3, 7);
        } catch (Exception e) {
            System.out.println("Exception occured = " + e.getMessage());
        }
        menu.showSelection();
        test.buyProduct(menu, 2);
        System.out.println(test.getMoney());
        menu.showSelection();
        Milk.isAvailable();
        product copyy = (product)cola.clone();
        System.out.println("-------------");
        System.out.println(cola.id + cola.name + cola.price + cola.stock);
        System.out.println(copyy.id + copyy.name + copyy.price + copyy.stock);

        // BELOW THE PROBLEM OCCURS!!!

        catalog newtest = (catalog) menu.clone();

        // ABOVE THE IS THE PROBLEM!!!!

    }

}
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
    at java.util.ArrayList.rangeCheck(Unknown Source)
    at java.util.ArrayList.get(Unknown Source)
    at AutomatasA.catalog.clone(catalog.java:58)
    at AutomatasA.testMoney.main(testMoney.java:46)

您会注意到,我已经在目录本身的克隆方法中克隆了一个product类对象,但是您可能会注意到,主类已经测试了它,并且它工作了,所以product类的克隆是成功的。

你能看出问题所在吗?我知道也会有很多小错误的编码礼仪和可能更容易的方法做事情,但我只是一个初学者。我必须实现deep copy,而且它必须有意义,所以克隆product类是不够的,我想创建一个方法来克隆整个目录,所以如果要用一台新的机器替换机器,您可以使用那个方法。

顺便说一句,整个项目正在为虚拟零食机创建一个代码,就像你输入钱,按下你想要的物品的数字,然后得到它的那种。

谢谢你的帮助!

共有1个答案

孟杰
2023-03-14

您的异常是由以下行引起的:

for(int i = 0; i <= cat.size(); i++){

应该是

for(int i = 0; i < cat.size(); i++){

但你真的不应该这样实现你自己的深层克隆。如果您想要一个副本,请为它创建一个单独的方法,或者创建一个副本构造函数。

 类似资料:
  • 在这个bug报告中,Doug Lea写道(指的是JDK 5.0的预发布版本): 附言。我知道不推荐使用,并且内部基于。

  • 本文向大家介绍为什么要使用克隆?相关面试题,主要包含被问及为什么要使用克隆?时的应答技巧和注意事项,需要的朋友参考一下 克隆的对象可能包含一些已经修改过的属性,而 new 出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠克隆方法了。

  • 我遇到了一些实现的类代码,文档中写道: 类实现Cloneable接口,以向object.clone()方法表明,该方法对该类的实例进行字段对字段的复制是合法的。在未实现可克隆接口的实例上调用对象的克隆方法会导致引发异常CloneNotSupportedException。按照约定,实现此接口的类应该使用公共方法重写Object.clone(受保护)。有关重写此方法的详细信息,请参见object.c

  • 假设我有这门课: 以及子类: 我知道这是不可能的,但我想你明白我想要什么。如果Foobar实现了Cloneable,并且没有扩展AbstractFoo,那么子类就可以工作。我想我想要但不允许的是: 如果Foobar实现了Cloneable,并且没有扩展AbstractFoo,那么子类就可以工作。 除了扩展的抽象类,我怎么能做到“相同”?

  • 我们解决什么问题 我们知道,JDK中的Cloneable接口只是一个空接口,并没有定义成员,它存在的意义仅仅是指明一个类的实例化对象支持位复制(就是对象克隆),如果不实现这个类,调用对象的clone()方法就会抛出CloneNotSupportedException异常。而且,因为clone()方法在Object对象中,返回值也是Object对象,因此克隆后我们需要自己强转下类型。 泛型克隆接口

  • 因此,我的问题是:为什么还没有被否决?如果核心Java团队已经决定它是坏的,那么他们一定也考虑过弃用。他们反对这样做的理由是什么(在Java8中,它仍然没有被反对)?