2016-11-27 89 views
0

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

我正在传递一个片断(典当,白嘴鸦等)的列表,它扩展了一个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; 
} 

}

+0

你想克隆片自己呢?是不可变的还是它们包含一些可变状态? –

+0

是的,我想克隆自己的作品,并把它们放入新的列表中。不确定可变性(我对编程非常陌生),但Pieces只是扩展了Piece类的类。 (即骑士,主教) –

+0

你能张贴'Piece'类的代码和它的一个后代呢? –

回答

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类不能访问父类Piece类的xy字段。

你的clonePiece类别只会返回自己,这根本不是克隆。克隆将是:return new Piece(this.color, this.x, this.y);

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

+0

这不会是因为他使用继承工作。 –

+0

对不起,我很新的节目,但你将如何在其后代复制领域的海贼王类?假设我想复制从Piece继承的主教。 “新片(whitePiece)”如何访问主教中的数据? –

+0

你的Rook类不应该有任何额外的领域比一块。在野外,没有什么与从车到兵的本质区别。删除所有子类的字段。 –

0

编辑更新的例子来支持继承

您可以Piece类实现Cloneable接口,并在实现了一套类重写clone方法。件和鲁克类将是这样的:

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

一旦做到这一点,你可以调用任何一件物体上这种方法,并获得深克隆的实例。下面是Java的8个流例子是件深克隆列表:

List<Rook> pieces = new ArrayList<>(); 

List<Piece> cloned = pieces.stream() 
        .map(p -> (Piece) p.clone()) 
        .collect(Collectors.toList()); 

} 
+0

不起作用,他正在使用继承。 –

+0

@ToddSewell更新了支持继承的答案 –

+0

我会在每个继承自piece的类中实现clone()函数吗?如果是这种情况,我可以在Piece对象上调用.clone()吗?例如,如果我想克隆一个List whitePieces,即使clone()没有在Piece中定义,我仍然可以调用whitePieces.get(0).clone()吗? –

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并将其替换为引用es在你的列表中。例如:

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

Piece类中copy()中的代码是什么?如果我在Piece类中创建copy()抽象并在每个继承类中重写它,它会起作用吗? –

+0

当然,这是合理的。这个想法是简单地让你的'#copy' /'#clone'为每个子类创建一个新的适当的实例。将其抽象化将强制任何实现子类提供副本。附加的好处是每个子类都可以确保其中的内容(例如列表)被适当地复制。 – Rogue

1

首先,Clonablecommonly recommended to be avoided,所以我会建议你,而不是实现一个拷贝构造函数或你自己的复制方法。

这是我建议的落实:

为了从polymorphism受益,在Piece

public abstract Piece deepCopy(); 

添加一个抽象方法制作deep copies和相应的实现在子类中

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

color,xy都是基本类型,这意味着在赋值时,该值被复制。但是,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());