// 只能对实现了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