0

I have an object game of my Game.java class in my main class. I need to create a copy (game_copy) of game object such that when I make changes to the board of game_copy, the board of game does not get changed. I make this game_copy object as:

Game game_copy = new Game() ;
game_copy = game.clone() ;

But still when I make changes to the board of game_copy, the board of game gets changed as they still share a reference. How do I sort out this problem? Here are my Game and rplayer classes that I am using:

class Game implements Cloneable{
     int n;
     ArrayList<ArrayList<String>> board;
     rplayer [] players;
     int a ;

    public Game(int n){
      this.n=n;
      players = new rplayer[2] ;
      players[0]=new rplayer(this.a);
      players[1]=new rplayer(this.a);
      board= new ArrayList<ArrayList<String>>();
       for(int p= 0 ; p < n*n ; p++){
        ArrayList<String> r = new ArrayList<String>() ;
        board.add(r) ;
       }
     }

   public Game clone(){ 
    Game gm ;
    try { 
        gm =  (Game) super.clone(); 
    } 
    catch (CloneNotSupportedException e) { 
        System.out.println (" Cloning not allowed. " );
         return null; 
    }
    return gm
 }
}

class rplayer{
    int a;
    public rplayer(int a){
      this.a=a;
    }
}

This is what I tried before trying to use .clone() method, but the idea of making a copy constructor didn't work either. Both the objects were always related.

public Game(Game g){
this.n=g.n;
this.players = new rplayer[2] ;
rplayer[] temp_players = new rplayer[2] ;
temp_players = g.players;
this.players = temp_players ;
this.board= new ArrayList<ArrayList<String>>();
ArrayList<ArrayList<String>> temp_board = new ArrayList<ArrayList<String>>() ;
    for(int p= 0 ; p < n*n ; p++){
        ArrayList<String> r = new ArrayList<String>() ;
        board.add(r) ;
        temp_board.add(r) ;
    }
    temp_board = g.board ;
    board= temp_board;
}
scottstots
  • 155
  • 2
  • 17
  • 3
    Possible duplicate of [Java deep copy library](http://stackoverflow.com/questions/5001026/java-deep-copy-library) – Andremoniy Oct 13 '16 at 21:09
  • 1
    There is the notion of deep copy and shallow copy. You seem to want to do a deep copy and create a new object. I suggest you write custom code that creates a new game object and walks through the old game object and copies over one by one all the state variables you want to persist into the new game object. Yes, it's more work and code but that's the best way to get what you seem to want. – mba12 Oct 13 '16 at 21:11
  • @mba12 I have added my copy constructor that I used before landing upon the method of cloning. That didn't work either. – scottstots Oct 14 '16 at 11:22
  • Why do you *need* to clone a `Game` ? – Spotted Oct 14 '16 at 11:32
  • I am making an AI for a game. So I have to use minimax search on the board. To implement this, I need a duplicate game board so that my present state board does not get changed. – scottstots Oct 14 '16 at 12:30

3 Answers3

1

Per the Javadocs:

Otherwise, this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.

In other words, a new object IS created, but the references inside the object still point to the same member variables. You need to make copies of the contents inside the object as well as the object itself.

https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

Christopher Schneider
  • 3,745
  • 2
  • 24
  • 38
  • I tried making copy for the rplayer.java class as well, but it didn't work either. – scottstots Oct 14 '16 at 10:54
  • You probably aren't doing it correctly, then. There's no way using `new` and manually setting variables wouldn't work. Your other option, as someone else already mentioned, is to Serialize the objects. – Christopher Schneider Oct 14 '16 at 13:14
0

What I have found to make deep copy of a complex object by doing mark the object with Serializable interface and then serialize the object in memory. As your Game object has reference to another object and that object also has the reference to others it would be better to clone the object through serialization. This will ensure you that you will get absolutely different object. Java clone will not serve the purpose as the objects are getting complicated.

here is the sample code how to serialize object in memory.

class Game implements Serializable {

........
........
........

public Game makeClone() throws IOException, ClassNotFoundException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    ObjectOutputStream out = new ObjectOutputStream(outputStream);
    out.writeObject(this);

    ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
    ObjectInputStream in = new ObjectInputStream(inputStream);
    Game copied = (Game) in.readObject();
    return copied;
}

}
seal
  • 1,122
  • 5
  • 19
  • 37
  • When I try to make a copy using makeClone() method like you suggested, as `Game game_copy = new Game() ; game_copy = game.makeClone() ;` game_copy I obtained is null. – scottstots Oct 14 '16 at 11:13
  • please provide you'r code. I've tested my code. It works. And another thing, you don't need to do this `Game game_copy = new Game() ;`. `makeClone` method return you a new object of Game. – seal Oct 14 '16 at 11:34
  • [**Here**](http://ideone.com/07Qalo) is the code that I have tested. take a look and try to find where your code differ. And also run the code that will generate two different type object as you will see in the console. – seal Oct 14 '16 at 11:40
  • Thank for the code! :) But since my Game class also uses an array of rplayer class that I have defined, it gives me `NotSerializableException rplayer` in makeClone() method. How do I use this two classes deep? – scottstots Oct 14 '16 at 12:39
  • You also need to mark the `rplayer` with `Serializable` interface by implementing it. – seal Oct 14 '16 at 12:46
0

Implementing the Cloneable interface is generally not recommended. A few excerpts from Joshua Bloch's Effective Java (2nd Edition):

Override clone judiciously. The Cloneable interface was intended as a mixin interface for objects to advertise that they permit cloning. Unfortunately, it fails to serve this purpose. Its primary flaw is that it lacks a clone method, and Object's clone method is protected.

Josh then goes on to explain the many shortcomings of the Cloneable interface and the clone method. What he suggests as an alternative is that you make a "copy constructor" that copies the state of one object into your new copy, defensively copying the things that need protection. In your case, a copy constructor would probably look something like this...

public Game(Game original) {
    if (null == original) 
        throw new IllegalArgumentException("Game argument must not be null for copying");

    // int primitives can be copied by value harmlessly.
    this.n = original.n;
    this.a = original.a;

    // Collections require special protection, however, to ensure that
    // manipulating one game's state doesn't manipulate the other.
    ArrayList<ArrayList<String>> boardCopy = new ArrayList<>();
    for (ArrayList<String> subList : original.board) {
        // Fortunately, Strings are immutable, so we don't need to
        // manually copy them. And ArrayList has a copy constructor
        // of its own, so that's handy!
        ArrayList<String> subCopy = new ArrayList<>(subList); 
        boardCopy.add(subCopy);
    }
    this.board = boardCopy;

    this.players = new rplayer[original.players.length];
    for (int i = 0; i < original.players.length; i++) {
        rplayer player = original.players[i];
        // If--and ONLY if--the rplayer class is immutable, this
        // is safe; otherwise you need to copy each player on your
        // own!
        this.players[i] = player;
    }
}

The idea here is that you want to completely eliminate any "spooky action at a distance"; that is, make sure it's impossible for changing the state of Game A from indirectly changing the state of Game B. If something is immutable (Strings, wrapped primitives, your own immutable class), you can re-use the references between them. Otherwise, you need to copy the state of those objects to brand new instances that your copy will use.

nasukkin
  • 2,460
  • 1
  • 12
  • 19
  • Thank you for your answer! :) But this is exactly what I did before I landed upon the idea of cloning, as this was not working for me. Both my copied object and original object shared the same reference and changed when either of them was changed. – scottstots Oct 14 '16 at 10:52