java序列化,看这篇就够了 (4)

从输出我们看到,使用transient修饰的属性,java序列化时,会忽略掉此字段,所以反序列化出的对象,被transient修饰的属性是默认值。对于引用类型,值是null;基本类型,值是0;boolean类型,值是false。

使用transient虽然简单,但将此属性完全隔离在了序列化之外。java提供了可选的自定义序列化。可以进行控制序列化的方式,或者对序列化数据进行编码加密等。

private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectIutputStream in) throws IOException,ClassNotFoundException
;
private void readObjectNoData() throws ObjectStreamException;

通过重写writeObject与readObject方法,可以自己选择哪些属性需要序列化, 哪些属性不需要。如果writeObject使用某种规则序列化,则相应的readObject需要相反的规则反序列化,以便能正确反序列化出对象。这里展示对名字进行反转加密。

public class Person implements Serializable {
   private String name;
   private int age;
   //省略构造方法,get及set方法

   private void writeObject(ObjectOutputStream out) throws IOException {
       //将名字反转写入二进制流
       out.writeObject(new StringBuffer(this.name).reverse());
       out.writeInt(age);
   }

   private void readObject(ObjectInputStream ins) throws IOException,ClassNotFoundException{
       //将读出的字符串反转恢复回来
       this.name = ((StringBuffer)ins.readObject()).reverse().toString();
       this.age = ins.readInt();
   }
}

当序列化流不完整时,readObjectNoData()方法可以用来正确地初始化反序列化的对象。例如,使用不同类接收反序列化对象,或者序列化流被篡改时,系统都会调用readObjectNoData()方法来初始化反序列化的对象。

更彻底的自定义序列化

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

writeReplace:在序列化时,会先调用此方法,再调用writeObject方法。此方法可将任意对象代替目标序列化对象

public class Person implements Serializable {
  private String name;
  private int age;
  //省略构造方法,get及set方法

  private Object writeReplace() throws ObjectStreamException {
      ArrayList<Object> list = new ArrayList<>(2);
      list.add(this.name);
      list.add(this.age);
      return list;
  }

   public static void main(String[] args) throws Exception {
      try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
           ObjectInputStream ios = new ObjectInputStream(new FileInputStream("person.txt"))) {
          Person person = new Person("9龙"23);
          oos.writeObject(person);
          ArrayList list = (ArrayList)ios.readObject();
          System.out.println(list);
      }
  }
}
//输出结果
//[9龙, 23]

readResolve:反序列化时替换反序列化出的对象,反序列化出来的对象被立即丢弃。此方法在readeObject后调用。

public class Person implements Serializable {
    private String name;
    private int age;
    //省略构造方法,get及set方法
     private Object readResolve() throws ObjectStreamException{
        return new ("brady"23);
    }
    public static void main(String[] args) throws Exception {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
             ObjectInputStream ios = new ObjectInputStream(new FileInputStream("person.txt"))) {
            Person person = new Person("9龙"23);
            oos.writeObject(person);
            HashMap map = (HashMap)ios.readObject();
            System.out.println(map);
        }
    }
}
//输出结果
//{brady=23}

readResolve常用来反序列单例类,保证单例类的唯一性。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfydj.html