本篇博客内容:
ObjectOutputStream + 内存流ByteArrayOutputStream
ObjectOutputStream + FileOutputStream
一、浅克隆(ShallowClone)和深克隆(DeepClone) <=返回目录
1.1、浅克隆和深克隆区别
packagecom.oy.shallowclone;/*浅克隆(ShallowClone)和深克隆(DeepClone)。
在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,
值类型包括int、double、byte、boolean、char等简单数据类型,
引用类型包括类、接口、数组等复杂类型。
浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制。
实现clone方法的步骤
(1)实现Cloneable接口
(2)重写Object类中的clone()方法,重写时需定义为public
(3)在重写方法中,调用super.clone()*/
public class Student implementsCloneable {private intnumber;public intgetNumber() {returnnumber;
}public void setNumber(intnumber) {this.number =number;
}
@Overridepublic Object clone() throwsCloneNotSupportedException {return super.clone();
}/*@Override
public Object clone() {
Student stu = null;
try {
stu = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}*/}
测试
packagecom.oy.shallowclone;public classStudentTest {public static void main(String args[]) throwsCloneNotSupportedException {
Student stu1= newStudent();
stu1.setNumber(12345);//stu1克隆出stu2
Student stu2 =(Student) stu1.clone();
System.out.println("学生1:" + stu1.getNumber()); //12345
System.out.println("学生2:" + stu2.getNumber()); //12345
stu2.setNumber(54321); //修改stu2
System.out.println("学生1:" + stu1.getNumber()); //12345
System.out.println("学生2:" + stu2.getNumber()); //54321
}
}
1.2、浅克隆
Cat类
packagecom.oy.shallowclone;public class Cat implementsCloneable {privateString name;
//getter和setter省略@Overridepublic Object clone() throwsCloneNotSupportedException {return super.clone();
}
}
Person类
packagecom.oy.shallowclone;public class Person implementsCloneable {privateString name;privateInteger age;privateCat cat;//getter和setter省略
@Overridepublic Object clone() throwsCloneNotSupportedException {return super.clone();
}
}
测试类
packagecom.oy.shallowclone;public classPersonTest {public static void main(String[] args) throwsCloneNotSupportedException {
Cat cat= newCat();
cat.setName("狸花");
Person per1= newPerson();
per1.setName("张三");
per1.setAge(10);
per1.setCat(cat);//per1克隆出per2
Person per2 =(Person) per1.clone();
System.out.println(per1.getName()+ "-" + per1.getAge() + "-" + per1.getCat().getName()); //张三-10-狸花
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); //张三-10-狸花
System.out.println(per1.getName() == per2.getName()); //true
System.out.println(per1.getAge() == per2.getAge()); //true
System.out.println(per1.getCat() == per1.getCat()); //true//修改per1
per1.setName("李四"); //per1的name属性保存另一个"字符串"的地址
per1.setAge(20);
cat.setName("小橘");
System.out.println(per1.getName()+ "-" + per1.getAge() + "-" + per1.getCat().getName()); //李四-20-小橘
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); //张三-10-小橘
System.out.println(per1.getName() == per2.getName()); //false
System.out.println(per1.getAge() == per2.getAge()); //false
System.out.println(per1.getCat() == per1.getCat()); //true
}
}
理论上String和Integer类型的属性的克隆也是浅克隆。但是,String和Integer是不可变的。所以,实际上当String和Integer类型的属性改变时,克隆对象不会跟着改变。
packagecom.oy.shallowclone;/*** 理论上String和Integer类型的属性的克隆也是浅克隆。
* 但是,String和Integer是不可变的。所以,实际上当String和Integer类型的属性改变时,克隆对象不会跟着改变。
*
*@authoroy*/
public classPersonTest2 {public static void main(String[] args) throwsCloneNotSupportedException {
Cat cat= newCat();
cat.setName("狸花");
Person per1= newPerson();
String name= new String("张三");
per1.setName(name);
Integer age= new Integer("10");
per1.setAge(age);
per1.setCat(cat);//per1克隆出per2
Person per2 =(Person) per1.clone();
System.out.println(per1.getName()+ "-" + per1.getAge() + "-" + per1.getCat().getName()); //张三-10-狸花
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); //张三-10-狸花
System.out.println(per1.getName() == per2.getName()); //true 说明是浅克隆
System.out.println(per1.getAge() == per2.getAge()); //true 说明是浅克隆
System.out.println(per1.getCat() == per1.getCat()); //true 说明是浅克隆//修改per1
name = new String("李四"); //只是修改了name变量里面保存的地址值
age = new Integer("20"); //只是修改了age变量里面保存的地址值
cat.setName("小橘");
System.out.println(per1.getName()+ "-" + per1.getAge() + "-" + per1.getCat().getName()); //张三-10-小橘
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); //张三-10-小橘
System.out.println(per1.getName() == per2.getName()); //true
System.out.println(per1.getAge() == per2.getAge()); //true
System.out.println(per1.getCat() == per1.getCat()); //true
}
}
1.3、深克隆
Teacher类
packagecom.oy.deepclone;class Teacher implementsCloneable {private intage;privateString name;//getter和setter省略
@Overridepublic Object clone() throwsCloneNotSupportedException {return super.clone();
}
}
Student类
packagecom.oy.deepclone;public class Student implementsCloneable {private intage;privateString name;privateTeacher teacher;//getter和setter省略
@Overridepublic Object clone() throwsCloneNotSupportedException {//这一步返回的这个student还只是一个浅克隆,
Student student = (Student) super.clone();//然后克隆的过程中获得这个克隆的student,然后调用这个getTeacher这个方方法得到这个Teacher对象。//然后实现克隆。在设置到这个student中的Teacher。//这样实现了双层克隆使得那个teacher对象也得到了复制。
student.setTeacher((Teacher) student.getTeacher().clone());//双层克隆使得那个teacher对象也得到了复制
returnstudent;
}
}
测试类
packagecom.oy.deepclone;public classTest {public static void main(String[] args) throwsCloneNotSupportedException {
Teacher teacher= newTeacher();
teacher.setAge(40);
teacher.setName("teacher zhang");
Student stu1= newStudent();
stu1.setAge(10);
stu1.setName("张三");
stu1.setTeacher(teacher);//stu1深克隆出stu2
Student stu2 =(Student) stu1.clone();//这里是深复制,所以这时候Student中的teacher就是teacher这个对象的一个复制,就和student2是Student的一个复制//所以下面teacher.setName只是对他原来的这个对象更改,但是复制的那个并没有更改
System.out.println(stu1.getName() + "-" + stu1.getAge() + "-" + stu1.getTeacher().getName());//张三-10-teacher zhang
System.out.println(stu2.getName() + "-" + stu2.getAge() + "-" + stu2.getTeacher().getName());//张三-10-teacher zhang//修改stu1
stu1.setName("李四");
stu1.setAge(20);
teacher.setName("teacher wang");
System.out.println(stu1.getName()+ "-" + stu1.getAge() + "-" + stu1.getTeacher().getName());//李四-20-teacher wang
System.out.println(stu2.getName() + "-" + stu2.getAge() + "-" + stu2.getTeacher().getName());//张三-10-teacher zhang
}
}
二、序列化和反序列化实现深克隆 <=返回目录
Car类
public class Car implementsSerializable {private static final long serialVersionUID = -7633040136520448512L;privateString name;privateString color;publicCar() {}publicCar(String name, String color) {this.name =name;this.color =color;
}//getter和setter方法省略
@OverridepublicString toString() {return "Car [name=" + name + ", color=" + color + "]";
}
}
Person类
public class Person implementsSerializable {private static final long serialVersionUID = 4792126594710124401L;privateString name;private intage;privateCar car;publicPerson() {}public Person(String name, intage) {this.name =name;this.age =age;
}public Person(String name, intage, Car car) {this.name =name;this.age =age;this.car =car;
}//getter和setter方法省略
@OverridepublicString toString() {return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
工具类:使用序列化和反序列化实现对象的克隆
packagecom.oy;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.Closeable;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;/*** 工具类:使用序列化和反序列化实现对象的克隆
*
*@authoroy
*@version1.0
* @date 2018年8月9日
* @time 下午8:59:23*/
public classcloneUtil {privatecloneUtil() {
}
@SuppressWarnings("unchecked")public static T cloneObject(T obj) {
T cloneObj= null;//序列化
ByteArrayOutputStream bout = null;
ObjectOutputStream oos= null;try{
bout= newByteArrayOutputStream();
oos= newObjectOutputStream(bout);
oos.writeObject(obj);
}catch(IOException e) {
e.printStackTrace();
}finally{
close(oos);
close(bout);
}//反序列化
ByteArrayInputStream bin = null;
ObjectInputStream ois= null;try{
bin= newByteArrayInputStream(bout.toByteArray());
ois= newObjectInputStream(bin);
cloneObj=(T) ois.readObject();
}catch (IOException |ClassNotFoundException e) {
e.printStackTrace();
}finally{
close(ois);
close(bin);
}returncloneObj;
}private static voidclose(Closeable closeable) {if (closeable != null) {try{
closeable.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
测试
/*** 序列化和反序列化实现深克隆
*
*@authoroy
*@version1.0
* @date 2018年8月9日
* @time 下午8:58:53*/
public classTest {public static voidmain(String[] args) {
Car car= new Car("BYD", "black");
Person p1= new Person("张三", 20, car);
Person p2=cloneUtil.cloneObject(p1);
System.out.println("P1:" + p1);//P1:Person [name=张三, age=20, car=Car [name=BYD, color=black]]
System.out.println("p2:" + p2);//p2:Person [name=张三, age=20, car=Car [name=BYD, color=black]]
if (p2 != null) {
car.setName("宝马");
car.setColor("red");
}
System.out.println("P1:" + p1);//P1:Person [name=张三, age=20, car=Car [name=宝马, color=red]]
System.out.println("p2:" + p2);//p2:Person [name=张三, age=20, car=Car [name=BYD, color=black]]
}
}
三、封装序列化和反序列化操作 <=返回目录
3.1、封装序列化和反序列化操作
packagecom.oy;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.Closeable;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.util.ArrayList;importjava.util.List;/*** 序列化,反序列化工具类。用于转换byte[]和对象
*
*@authoroy
* @date 2019年6月3日 下午11:46:53
*@version1.0.0*/
public classSerializeUtil {public static byte[] serialize(Object object) {
ObjectOutputStream oos= null;
ByteArrayOutputStream baos= null;try{//序列化
baos = newByteArrayOutputStream();
oos= newObjectOutputStream(baos);
oos.writeObject(object);byte[] bytes =baos.toByteArray();returnbytes;
}catch(Exception e) {
e.printStackTrace();
}finally{
close(oos);
close(baos);
}return null;
}public static Object unserialize(byte[] bytes) {
ByteArrayInputStream bais= null;
ObjectInputStream ois= null;try{//反序列化
bais = newByteArrayInputStream(bytes);
ois= newObjectInputStream(bais);returnois.readObject();
}catch(Exception e) {
e.printStackTrace();
}finally{
close(bais);
close(ois);
}return null;
}/*** 序列化 list 集合
*
*@paramlist
*@return
*/
public static byte[] serializeList(List>list) {if (list == null || list.size() <= 0) {return null;
}
ObjectOutputStream oos= null;
ByteArrayOutputStream baos= null;byte[] bytes = null;try{
baos= newByteArrayOutputStream();
oos= newObjectOutputStream(baos);for(Object obj : list) {
oos.writeObject(obj);
}
bytes=baos.toByteArray();
}catch(Exception e) {
e.printStackTrace();
}finally{
close(oos);
close(baos);
}returnbytes;
}/*** 反序列化 list 集合
*
*@paramlb
*@return
*/
public static List> unserializeList(byte[] bytes) {if (bytes == null) {return null;
}
List list = new ArrayList();
ByteArrayInputStream bais= null;
ObjectInputStream ois= null;try{//反序列化
bais = newByteArrayInputStream(bytes);
ois= newObjectInputStream(bais);while (bais.available() > 0) {
Object obj=(Object) ois.readObject();if (obj == null) {break;
}
list.add(obj);
}
}catch(Exception e) {
e.printStackTrace();
}finally{
close(bais);
close(ois);
}returnlist;
}/*** 关闭io流对象
*
*@paramcloseable*/
public static voidclose(Closeable closeable) {if (closeable != null) {try{
closeable.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
3.2、cloneUtil类改为:
public classcloneUtil {privatecloneUtil() {}
@SuppressWarnings("unchecked")public static T cloneObject(T obj) {//序列化
byte[] bs =SerializeUtil.serialize(obj);//反序列化
return(T) SerializeUtil.unserialize(bs);
}
}
四、对象持久化到文件或从文件中读取对象 <=返回目录
packagecom.oy;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;/*** 序列化和反序列化
*
*@authoroy
*@version1.0
* @date 2018年8月9日
* @time 下午8:58:32*/
public classserialDemo {public static void main(String[] args) throwsIOException, ClassNotFoundException {//创建Person对象
Car car = new Car("BMW", "black");
Person p= new Person("张三abc", 20, car);
write(p);
Object obj=read();//Person [name=张三abc, age=20, car=Car [name=BMW, color=black]]
System.out.println(obj);
}private static Object read() throwsFileNotFoundException, IOException, ClassNotFoundException {//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\object.txt"));//反序列化
Object obj =ois.readObject();//释放资源
ois.close();returnobj;
}private static void write(Object obj) throwsFileNotFoundException, IOException {//创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\object.txt"));//序列化
oos.writeObject(obj);//释放资源
oos.close();
}
}
参考: