2

I have a problem with modify list in java, i want to change value in listTempEnemy with foreach and then the value change as i want, but it has an affect to listEnemy which should not change, this is my code Thank You.

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

The result is

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

And then i have change my code

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

This is the result that i want

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
Makku
  • 97
  • 1
  • 1
  • 10
  • 3
    This is how references work. You don't pass an object itself to a method, instead, you pass a reference. If two methods are called with each of them receiving a reference to the very same object, then *changes* to that object are reflected in both methods. – MC Emperor Feb 18 '20 at 09:53

2 Answers2

2

You've added the same object (pointers/references to the same object in heap (memory)) to the two separate lists. When you change the object in one list it changes it in the other because they are both the same object. This is why immutable objects are preferable as these kind of bugs can be really hard to spot (if you had a lot of complex logic... e.g. which class is mutating the objects?). You'll need 2 copies of your object for list 1 and list 2

tomgeraghty3
  • 1,234
  • 6
  • 10
  • 1
    it's not the same pointer. it's two pointers to the same object in heap. – Sharon Ben Asher Feb 18 '20 at 09:41
  • 2
    In the context of Java, it's probably better to call them references. – MC Emperor Feb 18 '20 at 09:47
  • i have change my code, can you check again thank you. @tomgeraghty3 – Makku Feb 18 '20 at 10:10
  • @Makku you've got exactly the same problem you've just achieved it another way. You've said addAll() from list 1 into list 2 which will copy the SAME object into the 2 lists. So when you modify it in list 1 it will affect the same object in list 2. It's hard to see what you're trying to achieve from your snippit but you want to either (1) create immutable objects (i.e. those without setters, so once the object is created you can't change it's value) or (2) Create a copy of the objects in list 1, modify them and put them into list 2 – tomgeraghty3 Feb 18 '20 at 10:14
  • i want to change a value in list, but i want keep the original list, so what i get is Original list and Changed list @tomgeraghty3 – Makku Feb 18 '20 at 10:32
  • so the two options I stated above will help – tomgeraghty3 Feb 18 '20 at 10:46
  • Java is pass by value and therefore has no pointers. Each time you pass an object the value (reference to the object) gets copied. However: The object remains the same. You need to clone it or create a new object. https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value/40593867 – daPhantom Feb 18 '20 at 10:48
0

Both lists contain the same players. Therefore, if you change a player in 1 list, you implicitely change the player in the other list as well.

You could try to fill the second list with clones of those in the first.
Something like this:

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

Of course, you Game class should implement the Cloneable interface.

Robert Kock
  • 5,795
  • 1
  • 12
  • 20