麻烦帮忙看看这段关于java的序列化的代码,摘自Effective Java

package org.effectivejava.examples.chapter11.item77;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Arrays;

// Broken singleton - has nontransient object reference field!
public class Elvis implements Serializable {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() {
    }

    private String[] favoriteSongs = { "Hound Dog", "Heartbreak Hotel" };

    public void printFavorites() {
        System.out.println(Arrays.toString(favoriteSongs));
    }

    private Object readResolve() throws ObjectStreamException {
        return INSTANCE;
    }
}
 package org.effectivejava.examples.chapter11.item77;
import java.io.Serializable;

public class ElvisStealer implements Serializable {
    static Elvis impersonator;
    private Elvis payload;

    private Object readResolve() {
        // Save a reference to the "unresolved" Elvis instance
        impersonator = payload;

        // Return an object of correct type for favorites field
        return new String[] { "A Fool Such as I" };
    }

    private static final long serialVersionUID = 0;
}
 package org.effectivejava.examples.chapter11.item77;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;

public class ElvisImpersonator {
    // Byte stream could not have come from real Elvis instance!
    private static final byte[] serializedForm = new byte[] { (byte) 0xac,
            (byte) 0xed, 0x00, 0x05, 0x73, 0x72, 0x00, 0x05, 0x45, 0x6c, 0x76,
            0x69, 0x73, (byte) 0x84, (byte) 0xe6, (byte) 0x93, 0x33,
            (byte) 0xc3, (byte) 0xf4, (byte) 0x8b, 0x32, 0x02, 0x00, 0x01,
            0x4c, 0x00, 0x0d, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65,
            0x53, 0x6f, 0x6e, 0x67, 0x73, 0x74, 0x00, 0x12, 0x4c, 0x6a, 0x61,
            0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a,
            0x65, 0x63, 0x74, 0x3b, 0x78, 0x70, 0x73, 0x72, 0x00, 0x0c, 0x45,
            0x6c, 0x76, 0x69, 0x73, 0x53, 0x74, 0x65, 0x61, 0x6c, 0x65, 0x72,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
            0x4c, 0x00, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x74,
            0x00, 0x07, 0x4c, 0x45, 0x6c, 0x76, 0x69, 0x73, 0x3b, 0x78, 0x70,
            0x71, 0x00, 0x7e, 0x00, 0x02 };

    public static void main(String[] args) {
        // Initializes ElvisStealer.impersonator and returns
        // the real Elvis (which is Elvis.INSTANCE)
        Elvis elvis = (Elvis) deserialize(serializedForm);
        Elvis impersonator = ElvisStealer.impersonator;

        elvis.printFavorites();
        impersonator.printFavorites();
    }

    // Returns the object with the specified serialized form
    private static Object deserialize(byte[] sf) {
        Object result=null;
        try {
            InputStream is = new ByteArrayInputStream(sf);
            ObjectInputStream ois = new ObjectInputStream(is);
            result= ois.readObject();
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
        return result;
    }
}

这代码根本跑不起来,会报错。而ElvisStealer类的readResolve方法居然return new String[] { "A Fool Such as I" };更是让人摸不着头脑,如果返回的是ElvisStealer那还好,但是这里却返回字符数组,那不必错无疑么。求帮忙纠正下这段代码,然后讲一下ElvisStealer类的readResolve方法的return

首先,我测试了你的代码,是能够运行的,我的环境是jdk1.8+Eclipse4.5,运行结果是:

[Hound Dog, Heartbreak Hotel]
[A Fool Such as I]

其次,这个readResolve方法的作用是让程序员定制反序列化操作返回的对象,反序列化调用readObject()时,底层是调用了readResolve()方法的。
最后,再分析你的main方法测试,给出的序列化字节serializedForm 是一个ElvisStealer类的对象的字节数组,它的两个属性payload都是有引用值的。所以你对这个字节数据反序列化时调用readObject时,先调用了ElvisStealer类的readResolve,然后又调用Elvis类的readResolve,得到了Elvis的实例,同时impersonator属性指向payload。

补充一下,而ElvisStealer类的readResolve方法,这里用return new String[] { "A Fool Such as I" },其实是为了定制序列化操作的返回值,通常默认的就是返回原来序列话的值,不会破坏原有的对象信息的。这里可能是为了显示定制,而返回特定的值。它与writeReplace序列化时写入的信息是一致的。我们在定制序列化时应该保证writeReplace和readResolve信息的一致。

楼上答得很好,我也将代码运行了一下,也报错。我用的是 jdk1.7 + Kepler Service Release 2。我查了一下,readResolve()方法与writeReplace()方法是对应的,readResolve()方法可以实现保护性复制整个对象,并且它会紧接着readObject()方法运行,该方法的返回值将会代替原来反序列化的对象
(即也就是readObject()的返回值,这个值将被丢弃)。常用于序列化单例类、枚举类。所以正如楼上所说,readResolve()和writeReplace()方法的作用是让程序员定制反序列化和序列化操作返回的对象