• J2SE 8的输入输出--序列化


    1. 普通序列化 implements Serializable

    继承Serializable接口

    class Employee implements Serializable {
    	private String name;
    	private double salary;
    	private LocalDate hireDay;
    
    	public Employee() {
    	}
    
    	public Employee(String n, double s, int year, int month, int day) {
    		name = n;
    		salary = s;
    		hireDay = LocalDate.of(year, month, day);
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public double getSalary() {
    		return salary;
    	}
    
    	public void setSalary(double salary) {
    		this.salary = salary;
    	}
    
    	public LocalDate getHireDay() {
    		return hireDay;
    	}
    
    	public void setHireDay(LocalDate hireDay) {
    		this.hireDay = hireDay;
    	}
    
    	public void raiseSalary(double byPercent) {
    		double raise = salary * byPercent / 100;
    		salary += raise;
    	}
    
    	public String toString() {
    		return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
    	}
    }

    // 1. 普通序列化
    Employee employee = new Employee("Harry Hacker", 50000, 1989, 10, 1);
    
    try (FileOutputStream personOutputStream = new FileOutputStream("E:\employee.dat");
    		ObjectOutputStream objectOutputStream = new ObjectOutputStream(personOutputStream);) {
    	objectOutputStream.writeObject(employee);
    }
    
    try (FileInputStream personInputStream = new FileInputStream("E:\employee.dat");
    		ObjectInputStream objectInputStream = new ObjectInputStream(personInputStream);) {
    	Object readObject = objectInputStream.readObject();
    
    	if (readObject instanceof Employee) {
    		Employee tempEmployee = (Employee) readObject;
    		System.out.println(tempEmployee.toString());
    	}
    }
    System.out.println();
    执行结果

    io.Employee[name=Harry Hacker,salary=50000.0,hireDay=1989-10-01]


    2. 关联对象

    一个employee被多个Manager关联, 反序列后还是同一个。

    // 2. 关联对象	一个employee被多个Manager关联, 反序列后还是同一个
    Manager manager1 = new Manager("Carl Cracker", 80000, 1987, 12, 15);
    manager1.setSecretary(employee);
    
    Manager manager2 = new Manager("Tony Tester", 40000, 1990, 3, 15);
    manager2.setSecretary(employee);
    
    try (FileOutputStream managerOutputStream = new FileOutputStream("E:\manager.dat");
    		ObjectOutputStream objectOutputStream = new ObjectOutputStream(managerOutputStream);) {
    	objectOutputStream.writeObject(manager1);
    	objectOutputStream.writeObject(manager2);
    }
    
    try (FileInputStream managerInputStream = new FileInputStream("E:\manager.dat");
    		ObjectInputStream objectInputStream = new ObjectInputStream(managerInputStream);) {
    	Object readObject1 = objectInputStream.readObject();
    	Object readObject2 = objectInputStream.readObject();
    
    	if (readObject1 instanceof Manager) {
    		Manager tempManager = (Manager) readObject1;
    		System.out.println(tempManager.toString());
    		System.out.println(tempManager.getSecretary().hashCode());
    	}
    
    	if (readObject2 instanceof Manager) {
    		Manager tempManager = (Manager) readObject2;
    		System.out.println(tempManager.toString());
    		System.out.println(tempManager.getSecretary().hashCode());
    	}
    }
    System.out.println();

    执行结果

    io.Manager[name=Carl Cracker,salary=80000.0,hireDay=1987-12-15][secretary=io.Employee[name=Harry Hacker,salary=50000.0,hireDay=1989-10-01]]
    381259350
    io.Manager[name=Tony Tester,salary=40000.0,hireDay=1990-03-15][secretary=io.Employee[name=Harry Hacker,salary=50000.0,hireDay=1989-10-01]]
    381259350

    3. 忽略冗余字段 transient

    不能使用javax.persistence.Trasient,使用关键字 transient

    class Employee implements Serializable {
    	private String name;
    	private transient double salary;
    	private LocalDate hireDay;
    	...
    }
    执行1的结果

    io.Employee[name=Harry Hacker,salary=0.0,hireDay=1989-10-01]


    4. 保护性恢复  readResolve()&writeReplace()

    writeReplace()    在序列化时会先调用writeReplace方法将当前对象替换成另一个对象(该方法会返回替换后的对象)并将其写入流中;

    readResolve()    在readObject调用之后自动调用,它最主要的目的就是让恢复的对象变个样.


    对于单例对象, 序列化后取得的对象要与序列化之前的对象一致才行; 可以使用readResolve()在read时做一些处理.

    class MySingleton implements Serializable {
    	private MySingleton() {
    	}
    
    	private static final MySingleton INSTANCE = new MySingleton();
    
    	public static MySingleton getInstance() {
    		return INSTANCE;
    	}
    	
    	private Object writeReplace() throws ObjectStreamException{
    		return INSTANCE;
    	}
    	
    	private Object readResolve() throws ObjectStreamException {
    		return INSTANCE;
    	}
    }
    下面代码返回true

    MySingleton mySingleton = MySingleton.getInstance();
    
    try (FileOutputStream mySingletonOutputStream = new FileOutputStream("E:\mySingleton.dat");
    		ObjectOutputStream objectOutputStream = new ObjectOutputStream(mySingletonOutputStream);) {
    	objectOutputStream.writeObject(mySingleton);
    }
    
    try (FileInputStream mySingletonInputStream = new FileInputStream("E:\mySingleton.dat");
    		ObjectInputStream objectInputStream = new ObjectInputStream(mySingletonInputStream);) {
    	Object readObject = objectInputStream.readObject();
    
    	if (readObject instanceof MySingleton) {
    		MySingleton orientation = (MySingleton) readObject;
    
    		// (1) 没有readResolve()方法时; 序列化new出的是新对象,和原先对象不相等
    		// (2) 添加readResolve()方法后, 序列化之后调用readObject()时会调用readResolve()方法
    		System.out.println(mySingleton == orientation);
    	}
    }
    System.out.println();

    5. readObjectNoData()

    数据结构改变后, 调用readObjectNoData()方法.

    初始化Person, 指定掌纹

    class Person implements Serializable {               
        private static final long serialVersionUID = 8427041451926540477L;
    
        public Person() {  }
        
        private int age;
        
        public int getAge() {
            return age;
        }
        
        public void setAge(int age) {
            this.age = age;
        }              
    }
    将其序列化

    Person p = new Person();             
    p.setAge(10);
    
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/person.dat"));             
    oos.writeObject(p);            
    oos.flush();             
    oos.close();
    类结构变化后

    class Animal implements Serializable {                  
        private String name;                 
        public Animal() {  }                 
                        
        private void readObjectNoData() {                       
            this.name = "zhangsan";                 
        }
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}          
    }
    
    class Person extends Animal {               
    	private static final long serialVersionUID = 8427041451926540477L;
    
    	public Person() {  }
        
    	private int age;
    	
    	public int getAge() {
    		return age;
    	}
    	
    	public void setAge(int age) {
    		this.age = age;
    	}              
    }
    执行

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/person.dat"));       
    Person sp = (Person) ois.readObject();       
    System.out.println(sp.getName());
    ois.close();
    得到 zhangsan


    6.  Externalizable接口

    由开发者完全决定如何序列化和反序列化目标对象

    注意: 必须提供一个无参构造器,访问权限为public; 否则会抛出java.io.InvalidClassException 异常

    class Student implements Externalizable {
    	private String name;
    	private int age;
    
    	@Override
    	public void writeExternal(ObjectOutput out) throws IOException {
    		out.writeObject(name);
    		out.writeInt(age);
    	}
    
    	@Override
    	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    		name = (String)in.readObject();
    		age = in.readInt();
    	}
    	
    	//no valid constructor
    	//必须提供一个无参构造器,访问权限为public;否则会抛出java.io.InvalidClassException 异常
    	public Student() {
    		// TODO Auto-generated constructor stub
    	}
    	
    	public Student(String name, int age) {
    		this.name= name;
    		this.age=age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    	
    	@Override
    	public String toString() {
    		return "name:"+name+", age: "+age;
    	}
    }
    序列化

    Student student = new Student("name", 20);
    
    try (FileOutputStream studentOutputStream = new FileOutputStream("E:\student.dat");
    		ObjectOutputStream objectOutputStream = new ObjectOutputStream(studentOutputStream);) {
    	objectOutputStream.writeObject(student);
    }
    
    try (FileInputStream studentInputStream = new FileInputStream("E:\student.dat");
    		ObjectInputStream objectInputStream = new ObjectInputStream(studentInputStream);) {
    	Object readObject = objectInputStream.readObject();
    
    	if (readObject instanceof Student) {
    		System.out.println(((Student) readObject).toString());
    	}
    }
    System.out.println();
    结果: name:name, age: 20

    7.  为克隆使用序列化

    实现深拷贝

    class SerialCloneable implements Cloneable, Serializable {
    	public Object clone() throws CloneNotSupportedException {
    		try {
    			// save the object to a byte array
    			ByteArrayOutputStream bout = new ByteArrayOutputStream();
    			try (ObjectOutputStream out = new ObjectOutputStream(bout)) {
    				out.writeObject(this);
    			}
    
    			// read a clone of the object from the byte array
    			try (InputStream bin = new ByteArrayInputStream(bout.toByteArray())) {
    				ObjectInputStream in = new ObjectInputStream(bin);
    				return in.readObject();
    			}
    		} catch (IOException | ClassNotFoundException e) {
    			CloneNotSupportedException e2 = new CloneNotSupportedException();
    			e2.initCause(e);
    			throw e2;
    		}
    	}
    }
    class Employee extends SerialCloneable {
    	private String name;
    	private double salary;
    	private LocalDate hireDay;
    
    	...
    }
    执行

    //7. 深拷贝
    Employee harry = new Employee("Harry Hacker", 35000, 1989, 10, 1);
    // clone harry
    Employee harry2 = (Employee) harry.clone();
    
    // mutate harry
    harry.raiseSalary(10);
    
    // now harry and the clone are different
    System.out.println(harry);
    System.out.println(harry2);

    结果

    io.Employee[name=Harry Hacker,salary=38500.0,hireDay=1989-10-01]
    io.Employee[name=Harry Hacker,salary=35000.0,hireDay=1989-10-01]

  • 相关阅读:
    【二十五】cookie与session学习总结
    【二十四】使用mysqli扩展类批量执行多条sql语句
    【二十三】php之预定义超全局变量
    【二十二】mysqli事务处理与预处理总结
    【二十一】基于mysqli的表格数据练习
    【二十】mysqli基于面向过程与面向对象的编程
    为什么所有浏览器的userAgent都带Mozilla
    如何快速的搜索自己想要的资料
    从汇编看c++成员函数指针(三)
    从汇编看c++中指向成员变量的指针(二)
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710384.html
Copyright © 2020-2023  润新知