用Java克隆列表

时间:2016-11-27 19:05:12

标签: java oop inheritance deep-copy

我正在处理一个对象中的函数,该对象将对象列表作为参数并将其内容克隆到自己的List中。修改新列表不应该影响传入的List。我知道列表将通过引用传递,但列表中的对象是通过引用还是值传递的? (对不起,如果这听起来很愚蠢)

我传递了一个片段列表(pawn,rook等),它扩展了Piece类。我正在考虑在Piece类中创建一个clonePiece()函数,但我不知道如何去做。这就是我到目前为止所做的:

    public void copyPieces(List<Piece> whitePieces, List<Piece> blackPieces){
    for (int i = 0; i < whitePieces.size(); i++){
        this.whitePieces.add(whitePieces.get(i).clonePiece());
    }
    for (int i = 0; i < blackPieces.size(); i++){
        this.whitePieces.add(blackPieces.get(i).clonePiece());
    }

如何在抽象类中实现clonePiece()函数,以创建其继承类的新实例?

编辑:

public abstract class Piece {
private int color;
private int x;
private int y;

public Piece (int color, int x, int y){
    this.color = color;
    this.y = y;
    this.x = x;
}

public int getColor(){
    return this.color;
}
public int getX(){
    return this.x;
}
public int getY(){
    return this.y;
}

public void move(int x, int y, Board board){
    board.getGameTiles()[this.x][this.y].setToUnoccupied();
    this.x = x;
    this.y = y;
}

public abstract ArrayList<Move> getMoves(Board board);

public Piece clonePiece(){
    return this;
}

}

public class Rook extends Piece{

int x, y, color;
private ArrayList<Move> moves;

public Rook(int color, int x, int y) {
    super(color, x, y);
    this.x = x;
    this.y = y;
    this.color = color;
    moves = new ArrayList<>();
}

@Override
public ArrayList<Move> getMoves(Board board) {

    //moves right
    int a = 1;
    while(UtilFunctions.isInBoundaries(x+a, y)){
        if(!board.getGameTiles()[x+a][y].isTileOccupied()){
            //add move type 0 for passive move
            moves.add(new Move(x, y, x+a, y, 0));
        }
        else{
            if(board.getGameTiles()[x+a][y].getPiece().getColor() != this.color){
                //add move type 1 for attack move
                moves.add(new Move(x, y, x+a, y, 1));
            }
            break;
        }
        a++;
    }

    //moves left
    a = -1;
    while(UtilFunctions.isInBoundaries(x+a, y)){
        if(!board.getGameTiles()[x+a][y].isTileOccupied()){
            //add move type 0 for passive move
            moves.add(new Move(x, y, x+a, y, 0));
        }
        else{
            if(board.getGameTiles()[x+a][y].getPiece().getColor() != this.color){
                //add move type 1 for attack move
                moves.add(new Move(x, y, x+a, y, 1));
            }
            break;
        }
        a++;
    }

    //moves up
    a = 1;
    while(UtilFunctions.isInBoundaries(x, y+a)){
        if(!board.getGameTiles()[x][y+a].isTileOccupied()){
            //add move type 0 for passive move
            moves.add(new Move(x, y, x, y+a, 0));
        }
        else{
            if(board.getGameTiles()[x][y+a].getPiece().getColor() != this.color){
                //add move type 1 for attack move
                moves.add(new Move(x, y, x, y+a, 1));
            }
            break;
        }
        a++;
    }

    //moves down
    a = -1;
    while(UtilFunctions.isInBoundaries(x, y+a)){
        if(!board.getGameTiles()[x][y+a].isTileOccupied()){
            //add move type 0 for passive move
            moves.add(new Move(x, y, x, y+a, 0));
        }
        else{
            if(board.getGameTiles()[x][y+a].getPiece().getColor() != this.color){
                //add move type 1 for attack move
                moves.add(new Move(x, y, x, y+a, 1));
            }
            break;
        }
        a++;
    }

    return moves;
}

}

4 个答案:

答案 0 :(得分:1)

您的子课程不应该包​​含父类课程以外的任何字段。在这个层面上没有任何本质上的不同。从子类中删除其他字段,然后授予对父类Piece字段的访问权限。

abstract class Piece {

    Piece(boolean white, int x, int y){
        //set fields
        ...
    }

    public abstract Piece copyPiece();
}

然后在所有子类中实现copyPiece()方法。然后致电:

public void copyPieces(List<Piece> whitePieces, List<Piece> blackPieces){
    for (Piece whitePiece : whitePieces){
        this.whitePieces.add(whitePiece.copyPiece());
    }
    for (Piece blackPiece : blackPieces){
        this.blackPieces.add(blackPiece.copyPiece());
    }
}

发布代码后编辑:

由于发布的代码,我的原始答案不合适。相应修改。

有些事情对我来说很奇怪。首先,颜色可以是布尔值white,因为只有两种颜色。接下来,您的Rook课程无法设置对父x课程的yPiece字段的访问权限,这似乎很奇怪。

你的clonePiece课除了自己什么都不做,这根本不是克隆。克隆将是:return new Piece(this.color, this.x, this.y);

接下来,您的move(x, y, board)方法不正确。首先,考虑不传入board并让使用move方法的类成为操纵它的类。如果你不想走这条路,你必须在棋盘上设置棋子的新位置,而不仅仅是删除旧棋盘。

答案 1 :(得分:1)

让作品返回自己的#copy方法(或使用Clonable):

public abstract class Piece {

    public Piece copy() {
        //return copy
    }
}

这可以类似地用于子类:

public class Rook extends Piece {

    @Override
    public Rook copy() {
        //return copy
    }
}

然后,当您有Piece个对象的列表时,只需在对象上调用#copy并替换列表中的引用即可。例如:

List<Piece> pieces = /* some list */;
List<Piece> copy = new ArrayList<>(pieces);
copy.replaceAll(Piece::copy); //replace references with copies

答案 2 :(得分:1)

首先,Clonablecommonly recommended to be avoided,因此我建议您改为实现复制构造函数或自己的复制方法。

这是我建议的实施方式:

为了从polymorphism中受益,请添加一个抽象方法,以便在Piece

中制作deep copies
public abstract Piece deepCopy();

以及子类中的相应实现

@Override
public Rook deepCopy() {
    Rook rook = new Rook(this.getColor(), this.getX(), this.getY());
    for (Move m : this.moves) {
        rock.addMove(new Move(m));
    }
    return rook;
}

colorxy都是原始类型,这意味着在赋值时会复制该值。但是,Rook还包含字段move,它是引用类型Move的列表。这意味着为了能够进行深层复制,Move类还需要包含复制构造函数或复制方法。前者显示在这里。

public Move(Move move) {
    this(move.x, move.y);
}

最后,以Java 7方式复制您的作品列表:

List<Piece> newList = new ArrayList<>();
for (Piece p : oldList) {
    newList.add(p.deepCopy());
}

或Java 8方式(如Darshan Mehta之前建议的那样):

List<Piece> newList = whitePieces.stream()
    .map(p -> p.deepCopy())
    .collect(Collectors.toList());

答案 3 :(得分:0)

编辑更新了示例以支持继承

您可以使free类实现Piece接口并覆盖impl类中的clone方法。 Piece和Rook类看起来像这样:

Cloneable

完成此操作后,您可以在任何棋子对象上调用此方法并获取深度克隆实例。下面是深入克隆片段的Java 8流示例:

abstract class Piece implements Cloneable{
    int x;
    int y;

    protected void copy(Piece p){
        p.x = this.x;
        p.y = this.y;
    }
}

class Rook extends Piece{
    int z;

    @Override
    public Object clone(){
        Rook rook = new Rook();
        super.copy(rook);
        rook.z = this.z;
        return rook;
    }
}