我正在处理一个对象中的函数,该对象将对象列表作为参数并将其内容克隆到自己的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;
}
}
答案 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
课程的y
和Piece
字段的访问权限,这似乎很奇怪。
你的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)
首先,Clonable
是commonly recommended to be avoided,因此我建议您改为实现复制构造函数或自己的复制方法。
这是我建议的实施方式:
为了从polymorphism中受益,请添加一个抽象方法,以便在Piece
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;
}
color
,x
和y
都是原始类型,这意味着在赋值时会复制该值。但是,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;
}
}