Java版顺序表的浅拷贝与深拷贝(二)
当一个类包含数组或对象等引用类型的成员变量时,该类声明的拷贝构造方法,不仅要复制基本类型的成员变量的值,还要为引用类型变量申请存储空间,并复制其中所有对象,这种复制方式称为深拷贝。
SeqList<T> 类声明深拷贝构造方法如下,申请数组存储空间复制所有数组元素。
public SeqList(SeqList<T> list) {//深拷贝构造方法,复制list
this.n = list.n;
this.element = new Object[list.element.length];//申请一个数组空间
for (int i = 0; i < list.n; i++) {//复制数组中所有元素
this.element[i] = list.element[i];
}
}
SeqList<T>深拷贝执行结果如下图(a),listb.element申请新的数组空间,使得lista.element与listb.element分别引用各自的数组。
SeqList深拷贝之后,lista和listb拥有自己的element数组空间,进行插入和删除操作时互不影响,但是,因为对象赋值是引用赋值,深拷贝只是对数组进行了空间申请,对于数组中的对象元素并没有申请新的空间,所以导致lista.element和listb.element两个数组对应元素引用相同实例,如果进行修改操作,仍会影响对方。执行下面代码查看运行结果
public static void main(String[] args) {
int n = 5;
SeqList<StringBuilder> lista = new SeqList<StringBuilder>(n - 1);
for (int i = 0; i < n; i++) {
lista.insert(new StringBuilder(((char)('A' + i) + "")));// 尾插入
}
SeqList<StringBuilder> listb = new SeqList<StringBuilder>(lista);// 执行拷贝构造方法
System.out.println("图(a), lista = " + lista.toString());
System.out.println(" listb = " + listb.toString());
lista.insert(new StringBuilder("F"));//lista在最后插入一个元素F
listb.remove(listb.n - 1);//listb删除最后一个元素
StringBuilder strBud = lista.get(0);
strBud.setCharAt(0, 'X');//lista修改第一个元素为X
System.out.println("图(b), lista = " + lista.toString());
System.out.println(" listb = " + listb.toString());
}
对应的内存空间变化如下图:
如图上图(c)所示。
完整的运行程序代码如下:
public class SeqList<T> {
private int n;
private Object[] element;
/**
* 构造长度为length的空表
*/
public SeqList(int length) {
this.element = new Object[length];
this.n = 0;
}
public SeqList(SeqList<T> list) {// 深拷贝构造方法,复制list
this.n = list.n;
this.element = new Object[list.element.length];// 申请一个数组空间
for (int i = 0; i < list.n; i++) {// 复制数组中所有元素
this.element[i] = list.element[i];
}
}
/**
*获取一个元素
*/
public T get(int i) {
if (i >= 0 && i < this.n) {
return (T) this.element[i];
}
return null;
}
/**
* 插入一个元素
*/
public void set(int i, T x) {
if (x == null) {
throw new NullPointerException("x==null");
}
if (i >= 0 && i < this.n) {
this.element[i] = x;
} else {
throw new IndexOutOfBoundsException();
}
}
/**
* 插入一个数据元素
*/
public void insert(T x) {
Object[] source = this.element;
if (this.n == element.length) {
this.element = new Object[element.length * 2];
for (int i = 0; i < source.length; i++) {
this.element[i] = source[i];
}
}
this.element[this.n] = x;
this.n++;
}
/**
* @param i
* 删除第i个元素
*/
public T remove(int i) {
if (this.n > 0 && i >= 0 && i < this.n) {
T old = (T) this.element[i];
for (int j = i; j < this.n - 1; j++) {
this.element[j] = this.element[j + 1];// 从i+1开始向前移动一个位置
}
this.element[this.n - 1] = null;
this.n--;
return old;
}
return null;
}
/**
* 返回顺序表所有元素的数据
*/
public String toString() {
String str = "";
if (this.n > 0) {
str = this.element[0].toString();
for (int i = 1; i < this.n; i++) {
str += "," + this.element[i].toString();
}
}
return str;
}
public static void main(String[] args) {
int n = 5;
SeqList<StringBuilder> lista = new SeqList<StringBuilder>(n - 1);
for (int i = 0; i < n; i++) {
lista.insert(new StringBuilder(((char)('A' + i) + "")));// 尾插入
}
SeqList<StringBuilder> listb = new SeqList<StringBuilder>(lista);// 执行拷贝构造方法
System.out.println("图(a), lista = " + lista.toString());
System.out.println(" listb = " + listb.toString());
lista.insert(new StringBuilder("F"));//lista在最后插入一个元素F
listb.remove(listb.n - 1);//listb删除最后一个元素
StringBuilder strBud = lista.get(0);
strBud.setCharAt(0, 'X');//lista修改第一个元素为X
System.out.println("图(b), lista = " + lista.toString());
System.out.println(" listb = " + listb.toString());
}
}
运行结果如下:
图(a), lista = A,B,C,D,E
listb = A,B,C,D,E
图(b), lista = X,B,C,D,E,F
listb = X,B,C,D