clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。
clone 与 "="的区别
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User("hl", "1234");
User user2 = user;
System.out.println(user == user2); //true
User user3 = (User) user.clone();
System.out.println(user == user3); //false
}
“=” : 引用指向同一个对象(内存地址)
clone : 开辟新内存,指向不同对象(内存地址)
例1:
tatic void test1(){
int[] array = {1,2,3,4};
int[] clone = array.clone();
array[2] = 6;
System.out.println(Arrays.toString(array)); // [1, 2, 6, 4]
System.out.println(Arrays.toString(clone)); // [1, 2, 3, 4]
clone[2] = 7;
System.out.println(Arrays.toString(array)); // [1, 2, 6, 4]
System.out.println(Arrays.toString(clone)); // [1, 2, 7, 4]
}
例2:
static void test3(){
int[][] array = {{1,2},{3,4,5}};
int[][] clone = array.clone();
array[0][0] = 6;
for (int[] is : array) {
System.out.print(Arrays.toString(is)); //[6, 2][3, 4, 5]
}
System.out.println("");
for (int[] is : clone) {
System.out.print(Arrays.toString(is)); //[6, 2][3, 4, 5]
}
表象 : 例1中改变原数组的值 不会引起克隆数组的变化,而例2克隆数组会随着原数组的变化而发生变化 .
java克隆时,如果克隆的对象的各属性都是简单数据项,那么克隆出来的结果无误,也就是浅拷贝。
如果对象的属性中存在引用的话,那克隆出来的对象会和原对象指向相同的引用地址,这时候想克隆,需要深拷贝。
clone并不能直接作用于二维数组。
因为java中没有二维数组的概念,只有数组的数组。
所以二维数组int array[][] 中存储的实际上是两个一维数组的引用。当调用clone函数时,是对这两个引用进行了复制。
浅拷贝?
public class Person implements Cloneable {
private int age;
private Head head;
public Person(Head head) {
super();
this.head = head;
}
public Person() {
super();
}
static class Head{
private Mouth mouth;
private int num;
public Head(Mouth mouth) {
super();
this.mouth = mouth;
}
public Head() {
super();
}
}
static class Mouth{
}
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person(new Head(new Mouth()));
Person clone = (Person)person.clone();
//1
System.out.println(person == clone); //false
//2
clone.age = 4;
System.out.println(person.age +"-" +clone.age); //0-4
//3
System.out.println(person.head == clone.head); //true
//4
System.out.println(person.head.num +"---" + person.head.num); //null---null
person.head.num = 1;
System.out.println(person.head.num +"---" + person.head.num); //1---1
clone.head.num = 2;
System.out.println(person.head.num +"---" + person.head.num); //2---2
//5
System.out.println(person.head.mouth == clone.head.mouth); //true
}
}
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值 [ 对应代码中2,4 ];如果属性是内存地址(引用类型),拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。[ 对应代码中3,5 ]
浅拷贝
如何实现深拷贝?
深拷贝
1. 实现Cloneable接口,重写对象的clone方法
public class Person implements Cloneable { //实现Cloneable接口
private Head head;
public Person(Head head) {
super();
this.head = head;
}
public Person() {
super();
}
static class Head implements Cloneable{ //实现Cloneable接口
private Mouth mouth;
public Head(Mouth mouth) {
super();
this.mouth = mouth;
}
public Head() {
super();
}
//重写Head对象的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
static class Mouth {
}
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person(new Head(new Mouth()));
Person clone = (Person)person.clone();
//1
System.out.println(person == clone); //false
//2
System.out.println(person.head == clone.head); //false
//3
System.out.println(person.head.mouth == clone.head.mouth); //true
}
//重写Person对象的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Person person = new Person(new Head(new Mouth()));
person.head = (Head) head.clone();
return person;
}
}
如果要实现对象的深拷贝,必须重写该对象的clone方法.如果一个对象中引用的对象又引用另一个对象 如:Person -> Head -> Mouth 则必须重写Person和Head的clone方法,以此类推有n个对象嵌套引用则需要重写n-1个对象的clone方法,因此用这种方法实现彻底的深拷贝基本不可能.
2. 利用序列化
public class SerializableTest {
public static void main(String[] args) throws ClassNotFoundException, IOException, CloneNotSupportedException {
Person1 person = new Person1(new Head());
Person1 cloneT = (Person1) person.cloneT(); //序列化
Person1 clone = (Person1) person.clone(); //重写clone()
System.out.println("cloneT--"+ (person == cloneT)); //false
System.out.println("cloneT--" + (person.head == cloneT.head)); //false
System.out.println("------------------------------------");
System.out.println("clone--"+ (person == clone)); //false
System.out.println("clone--" + (person.head == clone.head)); //true
}
}
class Person1 implements Serializable,Cloneable{
private static final long serialVersionUID = 1L;
public Head head;
public Person1(Head head) {
super();
this.head = head;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
public Object cloneT() throws IOException, ClassNotFoundException{
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
class Head implements Serializable{
private static final long serialVersionUID = 1L;
}