对象及其克隆(正确完成)字节表示不应该相同吗?

时间:2014-01-09 07:12:34

标签: java stream bytearray equals

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的字节流表示。

2 个答案:

答案 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合同中没有任何内容在equalswriteObject的结果之间建立任何关系。此外,来自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的自定义类型是微不足道的在违反任何合同要求的情况下违反了提出的初始问题。)