03 JAVA 数组补充 拷贝、序列化

previous: 也是狗(本来我想要一个表情来表示这个字,没错,提交之后整篇文章都不见了,坑爹的,我又写了一遍,这件事告诉不要乱用表情)了,拷贝还要分多么多类型,其实之前也是学过的,不过身为自豪的学渣,不负己望,我已经忘啦~


1. 概念

浅拷贝会创建一个新对象,但是对象的引用类型成员还是会指向被复制对象的引用类型成员,与浅拷贝不同,深拷贝会为拷贝引用类型成员动态到动态分配的内存中。而懒惰拷贝其实很简单,就是开始的时候是浅拷贝,只有当某个引用想要修改某个共享数据的时候才会进行深拷贝,但是呢,惰性拷贝需要有计数器来记录引用的次数,所以开销还是挺大的~



2. java中的Object类中提供了clone()方法,具有下面的功能:

- x.clone() != x 

- x.clone().getClass() = x.getClass() 两个对象是同一个类型

- x.clone().equals(x) 内容一样

3. 实现

- 浅拷贝

class Employee implements Cloneable{
	String name;
	Car car;
	Employee(String name, String carName) {
		this.name =  name;
		car = new Car(carName);
	}
	
	public Object clone(){
		try {
			return super.clone();
			//Employee e = new Employee(name, car.name);
			//return e;
		}
		catch(CloneNotSupportedException e) {
			return null;
		}
	}
}

class Car {
	String name;
	Car(String name) {
		this.name = name;
	}
}

public class testClone{
	public static void main(String args[]) {
		Employee e = new Employee("Mark","Benz");
		Employee e1 = (Employee)e.clone();
		Employee e2 = e;
		System.out.println("e.id:"+e.name+" e.car.name:"+e.car.name);
		System.out.println("e1.id:"+e1.name+" e1.car.name:"+e1.car.name);
		System.out.println("e2.id:"+e2.name+" e2.car.name:"+e2.car.name);
		System.out.println("================================");
		e.name = "Jack";
		System.out.println("e.id:"+e.name+" e.car.name:"+e.car.name);
		System.out.println("e1.id:"+e1.name+" e1.car.name:"+e1.car.name);
		System.out.println("e2.id:"+e2.name+" e2.car.name:"+e2.car.name);
		System.out.println("================================");
		e.car.name ="Toyota";
		System.out.println("e.id:"+e.name+" e.car.name:"+e.car.name);
		System.out.println("e1.id:"+e1.name+" e1.car.name:"+e1.car.name);
		System.out.println("e2.id:"+e2.name+" e2.car.name:"+e2.car.name);
	}
}

结果:

e.id:Mark e.car.name:Benz

e1.id:Mark e1.car.name:Benz

e2.id:Mark e2.car.name:Benz

================================

e.id:Jack e.car.name:Benz

e1.id:Mark e1.car.name:Benz

e2.id:Jack e2.car.name:Benz

================================

e.id:Jack e.car.name:Toyota

e1.id:Mark e1.car.name:Toyota

e2.id:Jack e2.car.name:Toyota


- 深拷贝

public Object clone(){

try {

//return super.clone();

Employee e = new Employee(namecar.name);

return e;

}

catch(Exception e) {

return null;

}

}


结果:

e.id:Mark e.car.name:Benz

e1.id:Mark e1.car.name:Benz

e2.id:Mark e2.car.name:Benz

================================

e.id:Jack e.car.name:Benz

e1.id:Mark e1.car.name:Benz

e2.id:Jack e2.car.name:Benz

================================

e.id:Jack e.car.name:Toyota

e1.id:Mark e1.car.name:Benz

e2.id:Jack e2.car.name:Toyota

4. 序列化

当我们持久化对象的时候(JVM关闭的时候,仍然存在),序列化可以在保存对象时,将其状态保存为一组字节,在未来可以再将这些字节组装成对象(我们可以利用.class文件和序列化文件还原对象)。对象序列化保存的是对象的状态,也就是成员变量,序列化不会关注类中的静态变量。在JAVA中,只要一个类实现了java.io.Serialization接口,那么他就可以被序列化。JAVA的枚举类型默认基类java.lang.Enum,而该类实现了Serialization或Extenalizable接口,所以枚举类型对象都是默认可以被序列化,因为writeObject定义只能处理String, 数组,枚举和序列对象~当序列化一个对象时,它还会序列化该对象所引用的对象~


当两个进程进行远程通信的时候,互相发送数据,这些数据都以二进制的形式在网络上传送,发送方需要将对象转换为字节序列,才能在网络上传送,对方收到之后恢复数据位JAVA对象。每个Serializable对象会被编码,编码内容包括类名和类签名,对象的字段值和数组值,以及从初始对象中引用的其他多有对象的闭包。我们可以使用序列化永久存储对象到硬盘上或者在网络上传送对象的字节序列。java.io.ObjectOutputStream代表对象输出流,我们可以利用writeObject(obj)对obj进行序列化,然后写到目标输出流中;java.io.ObjectInputStream代表对象输入流,使用readObject()从一个输入流中读取字节序列,转化成对象,并返回。


序列化:把JAVA对象转换成字节序列的过程

反序列化:把字节序恢复为JAVA对象


我们可以使用序列化实现深拷贝:

import java.io.*;

class Point1 implements Serializable{
	int x;
	int y;
	Point1(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	public String toString() {
		return "x="+x+", y="+y;
	}
}

public class testCopy1 {
	public static void main(String args[]) throws IOException, ClassNotFoundException{
		ObjectOutputStream oos = null;
		//ObjectOutputStream oos1 = null;
		ObjectInputStream ois = null;
		Point1 p1 = new Point1(100,50);
		System.out.println("Original: "+p1);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		//File f1 = new File("a.out"); 存放字节序列文件
		//FileOutputStream fos = new FileOutputStream(f1);
		oos = new ObjectOutputStream(bos);
		oos.writeObject(p1);
		oos.close();
		//oos1 = new ObjectOutputStream(fos);
		//oos1.writeObject(p1);
		//oos1.close(); 如果之后采用反序列化查看内容,会发现结果是x=100, y=50
		Point1 p2 = null;
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		ois = new ObjectInputStream(bis);
		p2 = (Point1) ois.readObject();
		ois.close();
		System.out.println("Original: "+p2);
		//FileInputStream fis = new FileInputStream("a.out");
		p2.x = 150;
		System.out.println("Original: "+p1);
		System.out.println("Original: "+p2);
	}
}
结果:

Original: x=100, y=50

Original: x=100, y=50

Original: x=100, y=50

Original: x=150, y=50


reference:

1. J2SE 8 API

2. http://www.jb51.net/article/48201.htm

3. http://developer.51cto.com/art/201202/317181.htm(后面再来看一下,先MARK)

4. http://www.cnblogs.com/yxnchinahlj/archive/2010/09/20/1831615.html

5. http://www.cnblogs.com/xudong-bupt/archive/2013/05/19/3086493.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值