2016-10-13 3 views
0

У меня есть объектная игра моего класса Game.java в моем основном классе. Мне нужно создать копию (game_copy) игрового объекта, чтобы при внесении изменений в правление game_copy доски игры не менялись. Я делаю этот объект game_copy как:Глубокое клонирование объекта класса в java

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

Но до сих пор, когда я внести изменения в совет game_copy, доска игры получает изменилась, поскольку они по-прежнему разделяют ссылку. Как мне решить эту проблему? Вот мои игры и rplayer классы, которые я использую:

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

Это то, что я пытался, прежде чем пытаться использовать .clone() метод, но идея сделать конструктор копирования не работает. Оба объекта всегда были связаны.

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; 
} 
+3

Возможный дубликат [Java deep copy library] (http://stackoverflow.com/questions/5001026/java-deep-copy-library) – Andremoniy

+1

Существует понятие глубокой копии и мелкой копии. Кажется, вы хотите сделать глубокую копию и создать новый объект. Я предлагаю вам написать собственный код, который создает новый игровой объект и проходит через старый игровой объект и копирует по одному все переменные состояния, которые вы хотите сохранить в новом игровом объекте. Да, это больше работы и кода, но это лучший способ получить то, что вам кажется нужным. – mba12

+0

@ mba12 Я добавил свой конструктор копий, который я использовал, прежде чем приступать к методу клонирования. Это тоже не сработало. –

ответ

0

То, что я нашел, чтобы сделать глубокую копию сложного объекта, делая обозначают объект с Serializable интерфейсом, а затем сериализовать объект в памяти. Поскольку объект Game имеет ссылку на другой объект, и этот объект также имеет ссылку на других, было бы лучше клонировать объект посредством сериализации. Это гарантирует, что вы получите абсолютно другой объект. Клон Java не будет служить цели, поскольку объекты становятся сложными.

вот пример кода, как сериализовать объект в памяти.

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

} 
+0

Когда я пытаюсь сделать копию, используя метод makeClone(), как вы сказали, как «Game game_copy = new Game(); game_copy = game.makeClone(); 'game_copy Я получил значение null. –

+0

, пожалуйста, предоставьте код. Я проверил свой код. Оно работает. И еще, вам не нужно делать это 'Game game_copy = new Game();'. Метод 'makeClone' возвращает вам новый объект игры. – seal

+0

[** Здесь **] (http://ideone.com/07Qalo) - это код, который я тестировал. взгляните и попытайтесь найти, где ваш код отличается. А также запустите код, который будет генерировать два разных объекта типа, как вы увидите на консоли. – seal

1

согласно Javadocs:

В противном случае, этот метод создает новый экземпляр класса этого объекта и инициализирует все его поле с точно содержанием соответствующих полей этого объекта, как бы по заданию; содержимое полей само по себе не клонируется. Таким образом, этот метод выполняет «мелкой копии» этого объекта, а не операции «глубокой копии».

Другими словами, создается новый объект IS, но ссылки внутри объекта по-прежнему указывают на одни и те же переменные-члены. Вам нужно сделать копии содержимого внутри объекта, а также самого объекта.

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

+0

Я тоже пытался сделать копию для класса rplayer.java, но это тоже не сработало. –

+0

Вы, вероятно, не делаете это правильно. Невозможно использовать переменные 'new' и вручную, которые не будут работать. Другой вариант, как уже упоминалось, - это сериализовать объекты. –

0

Внедрение интерфейса Cloneable обычно не рекомендуется. Несколько отрывков из Джошуа Блоха Effective Java (2nd Edition):

Override clone рассудительно. Интерфейс Cloneable был предназначен как интерфейс mixin для рекламы объектов, которые разрешают клонирование. К сожалению, он не может служить этой цели. Его основной недостаток заключается в том, что ему не нужен метод clone, и метод клонирования Object защищен.

Затем Джош объясняет многие недостатки интерфейса Cloneable и метод clone. В качестве альтернативы он предлагает альтернативу, что вы создаете «конструктор копирования», который копирует состояние одного объекта в вашу новую копию, защищая файлы, требующие защиты. В вашем случае конструктор копирования, вероятно, будет выглядеть примерно так ...

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

Идея состоит в том, что вы хотите полностью устранить любое «жуткий действие на расстоянии»; то есть убедитесь, что невозможно изменить состояние Game A от косвенного изменения состояния Game B. Если что-то неизменное (строки, обернутые примитивы, ваш собственный неизменный класс), вы можете повторно использовать ссылки между ними. В противном случае вам нужно скопировать состояние этих объектов в новых экземпляров, которые будут использовать ваша копия.

+0

Спасибо за ваш ответ! :) Но это именно то, что я сделал, прежде чем я приземлился на идею клонирования, поскольку это не работало для меня. И мой скопированный объект, и исходный объект разделяли одну и ту же ссылку и менялись, когда любой из них был изменен. –