【问题标题】:Modify list has an affect on another list in java修改列表对java中的另一个列表有影响
【发布时间】:2020-06-02 06:57:56
【问题描述】:

我在 java 中的修改列表有问题,我想用 foreach 更改 listTempEnemy 中的值,然后根据需要更改值,但它对 listEnemy 有影响,它不应该改变,这个是我的代码谢谢。

public void hunt() {
    Enemy enemy = new Enemy();
    enemy.setEnemyName("Poring");
    enemy.setEnemyMinATK(10);
    enemy.setEnemyMaxATK(20);
    listEnemy.add(enemy);

    List<Enemy> listTempEnemy = new ArrayList<Enemy>();
    listTempEnemy.addAll(listEnemy);

    for (Enemy enm : listEnemy) {
        System.out.println("Before "+ enm.getEnemyMinATK() + " | " + enm.getEnemyMaxATK());
    }

    for (Enemy enm : listTempEnemy) {
        enm.setEnemyMinATK((enm.getEnemyMinATK() * 10/100) + enm.getEnemyMinATK());
        enm.setEnemyMaxATK((enm.getEnemyMaxATK() * 10/100) + enm.getEnemyMaxATK());
        System.out.println("Value Changed "+ enm.getEnemyMinATK() + " | " + enm.getEnemyMaxATK());
    }

    for (Enemy enm : listEnemy) {
        System.out.println("After "+ enm.getEnemyMinATK() + " | " + enm.getEnemyMaxATK());
    }
}

结果是

2020-02-18T17:02:33.843+0700|Info: Before 10 | 20
2020-02-18T17:02:33.843+0700|Info: Value Changed 11 | 22
2020-02-18T17:02:33.843+0700|Info: After 11 | 22

然后我更改了我的代码

private List<Enemy> loadEnemy() {
    List<Enemy> listEnemy = new ArrayList<Enemy>();

    Enemy enemy = new Enemy();
    enemy.setEnemyName("Poring");
    enemy.setEnemyHP(100);
    enemy.setEnemyMinATK(10);
    enemy.setEnemyMaxATK(20);
    listEnemy.add(enemy);

    return listEnemy;
}

public void hunt() {
    List<Enemy> listTempEnemy = loadEnemy();

    for (Enemy enm : listEnemy) {
        System.out.println("Before "+ enm.getEnemyMinATK() + " | " + enm.getEnemyMaxATK());
    }

    for (Enemy enm : listTempEnemy) {
        enm.setEnemyMinATK((enm.getEnemyMinATK() * 10/100) + enm.getEnemyMinATK());
        enm.setEnemyMaxATK((enm.getEnemyMaxATK() * 10/100) + enm.getEnemyMaxATK());
        System.out.println("Changed Value " + enm.getEnemyMinATK() + " | " + enm.getEnemyMaxATK());
    }

    for (Enemy enm : listEnemy) {
        System.out.println("After "+ enm.getEnemyMinATK() + " | " + enm.getEnemyMaxATK());
    }
}

这是我想要的结果

2020-02-18T17:46:36.387+0700|Info: Before 10 | 20
2020-02-18T17:46:36.387+0700|Info: Changed Value 11 | 22
2020-02-18T17:46:36.387+0700|Info: After 10 | 20

【问题讨论】:

  • 这就是引用的工作方式。您不会将对象本身传递给方法,而是传递引用。如果调用两个方法,每个方法都接收对同一个对象的引用,则对该对象的更改会反映在两个方法中。

标签: java list arraylist foreach


【解决方案1】:

您已将相同的对象(指向堆(内存)中相同对象的指针/引用)添加到两个单独的列表中。当您更改一个列表中的对象时,它会更改另一个列表中的对象,因为它们都是同一个对象。这就是为什么不可变对象更可取的原因,因为这类错误很难被发现(如果你有很多复杂的逻辑......例如,哪个类正在改变对象?)。对于列表 1 和列表 2,您需要 2 个副本对象

【讨论】:

  • 不是同一个指针。它是指向堆中同一个对象的两个指针。
  • 在 Java 的上下文中,将它们称为引用可能更好。
  • 我已经更改了我的代码,你能再检查一下吗谢谢。 @tomgeraghty3
  • @Makku 您遇到了与您刚刚以另一种方式实现的完全相同的问题。您已经说过 addAll() 从列表 1 到列表 2,这会将 SAME 对象复制到 2 个列表中。因此,当您在列表 1 中对其进行修改时,它将影响列表 2 中的相同对象。很难从您的代码片段中看到您想要实现的目标,但您想要 (1) 创建不可变对象(即那些没有设置器的对象,所以一旦创建了对象,您就无法更改它的值)或(2)在列表 1 中创建对象的副本,修改它们并将它们放入列表 2
  • 我想更改列表中的值,但我想保留原始列表,所以我得到的是原始列表和更改列表@tomgeraghty3
【解决方案2】:

两个列表都包含相同的玩家。因此,如果您更改 1 个列表中的玩家,您也隐含地更改了另一个列表中的玩家。

您可以尝试用第一个列表的克隆填充第二个列表。
像这样的:

listPlayer.add(game);
listTempPlayer.add((Game)game.clone());

当然,Game 类应该实现Cloneable 接口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 2019-11-06
    • 2014-02-17
    • 2015-03-31
    相关资源
    最近更新 更多