Serialization/deserialization 与 GZIP 流不一致
Serialization/deserialization with GZIP Sterams isn't consitent
我有以下和平代码试图 serialize/deserialize a Throwable
public void test() throws IOException, ClassNotFoundException {
IllegalStateException exception = new IllegalStateException("Oooops!");
ByteBuffer seralized = serialize(exception);
String asString = new String(seralized.array(), Charset.forName("UTF-8"));
Throwable deserialized = deserialize(seralized);
// false
System.out.println(exception.equals(deserialized));
// true
System.out.println(exception.toString().equals(deserialized.toString()));
seralized = serialize(deserialized);
String toCompare = new String(seralized.array(), Charset.forName("UTF-8"));
// true
System.out.println(asString.equals(toCompare));
}
private Throwable deserialize(ByteBuffer seralized) throws IOException, ClassNotFoundException {
return (Throwable) new ObjectInputStream(new GZIPInputStream(
new ByteArrayInputStream(seralized.array()))).readObject();
}
private ByteBuffer serialize(Throwable exception) throws IOException {
ByteArrayOutputStream causeBytesOut = new ByteArrayOutputStream();
ObjectOutputStream causeOut = new ObjectOutputStream(
new GZIPOutputStream(causeBytesOut));
causeOut.writeObject(exception);
causeOut.close();
return ByteBuffer.wrap(causeBytesOut.toByteArray());
}
解释代码:我正在测试我的 serialization/deserialization 是否兼容。
第一个打印输出 (false) 告诉我反序列化后得到的结果与序列化后的结果不同。
第二个打印 (true) 表示对象 "somewhat" 相似。
我试图深入每个对象看看有什么区别,所以我再次序列化它并查看字节缓冲区的内容。根据上次打印(正确),这看起来是一样的。
为什么初始对象和经过 serialization/deserialization 的对象不同,尽管看起来是一样的?
请找到以下对您观察到的结果的解释。
对类型 IllegalStateException
的对象调用 toString
将只是 return 完全限定的 class 名称。这是来自 Throwable#toString()
。因此,这对于两个对象都是相同的,equals
的结果将为真
java.lang.IllegalStateException
IllegalStateException
或其父项不会覆盖 equals
方法。因此将只等同于它自己。由于您的反序列化将创建一个新对象,因此您的对象在引用中不相等,因此 equals
将 return false(根据 Object#equals
)。
您正在使用以下表达式以完全相同的方式创建 asString
和 toCompare
,同时由于这两个具有相同内容的不同字符串对象将等同,您的第三个表达式是真的。
new String(seralized.array(), Charset.forName("UTF-8"));
如果您需要在使用原始对象调用 equals()
时让反序列化对象 return 为真,您可以子class IllegalStateException
并覆盖 equals
方法(在这种情况下也是 toString
。)。
IllegalStateException
不会覆盖 Object.equals()
,因此它通过 ==
运算符使用对象标识。因此,对于不同的实例,它总是 return false。
您的测试无效。
我有以下和平代码试图 serialize/deserialize a Throwable
public void test() throws IOException, ClassNotFoundException {
IllegalStateException exception = new IllegalStateException("Oooops!");
ByteBuffer seralized = serialize(exception);
String asString = new String(seralized.array(), Charset.forName("UTF-8"));
Throwable deserialized = deserialize(seralized);
// false
System.out.println(exception.equals(deserialized));
// true
System.out.println(exception.toString().equals(deserialized.toString()));
seralized = serialize(deserialized);
String toCompare = new String(seralized.array(), Charset.forName("UTF-8"));
// true
System.out.println(asString.equals(toCompare));
}
private Throwable deserialize(ByteBuffer seralized) throws IOException, ClassNotFoundException {
return (Throwable) new ObjectInputStream(new GZIPInputStream(
new ByteArrayInputStream(seralized.array()))).readObject();
}
private ByteBuffer serialize(Throwable exception) throws IOException {
ByteArrayOutputStream causeBytesOut = new ByteArrayOutputStream();
ObjectOutputStream causeOut = new ObjectOutputStream(
new GZIPOutputStream(causeBytesOut));
causeOut.writeObject(exception);
causeOut.close();
return ByteBuffer.wrap(causeBytesOut.toByteArray());
}
解释代码:我正在测试我的 serialization/deserialization 是否兼容。
第一个打印输出 (false) 告诉我反序列化后得到的结果与序列化后的结果不同。
第二个打印 (true) 表示对象 "somewhat" 相似。
我试图深入每个对象看看有什么区别,所以我再次序列化它并查看字节缓冲区的内容。根据上次打印(正确),这看起来是一样的。
为什么初始对象和经过 serialization/deserialization 的对象不同,尽管看起来是一样的?
请找到以下对您观察到的结果的解释。
对类型
IllegalStateException
的对象调用toString
将只是 return 完全限定的 class 名称。这是来自Throwable#toString()
。因此,这对于两个对象都是相同的,equals
的结果将为真java.lang.IllegalStateException
IllegalStateException
或其父项不会覆盖equals
方法。因此将只等同于它自己。由于您的反序列化将创建一个新对象,因此您的对象在引用中不相等,因此equals
将 return false(根据Object#equals
)。您正在使用以下表达式以完全相同的方式创建
asString
和toCompare
,同时由于这两个具有相同内容的不同字符串对象将等同,您的第三个表达式是真的。new String(seralized.array(), Charset.forName("UTF-8"));
如果您需要在使用原始对象调用 equals()
时让反序列化对象 return 为真,您可以子class IllegalStateException
并覆盖 equals
方法(在这种情况下也是 toString
。)。
IllegalStateException
不会覆盖 Object.equals()
,因此它通过 ==
运算符使用对象标识。因此,对于不同的实例,它总是 return false。
您的测试无效。