java.io.InvalidClassException: entity.User; local classincompatible: stream classdescserialVersionUID=8550471390860600205, local classserialVersionUID = -7433272285406297333
当实现 java.io.Serializable 接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的 Class 自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果 Class 文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的。
所以,在项目中 User 类中并没有显式的定义serialVersionUID。所以,在我精简代码后,serialVersionUID发生变化,导致反序列化失败。解决方法也很简单,,显式声明与流中相同的serialVersionUID即可。
java.io.ObjectOutputStream /** * Writes class descriptor representing a standard (i.e., not a dynamic * proxy) class to stream. */ privatevoidwriteNonProxyDesc(ObjectStreamClass desc, boolean unshared) throws IOException { bout.writeByte(TC_CLASSDESC); handles.assign(unshared ? null : desc);
if (protocol == PROTOCOL_VERSION_1) { // do not invoke class descriptor write hook with old protocol desc.writeNonProxy(this); } else { writeClassDescriptor(desc); }
java.io.ObjectStreamClass /** * Writes non-proxy class descriptor information to given output stream. */ voidwriteNonProxy(ObjectOutputStream out)throws IOException { out.writeUTF(name); out.writeLong(getSerialVersionUID());//写入获取的serialVersionUID
out.writeShort(fields.length); for (inti=0; i < fields.length; i++) { ObjectStreamFieldf= fields[i]; out.writeByte(f.getTypeCode()); out.writeUTF(f.getName()); if (!f.isPrimitive()) { out.writeTypeString(f.getTypeString()); } } }
java.io.ObjectStreamClass /** * Return the serialVersionUID for this class. The serialVersionUID * defines a set of classes all with the same name that have evolved from a * common root class and agree to be serialized and deserialized using a * common format. NonSerializable classes have a serialVersionUID of 0L. * * @return the SUID of the class described by this descriptor * 回此类的 serialVersionUID。serialVersionUID 定义了一组具有相同名称的类,它们的名称都是从公共根类演化而来的,并且能够使用公共格式进行序列化和反序列化。NonSerializable 类的 serialVersionUID 为 0L。 */ publiclonggetSerialVersionUID() { // REMIND: synchronize instead of relying on volatile? if (suid == null) { suid = AccessController.doPrivileged( newPrivilegedAction<Long>() { public Long run() { return computeDefaultSUID(cl); } } ); } return suid.longValue(); }