Object
及其克隆(正确完成)字节表示不应相同吗?
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(p);
byte[] byteArr1 = bos.toByteArray();
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(p.clone());
byte[] byteArr2 = bos.toByteArray();
Arrays.equals(byteArr1, byteArr2) == true
?
在比较对象及其克隆时,尝试查看是否有任何替代方法不实现equals方法。是的,这些不是最好的做法,但我只是想了解Serializable Object
的字节流表示。
答案 0 :(得分:0)
是的,他们是平等的。序列化取决于类和对象字段。只要类和字段相同,序列化数据就会相同。
public class Test implements Cloneable, Serializable {
int i = 1;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws Exception {
Test t = new Test();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(t);
byte[] byteArr1 = bos.toByteArray();
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(t.clone());
byte[] byteArr2 = bos.toByteArray();
System.out.println(Arrays.equals(byteArr1, byteArr2));
}
}
打印true
另请查看common-lang EqualsBuilder.reflectionEquals(obj1, obj2)
它可以通过分析字段来测试任何对象是否相等
答案 1 :(得分:0)
不一定:两个不同对象的序列化版本 not 需要为两个对象equals
的字节等于。
Serializable合同中没有任何内容在equals
与writeObject
的结果之间建立任何关系。此外,来自Serialized Form (writeObject) documentation for Hashtable:
.. [和Hashtable序列化]由Hashtable表示的每个键值映射的键(Object)和值(Object)键值映射是以无特定顺序发出的。< / p>
然而,当我说上面两个不同的对象时,我的意思是“独立创建”,因为我认为它总体上是一个更好的案例,让我们考虑Object.clone的合同来确定它不添加其他限制(事实上,clone
失去 equals
限制条件:
创建并返回此对象的副本。 “复制”的确切含义可能取决于对象的类别。对于任何对象x,一般意图是表达式:
x.clone() != x
将是真的,表达式为:
x.clone().getClass() == x.getClass()
将是真的,但这些并非绝对要求。虽然通常的情况是:
x.clone().equals(x)
将是真的,这不是绝对的要求。
作为clone
暗示具有完全相同序列化表示的对象的进一步反例,请考虑使用序列化实现clone
的对象(这完全有效)并且在一些语言中完成):由于序列化没有字节相等的要求(例如排序,如Hastable.writeObject的情况),因此也不保证这种序列化/反序列化(以及后来的序列化)的恢复顺序。
仅仅因为这样的规则适用于实践中使用的所有类型/实现(并且它很可能会),不暗示byteEquals(serialize(a), serialize(clone(a))
不是真的类型违反了任何类型/实现陈述合同或以其他方式不正确实施。
以下是使用Hashtable
的一些代码(我选择此类型,因为它 实现Serializable并且我确实找到了上面的文档)可能展示“等于”的问题,而不是“序列化时的字节等于”:
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static byte[] serialize(Object v) throws java.lang.Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(v);
return bos.toByteArray();
}
public static void main (String[] args) throws java.lang.Exception
{
Hashtable v1 = new Hashtable();
Hashtable v2 = new Hashtable();
int r = 1000;
for (int x = 0; x <= r; x++) {
v1.put(x, 0);
v2.put(r - x, 0);
}
byte[] byteArr1 = serialize(v1);
byte[] byteArr2 = serialize(v2);
System.out.println(v1.equals(v2));
System.out.println(Arrays.equals(byteArr1, byteArr2));
}
}
而且,在Ideone上,对我来说总是如此,根据OpenJDK implementation (以及之前的文档摘录),这不一定是条目的顺序(在碰撞和链接的情况下)没有明确定义:
933 private void More ...writeObject(java.io.ObjectOutputStream s)
934 throws IOException {
935 Entry<K, V> entryStack = null;
936
937 synchronized (this) {
938 // Write out the length, threshold, loadfactor
939 s.defaultWriteObject();
940
941 // Write out length, count of elements
942 s.writeInt(table.length);
943 s.writeInt(count);
944
945 // Stack copies of the entries in the table
946 for (int index = 0; index < table.length; index++) {
947 Entry<K,V> entry = table[index];
948
/* order of chained entries is not well defined!! */
949 while (entry != null) {
950 entryStack =
951 new Entry<>(0, entry.key, entry.value, entryStack);
952 entry = entry.next;
953 }
954 }
955 }
956
957 // Write out the key/value objects from the stacked entries
958 while (entryStack != null) {
959 s.writeObject(entryStack.key);
960 s.writeObject(entryStack.value);
961 entryStack = entryStack.next;
962 }
963 }
(OpenJDK实现的Hashtable.clone确实维护了条目的排序,但我省略了它,因为它不支持上面代码中概述的情况;创建符合Clonable / Serializable的自定义类型是微不足道的在违反任何合同要求的情况下违反了提出的初始问题。)