1、Java中的一般复制操作
java里的每一个对象以引用的方式进行操作,每次赋值操作涉及的也只是将一个对象的引用赋值,这样的结果是让这个对象多了一个引用而已。例如
class A {}
A obj1 = new A() ;
A obj2 = obj1;//
上面obj1和obj2其实都是指向同一个内存对象,这样对obj1的修改也会反应到obj2中。
而java中涉及到的很多数组的复制函数都是这种类型的浅复制(仅复制引用,而没有复制引用所指向的实际内存对象)。如 System.arraycopy , Arrays.copyOf,Arrays.fill等,对于java基本类型(short , int , long , float , double , byte , char , boolean),这种复制没关系,但是对于类对象就会出现我们不需要的情况。
java.lang.System类中
native void arraycopy( Object[] src , int srcPos , Object[] dst , int dstPos , int length ) ;该函数把src里的对象复制到dst中,其中复制的也只是引用
java.util.Arrays类中
void fill(Object[] a , Object val ) ;//将val填充到a中,此时将val引用复制到a中每个元素,这样其实是a中每个元素都只是对同一个内存对象的引用
比如:
class Point implements Cloneable {
private int x , y ;
public Point( int x , int y ) {
this.x = x ; this.y = y ;
}
public String toString() {
return "("+this.x + "," + this.y + ")" ;
}
public void modify( int newX , int newY ) {
this.x = newX ; this.y = newY ;
}
}
public class ArrayCopy {
public static void main( String[] args ) {
Point[] pointArray = new Point[5] ;
Point p1 = new Point( 1 , 1 ) ;
Arrays.fill( pointArray , p1 ) ;
System.out.println( Arrays.deepToString( pointArray) ) ;
System.out.println() ;
pointArray[0].modify( 2 , 3 ) ;
System.out.println( Arrays.deepToString( pointArray ) ) ;
Point[] pointArray2 = new Point[4] ;
System.arraycopy( pointArray , 0 , pointArray2 , 0 , 4 ) ;
System.out.println( Arrays.deepToString( pointArray2 )) ;
pointArray2[1].modify( 3 , 5 ) ;
System.out.println(Arrays.deepToString( pointArray2 )) ;
Point[] pointArray3 = Arrays.copyOf( pointArray2 , 4 ) ;
System.out.println( Arrays.deepToString( pointArray3 )) ;
pointArray3[2].modify( 0 , 0 ) ;
System.out.println( Arrays.deepToString( pointArray3 )) ;
System.out.println( p1 ) ;
}
}
此时输出结果为
[(1,1), (1,1), (1,1), (1,1), (1,1)]
[(2,3), (2,3), (2,3), (2,3), (2,3)]
[(2,3), (2,3), (2,3), (2,3)]
[(3,5), (3,5), (3,5), (3,5)]
[(3,5), (3,5), (3,5), (3,5)]
[(0,0), (0,0), (0,0), (0,0)]
(0,0)
这说明,在每次数组复制时都只是对引用的复制
2、实现java的深复制
利用java的基类Object中的clone方法。
⑴clone方法将对象复制了一份并返回给调用者(其实,此时的复制也是浅复制,若被复制的对象里含有非基本类型的对象,那么此时复制时也只是对引用进行复制)。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
⑵Java中对象的克隆
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法(该clone()方法为protected,若想类实现clone必须将其申明为public类型)。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone(),同时对该被复制对象里的非基本类型对象调用其自身的clone()函数(当然必须保证这种类型本身已经实现了clone接口)。
④在派生类中实现Cloneable接口。
那么通过clone函数得到的复制对象可以获得深复制效果,比如
class Point implements Cloneable {//该类实现了clone函数
private int x , y ;
public Point( int x , int y ) {
this.x = x ; this.y = y ;
}
public String toString() {
return "("+this.x + "," + this.y + ")" ;
}
public void modify( int newX , int newY ) {
this.x = newX ; this.y = newY ;
}
public Object clone() throws CloneNotSupportedException{
Point result ;
try{
result = (Point)super.clone() ;
}catch ( CloneNotSupportedException e ) {
throw e ;
}
return result ;
}
}
class PointNoClone {//没有实现clone函数
private int x , y ;
public PointNoClone( int x , int y ) {
this.x = x ; this.y = y ;
}
public void modify( int x , int y ) {
this.x = x ; this.y = y ;
}
public String toString() {
return "(" + this.x + "," + this.y + ")" ;
}
}
class PointHolder implements Cloneable {
private Point point ;
private PointNoClone pointNoclone ;
public PointHolder ( Point p , PointNoClone p2 ) {
this.point = p ;
this.pointNoclone = p2 ;
}
public Object clone() throws CloneNotSupportedException {
PointHolder result ;
try{
result = (PointHolder)super.clone() ;
result.point = (Point)this.point.clone() ;
}catch( CloneNotSupportedException e ) {
throw e ;
}
return result ;
}
public Point getPoint() {
return this.point ;
}
public PointNoClone getPointNoClone() {
return this.pointNoclone ;
}
public String toString() {
return "point:" + point.toString() + "\npointNoclone:" + pointNoclone.toString() ;
}
}
public class ArrayCopy {
public static void main( String[] args ) {
PointHolder pointHolder = new PointHolder( new Point( 20 , 20 ) , new PointNoClone( 15 , 15)) ;
PointHolder copyPointHolder = null ;
try{
copyPointHolder = (PointHolder)pointHolder.clone() ;
}catch( CloneNotSupportedException e ) {
e.printStackTrace() ;
}
copyPointHolder.getPoint().modify( 30 , 30 ) ;
copyPointHolder.getPointNoClone().modify( 25 , 25) ;
System.out.println("pointHolder\n" + pointHolder ) ;
System.out.println("copyPointHolder\n" + copyPointHolder) ;
}
}
运行结果为:
在PointHolder中实现了clone的对象得到了深复制的效果,而没有实现clone的pointNoClone只是浅复制