复制构造函数的一个问题

An Issue of Copy Constructor

我创建了一个 class 机器人,它具有两个属性:方向(它只是一个字符串 E、A、S、N)和位置(一个包含 4 个整数的数组,用于在两个方向上保持位置). class 有主要的构造函数:

public Robot (int east, int north, int west, int south, int direction) {
this.direction = direction%4 ;
location = new int[4] ;
int[] location = {east,north,west,south} ; }

还有一个拷贝构造函数:

Robot( Robot copy ) {
    direction = copy.direction ;
    location = copy.location ;
  }

它也有方法,但我想展示这两个方法:move() 和 setDirection()。

public void move() {
    location[direction]++ ;
  }

public void setDirection( int direction ) {
    this.direction = direction ;
  }

我创建了一个 Robot 对象并将其等同于一个新对象,还通过复制构造函数使用了另一个新对象:

  Robot terminator = new Robot(0,0,0,0,1) ;
  Robot b = terminator ;
  Robot a = new Robot(terminator) ;

问题来了,当我对终止符 a 或 b 使用 move() 方法时,其他位置都发生了变化,但是当我对终止符使用 setDirection 时,a 没有改变,但 b 发生了变化。此外,当我对 a 使用相同时,b 的 none 和终结符的方向会发生变化。那么区别是什么呢?为什么在终结器上实现的 move() 方法会影响副本,但在使用 setDirection() 时却不会?

System.out.println(terminator) ;
System.out.println(a) ;
System.out.println(b) ;

terminator.setDirection(2);
a.setDirection(3) ;
terminator.move() ;

System.out.println(terminator) ;
System.out.println(a) ;
System.out.println(b) ;

输出:

Location[0, 0, 0, 0]Direction N
Location[0, 0, 0, 0]Direction N
Location[0, 0, 0, 0]Direction N
Location[0, 0, 1, 0]Direction W
Location[0, 0, 1, 0]Direction S
Location[0, 0, 1, 0]Direction W

两个 Robot 实例都持有对同一位置 int[] 的引用。您需要在创建新的 Robot 实例时创建一个新数组,例如,使用 Arrays.copyOf:

Robot( Robot copy ) {
    direction = copy.direction ;
    location = Arrays.copy(copy.location, copy.location.length);
    // Here ---^
}

看看你的构造函数:

Robot( Robot copy ) {
   direction = copy.direction ; 
   location = copy.location ;
}

你在这里做的是浅拷贝。

您的 direction 是原始类型,因此您复制的 Robot 获得原始 Robot 方向值的副本。他们对 direction 变量

的引用不同

同时,您的 location 是一个数组,因此您复制的 Robot 获得了对原始 Robot 位置的引用。 Robot 都具有相同的 location 数组。改变一个会影响另一个。

如果你想分开两个Robot实例,你必须做一个deep copy数组location

而不是:

location = copy.location;

做:

location = Arrays.copyOf(copy.location, copy.location.length);