Java版顺序表的浅拷贝与深拷贝(一)
Java的类采用拷贝构造方法实现复制对象功能,声明格式如下:
类(类 对象){
this.成员变量 = 参数对象.成员变量;//逐域赋值,以参数的实例值初始化当前实例
}
一个类的拷贝构造方法通常实现为成员变量逐域赋值,即将当前对象的各成员变量赋值为实例参数对应的各成员变量的值,称为浅拷贝。
在Java中的类采用引用模型,当一个对象作为方法参数或返回值时,实参向形参传递的是对象的引用,都没有执行拷贝构造方法。因此,Java不提供默认拷贝构造方法。
(1)顺序表的浅拷贝
public SeqList(SeqList<T> list) {//拷贝构造方法,复制对象,浅拷贝
this.n = list.n;
this.element = list.element;
}
其中this.n是int整数,赋值运算复制了整数值。而数组是引用类型,赋值运算传递的是引用,没有申请新的存储空间。this.element = list.element,this.element变量获得了list.element数组引用,使得this和list两个对象的element变量引用同一个数组,this对象没有申请自己的数组空间。
public static void main(String[] args) {
String[] values = { "A", "B", "C", "D", "E" };
SeqList<String> lista = new SeqList<String>(values);
SeqList<String> listb = new SeqList<String>(lista);
System.out.println("lista = " + lista.toString());
System.out.println("listb = " + listb.toString());
}
运行结果如下:
lista = A,B,C,D,E
listb = A,B,C,D,E
上面代码的执行情况如下图所示
两个对象引用同一个数组,造成修改、插入、删除等操作结果相互影响,这是错误的。例如执行下面的代码,删除lista的一个元素时,实际上也删除了listb的元素,但list.n长度没有改变。
public static void main(String[] args) {
String[] values = { "A", "B", "C", "D", "E" };
SeqList<String> lista = new SeqList<String>(values);
SeqList<String> listb = new SeqList<String>(lista);
System.out.println("lista = " + lista.toString());
System.out.println("listb = " + listb.toString());
lista.remove(0);
System.out.println("remove lista = " + lista.toString());
System.out.println("listb = " + listb.toString());
}
运行结果如下:
lista = A,B,C,D,E
listb = A,B,C,D,E
remove lista = B,C,D,E
Exception in thread "main" java.lang.NullPointerException
at com.zxl.linklist.SeqList.toString(SeqList.java:58)
at com.zxl.linklist.SeqList.main(SeqList.java:73)
上面代码运行是有错误的,执行过程的情况如下图:
综上所述:
(1)当成员变量的数据类型是基本数据类型时,浅拷贝可以实现对象复制功能
(2)当成员变量是引用数据类型时,浅拷贝只复制了数组引用或对象引用,并没有实现对象复制功能。此时,拷贝构造方法就需要实现为深拷贝。
浅拷贝运行的完整代码如下:
public class SeqList<T> {
private int n;
private Object[] element;
/**
* 构造长度为length的空表
*/
public SeqList(int length) {
this.element = new Object[length];
this.n = 0;
}
/**
* 构造顺序表,由values数组提供元素
*/
public SeqList(T[] values) {
this(values.length);
for (int i = 0; i < values.length; i++) {
this.element[i] = values[i];
}
this.n = element.length;
}
public SeqList(SeqList<T> list) {
this.n = list.n;
this.element = list.element;
}
/**
* @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) {
String[] values = { "A", "B", "C", "D", "E" };
SeqList<String> lista = new SeqList<String>(values);
SeqList<String> listb = new SeqList<String>(lista);
System.out.println("lista = " + lista.toString());
System.out.println("listb = " + listb.toString());
lista.remove(0);
System.out.println("remove lista = " + lista.toString());
System.out.println("listb = " + listb.toString());
}
}