// 只能对实现了Serializable接口的类的对象进行序列化 // java.io.NotSerializableException: java.lang.Object ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(new Object()); oos.close();
@Getter public class A implements Serializable { private transient int f1 = 1; private int f2 = 2; @Getter private static final int f3 = 3; } // 序列化 // 仅对对象的非transient的实例变量进行序列化 A a1 = new A(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(a1); oos.close(); // 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); A a2 = (A) ois.readObject(); log.info("f1={}, f2={}, f3={}", a2.getF1(), a2.getF2(), a2.getF3()); // f1=0, f2=2, f3=3 ois.close();
@Data @AllArgsConstructor public class B implements Serializable { private static final long serialVersionUID = 1L; private int id; } @Test public void test3() throws Exception { // 序列化 B b1 = new B(1); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(b1); oos.close(); } @Test public void test4() throws Exception { // 如果先将B的serialVersionUID修改为1,直接反序列化磁盘上的文件,会报异常 // java.io.InvalidClassException: xxx.B; local class incompatible: stream classdesc serialVersionUID = 0, local class serialVersionUID = 1 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); B b2 = (B) ois.readObject(); ois.close(); }
具体实现序列化和反序列化的是 writeObject 和 readObject
@Data @AllArgsConstructor public class Student implements Serializable { private long id; private int age; private String name; // 只序列化部分字段 private void writeObject(ObjectOutputStream outputStream) throws IOException { outputStream.writeLong(id); outputStream.writeObject(name); } // 按序列化的顺序进行反序列化 private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { id = inputStream.readLong(); name = (String) inputStream.readObject(); } } Student s1 = new Student(1, 12, "Bob"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(s1); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); Student s2 = (Student) ois.readObject(); log.info("s2={}", s2); // s2=Student(id=1, age=0, name=Bob) ois.close();
// 反序列化会通过反射调用无参构造器返回一个新对象,破坏单例模式 // 可以通过readResolve()来解决 public class Singleton1 implements Serializable { private static final Singleton1 SINGLETON_1 = new Singleton1(); private Singleton1() { } public static Singleton1 getInstance() { return SINGLETON_1; } } Singleton1 s1 = Singleton1.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(s1); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); Singleton1 s2 = (Singleton1) ois.readObject(); log.info("{}", s1 == s2); // false ois.close();
public class Singleton2 implements Serializable { private static final Singleton2 SINGLETON_2 = new Singleton2(); private Singleton2() { } public static Singleton2 getInstance() { return SINGLETON_2; } public Object writeRepalce() { // 序列化之前,无需替换 return this; } private Object readResolve() { // 反序列化之后,直接返回单例 return getInstance(); } } Singleton2 s1 = Singleton2.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(s1); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); Singleton2 s2 = (Singleton2) ois.readObject(); log.info("{}", s1 == s2); // true ois.close();
Java序列化 只适用 于基于Java语言实现的框架
int itCount = 27; Set root = new HashSet(); Set s1 = root; Set s2 = new HashSet(); for (int i = 0; i < itCount; i++) { Set t1 = new HashSet(); Set t2 = new HashSet(); t1.add("foo"); // 使t2不等于t1 s1.add(t1); s1.add(t2); s2.add(t1); s2.add(t2); s1 = t1; s2 = t2; } ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH)); oos.writeObject(root); oos.close(); long start = System.currentTimeMillis(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); ois.readObject(); log.info("take : {}", System.currentTimeMillis() - start); ois.close(); // itCount - take // 25 - 3460 // 26 - 7346 // 27 - 11161
@Data class User implements Serializable { private String userName; private String password; } User user = new User(); user.setUserName("test"); user.setPassword("test"); // ObjectOutputStream ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(user); log.info("{}", os.toByteArray().length); // 107 // NIO ByteBuffer ByteBuffer byteBuffer = ByteBuffer.allocate(2048); byte[] userName = user.getUserName().getBytes(); byte[] password = user.getPassword().getBytes(); byteBuffer.putInt(userName.length); byteBuffer.put(userName); byteBuffer.putInt(password.length); byteBuffer.put(password); byteBuffer.flip(); log.info("{}", byteBuffer.remaining()); // 16
int count = 10_0000; User user = new User(); user.setUserName("test"); user.setPassword("test"); // ObjectOutputStream long t1 = System.currentTimeMillis(); for (int i = 0; i < count; i++) { ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(user); oos.flush(); oos.close(); byte[] bytes = os.toByteArray(); os.close(); } long t2 = System.currentTimeMillis(); log.info("{}", t2 - t1); // 731 // NIO ByteBuffer long t3 = System.currentTimeMillis(); for (int i = 0; i < count; i++) { ByteBuffer byteBuffer = ByteBuffer.allocate(2048); byte[] userName = user.getUserName().getBytes(); byte[] password = user.getPassword().getBytes(); byteBuffer.putInt(userName.length); byteBuffer.put(userName); byteBuffer.putInt(password.length); byteBuffer.put(password); byteBuffer.flip(); byte[] bytes = new byte[byteBuffer.remaining()]; } long t4 = System.currentTimeMillis(); log.info("{}", t4 - t3); // 182