java序列化

1.序列化的类要继承Serializable接口。其父类也需要实现这个接口。否则反序列化抛异常。

2.序列化类A,引用了另外一个类B的实例,那么类B也需要实现接口。如果两个A的实例,引用了同一个B实例,那么B只序列化一次。

3.A实例序列化后,反序列化的A的实例,与原实例是两个对象。这点要注意,反序列化过程不调用构造函数,因此单例模式时,会出问题。这时需要重写readResolve方法。一般此方法为private方法,因为如果父类有此方法,子类没有重写,那么子类反序列化将得到父类对象实例。

4.可以设置序列化的过滤器。反序列化时,会自动调用过滤器的inputcheck方法。

5.可以自定义序列化。有两种方法

一种是在序列化类中写writeObject和readObject方法。这种方法,反序列化时不会调用构造函数。前者控制序列化时的操作,后者是前者的反操作。也可以写writeReplace方法。这个方法可以将对象转换成其他对象。反序列化时会先调用writeObject,如果该方法返回的另外一个对象也有这个方法则继续调用,直到没有,然后再调用readObject方法。

另一种方法,实现Externailzable接口。这个接口强制实现自定义序列化。性能较第一种略好。这个接口有两个方法

void readExternal,和writeExternal方法。除了函数签名与第一种不一样,其他用法一样。这个方法的反序列化会调用无参构造函数。因此一定要有无参的构造函数。

第二种方法因为强制实现自定义序列,编程略麻烦,因此一般使用第一种方法序列化。

6.对象的类名,实例变量,都会被序列化,方法,类变量,transient实例变量(瞬态变量)都不会被实例化。如果想让某个实例变量不要序列化,应该加上transient修饰符。不应该加staic。

7.序列化还有一个serialVersionUID指定class文件的版本号。如果版本号没变,但是class变量变了。仍然可以反序列化。(如果修改了实例变量,那么则应该修改这个版本号)

package objStream;

import java.io.FileInputStream;
import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;

public class FilterTest {
    public static void main(String[] args) {
        try(
                var oid=new ObjectInputStream(new FileInputStream("out1.txt"));
                ){
            //为序列化设置过滤器。当反序列化时,过滤器的checkInput方法会被自动激发。
            //1、用lambda表达式,因为ObjectInputFilter是一个函数式接口。需要实现checkInput方法。这个方法有一个info参数。所以info->{}。
            oid.setObjectInputFilter(filterInfo -> {
                //2、重写checkinput方法,首先要遵循他默认的checkinput结果。因此要先得到一个ObjectInputFilter对象。
                var serialFilter=ObjectInputFilter.Config.getSerialFilter();
                if(serialFilter!=null) {
                    //3、利用已有的过滤器,得到默认的status结果。如果结果不是undecide,就返回结果。
                    var status = serialFilter.checkInput(filterInfo);
                    if (status != ObjectInputFilter.Status.UNDECIDED) {
                        return status;
                    }
                }
                //4、如果是undecided,继续判断。此处为拓展原来的。
                if(filterInfo.references()!=1) {
                    return ObjectInputFilter.Status.REJECTED;
                }
                if(filterInfo.serialClass()!=null&&filterInfo.serialClass()!=Person.class){
                    return ObjectInputFilter.Status.REJECTED;
                }
                //5、如果都不是以上情况,继续返回不确定。

                return ObjectInputFilter.Status.UNDECIDED;
            });

        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

  上面代码时设置序列化过滤器。

package objStream;

import java.io.*;

public class sameTest {
    public static void main(String[] args) {
        Teacher teacher=new Teacher("张三");
        var stu1=new Student("李四",teacher);
        var stu2=new Student("王五",teacher);
        try {
            var oos=new ObjectOutputStream(new FileOutputStream("same.txt"));
            var ois=new ObjectInputStream(new FileInputStream("same.txt"));

            oos.writeObject(teacher);
            oos.writeObject(stu1);
            oos.writeObject(stu2);
          var teacher1=(Teacher) ois.readObject();
          var stu11=(Student)ois.readObject();
          var stu22=(Student)ois.readObject();
            System.out.println(teacher1);
            System.out.println(teacher);
            System.out.println(stu1);
            System.out.println(stu2);
            System.out.println(stu11);
            System.out.println(stu22);
            System.out.println("stu1,stu11----"+ stu1.equals(stu11));
            System.out.println("stu2,stu22----"+ stu2.equals(stu22));
            System.out.println("stu1.teac,teac----"+ stu1.getTeacher().equals(teacher));//true
            System.out.println("stu1.teac,stu11.teac----"+ stu1.getTeacher().equals(stu11.getTeacher()));//false
            System.out.println("stu1.teac,stu2.teac----"+ stu1.getTeacher().equals(stu2.getTeacher()));//true
            System.out.println("stu11.teac,stu22.teac----" +stu11.getTeacher().equals(stu22.getTeacher()));//true
            System.out.println("teac,teac1----" +teacher.equals(teacher1));
            //得出结论,反序列化后的对象和原对象不是一个对象。
            //对于引用同一个对象的实例的两个不同对象,引用的同一个实例只序列化一次,所以这个实例是同一个。
            //反序列化时,不经过构造器,因此如果是单例或者是枚举类,则需要重写readResolve方法,以保证反序列化以后,还是原来的实例。否则将会生成新的实例
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Teacher implements Serializable{
    public Teacher(String name){
        this.name=name;
    }
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student implements Serializable{
    public Student(String name,Teacher teacher){
        this.name=name;
        this.teacher=teacher;
    }
    private String name;
    private Teacher teacher;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }
}

  上面代码运行结果是

 

posted @ 2020-04-04 18:45  小甲点点  阅读(230)  评论(0编辑  收藏  举报