克隆对象的值更改时,原始对象也会更改
我正在尝试使用克隆,但当克隆的对象的值发生更改时,原始对象也会发生更改。 正如你可以看到KalaGameState不使用任何对象,所以浅拷贝应该工作。
/**
* This class represents the current state of a Kala game, including
* which player's turn it is along with the state of the board; i.e. the
* numbers of stones in each side pit, and each player's 'kala').
*/
public class KalaGameState implements Cloneable
{
// your code goes here
private int turn;
private int[] sidePit;
private boolean game;
public Object clone() {
try {
return super.clone();
}
catch (CloneNotSupportedException e) {
// This should never happen
throw new InternalError(e.toString());
}
}
/**
* Constructs a new GameState with a specified number of stones in each
* player's side pits.
* @param startingStones the number of starting stones in each side pit.
* @throws InvalidStartingStonesException if startingStones not in the range 1-10.
*/
public KalaGameState(int startingStones) throws InvalidStartingStonesException
{
game=true;
turn=0;
sidePit=new int[14];
for (int i=0; i <= 13 ; i++)
{
sidePit[i] = startingStones;
}
sidePit[6] =0;
sidePit[13] =0;
// your code goes here
}
/**
* Returns the ID of the player whose turn it is.
* @return A value of 0 = Player A, 1 = Player B.
*/
public int getTurn()
{
return turn; // your code goes here
}
/**
* Returns the current kala for a specified player.
* @param playerNum A value of 0 for Player A, 1 for Player B.
* @throws IllegalPlayerNumException if the playerNum parameter
* is not 0 or 1.
*/
public int getKala(int playerNum) throws IllegalPlayerNumException
{
if(playerNum!=0 || playerNum!=1)
throw new IllegalPlayerNumException(playerNum);
if(playerNum==0)
return sidePit[6];
else
return
sidePit[13];
// your code goes here
}
/**
* Returns the current number of stones in the specified pit for
* the player whose turn it is.
* @param sidePitNum the side pit being queried in the range 1-6.
* @throws IllegalSidePitNumException if the sidePitNum parameter.
* is not in the range 1-6.
*/
public int getNumStones(int sidePitNum) throws IllegalSidePitNumException
{
if(turn==0)
{
if(sidePitNum>6 )
throw new IllegalSidePitNumException(sidePitNum);
}
else
if(sidePitNum>12)
throw new IllegalSidePitNumException(sidePitNum);
if(turn==0)
return sidePit[sidePitNum];
else
return sidePit[sidePitNum+6];
// your code goes here
}
/**
* Returns the current number of stones in the specified pit for a specified player.
* @param playerNum the player whose kala is sought. (0 = Player A, 1 = Player B).
* @param sidePitNum the side pit being queried (in the range 1-6).
* @throws IllegalPlayerNumException if the playerNum parameter is not 0 or 1.
* @throws IllegalSidePitNumException if the sidePitNum parameter is not in the
* range 1-6.
*/
public int getNumStones(int playerNum, int sidePitNum) throws IllegalPlayerNumException,
IllegalSidePitNumException
{
/*if(playerNum>2)
throw new IllegalPlayerNumException(playerNum);
if(turn==0)
{
if(sidePitNum>6 )
throw new IllegalSidePitNumException(sidePitNum);
}
else
if(sidePitNum>12)
throw new IllegalSidePitNumException(sidePitNum);
*/
if(playerNum==0)
return sidePit[sidePitNum];
else if(playerNum==1)
return sidePit[sidePitNum+7];
else
return sidePit[sidePitNum];
}
/**
* Returns the current score for a specified player - the player's
* kala plus the number of stones in each of their side pits.
* @param playerNum the player whose kala is sought. (0 = Player A, 1 = Player B).
* @throws IllegalPlayerNumException if the playerNum parameter is not 0 or 1.
*/
public int getScore(int playerNum) throws IllegalPlayerNumException
{
if(playerNum>1)
throw new IllegalPlayerNumException(playerNum);
int score=0;
if(playerNum==0)
{
for(int i=0;i<=5;i++)
score=score+sidePit[i];
score=score+sidePit[6];
}
else
{
for(int i=7;i<=12;i++)
score=score+sidePit[i];
score=score+sidePit[13];
}
// your code goes here
return score;
}
private int getSidePitArrayIndex(int sidePitNum) throws IllegalSidePitNumException
{
if(turn==0)
{
if(sidePitNum>6 )
throw new IllegalSidePitNumException(sidePitNum);
}
else
if(sidePitNum>12)
throw new IllegalSidePitNumException(sidePitNum);
if(turn==0)
{
return sidePitNum--;
}
else
{
return sidePitNum+6;
}
}
public boolean gameOver()
{
int stone=0;
if(turn==0)
for(int i=0;i<=5;i++)
stone=stone+getNumStones(i);
else
for(int i=7;i<=12;i++)
stone=stone+getNumStones(i-7);
if (stone==0)
game=false;
return game;
}
/**
* Makes a move for the player whose turn it is.
* @param sidePitNum the side pit being queried (should be in the range 1-6)
* @throws IllegalSidePitNumException if the sidePitNum parameter is not in the range 1-6.
* @throws IllegalMoveException if the side pit is empty and has no stones in it.
*/
public void makeMove(int sidePitNum) throws IllegalSidePitNumException, IllegalMoveException
{
if(turn==0)
{
if(sidePitNum>6 )
throw new IllegalSidePitNumException(sidePitNum);
}
else
if(sidePitNum>12)
throw new IllegalSidePitNumException(sidePitNum);
/*
if(turn==0)
{
if(sidePit[sidePitNum-1]==0)
throw new IllegalMoveException(sidePitNum);
}
else
{ if(sidePit[sidePitNum-1+7]==0)
throw new IllegalMoveException(sidePitNum);
}
*/
sidePitNum--;
int temp=sidePitNum;
int pitNum=sidePitNum+1;
int stones=getNumStones(turn,sidePitNum);
if(turn==0)
sidePit[sidePitNum]=0;
else
{
sidePitNum=sidePitNum+7;
sidePit[sidePitNum]=0;
pitNum=pitNum+7;
}
while(stones!=0)
{
if(turn==0)
{
sidePit[pitNum]=sidePit[pitNum]+1;
stones--;
pitNum++;
if(pitNum==13)
pitNum=0;
}
else
{
sidePit[pitNum]=sidePit[pitNum]+1;
stones--;
pitNum++;
if(pitNum==6)
pitNum=7;
else if(pitNum==14)
pitNum=0;
}
}
boolean res=anotherTurn(pitNum);
if(!res){
capture(pitNum,temp);
if(turn==0)
turn=1;
else turn=0;}
}
private boolean anotherTurn(int pitNum)
{pitNum--;
boolean temp=false;
if(turn==0)
{if(pitNum==6)
{turn=0;
temp=true;
}
}
else
if(pitNum==-1)
{turn=1;
temp=true;
}
return temp;
}
private void capture(int pitNum, int pit)
{
pitNum--;
if(turn==0){
if(sidePit[pitNum]==1 && pitNum<6)
{
if(pitNum==0)
{
sidePit[6]=sidePit[6]+sidePit[12]+1;
sidePit[12]=0;
}
else if(pitNum==1)
{
sidePit[6]=sidePit[6]+sidePit[11]+1;
sidePit[11]=0;
}
else if(pitNum==2)
{
sidePit[6]=sidePit[6]+sidePit[10]+1;
sidePit[10]=0;
}
else if(pitNum==3)
{
sidePit[6]=sidePit[6]+sidePit[9]+1;
sidePit[9]=0;
}
else if(pitNum==4)
{
sidePit[6]=sidePit[6]+sidePit[8]+1;
sidePit[8]=0;
}
else if(pitNum==5)
{
sidePit[6]=sidePit[6]+sidePit[7]+1;
sidePit[7]=0;
}
sidePit[pitNum]=0;
}
}
if(turn==1)
{ //pitNum=pitNum;
if(sidePit[pitNum]==1 && pit+7>6)
{
if(pitNum==7)
{
sidePit[13]=sidePit[13]+sidePit[5]+1;
sidePit[7]=0;
}
else if(pitNum==8)
{
sidePit[13]=sidePit[13]+sidePit[4]+1;
sidePit[4]=0;
}
else if(pitNum==9)
{
sidePit[13]=sidePit[13]+sidePit[3]+1;
sidePit[3]=0;
}
else if(pitNum==10)
{
sidePit[13]=sidePit[13]+sidePit[2]+1;
sidePit[2]=0;
}
else if(pitNum==11)
{
sidePit[13]=sidePit[13]+sidePit[1]+1;
sidePit[1]=0;
}
else if(pitNum==12)
{
sidePit[13]=sidePit[13]+sidePit[0]+1;
sidePit[0]=0;
}
sidePit[pitNum]=0;
}
}
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class RandomPlayer extends KalaPlayer{
//KalaGameState state;
public int chooseMove(KalaGameState gs) throws NoMoveAvailableException
{int[] moves;
moves=getMoves(gs);
try{
for(int i=0;i<=5;i++)
System.out.println(moves[i]);
for(int i=0;i<=5;i++)
{
if(moves[i]==1)
{
KalaGameState state=(KalaGameState) gs.clone();
state.makeMove(moves[i]);
gs.getTurn();
moves[i]=evalValue(state.getScore(0),state.getScore(1));
}
}
}
catch(IllegalMoveException e)
{
System.out.println(e);
//chooseMove(state);
}
return 10;
}
private int evalValue(int score0,int score1)
{
int score=0;
//int score0=0;
// int score1=0;
//getScore(0);
//score1=state.getScore(1);
//if((state.getTurn())==0)
score=score1-score0;
//else
//score=score1-score0;
System.out.println("score: "+score);
return score;
}
public int[] getMoves(KalaGameState gs)
{
int[] moves=new int[6];
for(int i=1;i<=6;i++)
{
if(gs.getNumStones(i)!=0)
moves[i-1]=1;
else moves[i-1]=0;
}
return moves;
}
}
你能解释一下哪里出了问题吗?
当我克隆KalaGameState
KalaGameState状态=(KalaGameState)gs.clone();
state.makeMove(moves[i]);
gs.getTurn();
当我调用state.makemove(...)时,它所做的更改也反映在gs实例中
你已经获得了所谓的对象的“浅拷贝”。 基本上所有的原语都被复制过来,包括对象引用(本例中的数组)。
你想要的是“深层复制”。 有几种方法可以解决这个问题,一种方法是使用克隆,另一种方法创建一个新的构造函数,它接收对象并将其全部复制(您必须创建一个新数组并将每个项目逐个复制到其中) , 例如)。
最简单的方法就是阅读这篇文章,从头开始(不一定是最好的)。
你需要clone()
int[] sidePit
(否则会在this
和它的clone()
之间共享。
KalaGameState clone = (KalaGameState) super.clone();
clone.sidePit = this.sidePit.clone();
return clone;
这应该可以解决您的问题,但是您也应该知道,Java中的克隆被认为是中断的。
关于clone()
行情
如果您在我的书中阅读过关于克隆的内容,尤其是如果您在各行之间阅读的话,那么您会知道我认为克隆已经彻底崩溃了。
来源:乔希布洛赫在设计 - 复制构造与克隆
所有共享参考文献中的突变问题
String[]
; String
是不可变的; 数组不是 问题是sidePit是对数组的引用。 对super.clone()
的调用正在创建一个新的KalaGameState,但sidePit
指向同一个数组。 super.clone()
方法(和整个Clonable接口)只有在对象由基元和字符串(或任何其他不可变对象)组成时才起作用。 但是,对于您的课程,您需要一个如下所示的克隆:
public KalaGameState clone() {
KalaGameState result = new KalaGameState();
result.sidePit = sidePit.clone();
return result;
}
链接地址: http://www.djcxy.com/p/40795.html
上一篇: Original object is also changed when values of cloned object are changed
下一篇: Java: recommended solution for deep cloning/copying an instance