也是自定义的枚举可序列化?

我明白Enum是可序列化的。 因此,这样做是安全的。 (selectedCountry是enum Country

没有客户成员variables的原始枚举

 public enum Country { Australia, Austria, UnitedState; } 

分段

 @Override public void onActivityCreated (Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (savedInstanceState != null) { selectedCountry = (Country)savedInstanceState.getSerializable(SELECTED_COUNTRY_KEY); } } @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putSerializable(SELECTED_COUNTRY_KEY, selectedCountry); } 

但是,如果我在自定义枚举类中有非序列化成员呢? 例如,

原始的枚举客户成员variables

 package org.yccheok; import org.yccheok.R; /** * * @author yccheok */ public enum Country { Australia(R.drawable.flag_au), Austria(R.drawable.flag_at), UnitedState(R.drawable.flag_us); Country(int icon) { this.icon = icon; nonSerializableClass = new NonSerializableClass(this.toString()); } public int getIcon() { return icon; } public static class NonSerializableClass { public NonSerializableClass(String dummy) { this.dummy = dummy; } public String dummy; } private final int icon; public NonSerializableClass nonSerializableClass; } 

我testing过了。 有用。 (我通过在序列化之前和之后打印出所有成员variables的值来进行testing,它们在之前和之后是相同的)

但是,我不明白为什么它可行? 由于我没有提供正确的readObjectwriteObject ,所以需要Serializable接口。

正如在Effective Java Item 75中所指出的那样:考虑使用自定义序列化表单 ,如果我在自己的枚举中有自定义成员variables,是否需要提供自己的readObjectwriteObject

它的工作原因是Enum的序列化过程与其他类的序列化过程不同。 从官方文档 :

1.12枚举常量的序列化

枚举常量序列化不同于普通的可序列化或可外部化的对象。 枚举常量的序列化forms仅由其名称组成; 常量的字段值不存在于表单中。 要序列化一个枚举常量,ObjectOutputStream写入枚举常量的名称方法返回的值。 要反序列化一个枚举常量,ObjectInputStream从stream中读取常量名称; 然后通过调用java.lang.Enum.valueOf方法获得反序列化的常量,将常量的枚举types与接收的常量名称一起作为parameter passing。 像其他可串行化或可外部化的对象一样,枚举常量可以作为序列化stream中随后出现的后向引用的目标。

这意味着,所有的自定义字段将不会被序列化。 在你的情况下,一切正常,因为你的应用程序进程仍在运行,你得到的是传递给savedInstanceState.putSerializable Enum实例。

但想象一下,由于Android没有足够的内存,您的应用程序被杀死的情况。 下一次用户打开应用程序,你会得到一个新的 Enum实例,所有的自定义字段将会被构造函数丢失并重新初始化。 因此,枚举中的可变字段总是有效的transient

根据Serializable文档, readObjectwriteObject根本不需要,所以你的问题可能不完全正确。

Serializable是一个标记接口 ,没有任何方法。

我把这个答案提交给你, 这个答案提供了序列化实现的更多细节(这就解释了为什么你不需要写和读函数)。

而且,正如Dianne Hackborn 在这里提到的那样, Parcelable对Android来说效率更高。

如果你对Enum特别感兴趣,请参考下面的段落 :

1.12枚举常量的序列化

枚举常量序列化不同于普通的可序列化或可外部化的对象。 枚举常量的序列化forms仅由其名称组成; 常量的字段值不存在于表单中。 要序列化一个枚举常量,ObjectOutputStream写入枚举常量的名称方法返回的值。 为了反序列化一个枚举常量,ObjectInputStream从stream中读取常量名称; 然后通过调用java.lang.Enum.valueOf方法获得反序列化的常量,将常量的枚举types与接收的常量名称一起作为parameter passing。 像其他可串行化或可外部化的对象一样,枚举常量可以作为序列化stream中随后出现的后向引用的目标。

枚举常量序列化的过程不能自定义:在序列化和反序列化过程中,由枚举types定义的任何类特定的writeObject,readObject,readObjectNoData,writeReplace和readResolve方法都将被忽略。 同样,任何serialPersistentFields或serialVersionUID字段声明也被忽略 – 所有枚举types都有一个固定的serialVersionUID 0L。 为枚举typeslogging可序列化的字段和数据是不必要的,因为发送的数据types没有变化。

所以,我不认为Enum是testing内部不可序列化类工作的正确select。

枚举成员的序列化不起作用。 不能@vmironov回答nonSerializable字段。 这是一个testing:

 public enum Country { Australia; public static class NonSerializableClass { public NonSerializableClass() {} public String dummy; } public NonSerializableClass nonSerializableClass; } 

将枚举写入序列化stream的代码:

 public class SerializationTestWrite { public static void main(String[] args) throws Exception{ FileOutputStream f = new FileOutputStream("tmp"); ObjectOutput s = new ObjectOutputStream(f); Country.Australia.nonSerializableClass = new Country.NonSerializableClass(); Country.Australia.nonSerializableClass.dummy = "abc"; s.writeObject(Country.Australia); s.flush(); System.out.println(Country.Australia.nonSerializableClass.dummy); } } 

在写入虚拟字段的值是: abc

从序列化stream中读取枚举的代码:

 public class SerializationTestRead { public static void main(String[] args) throws Exception{ FileInputStream in = new FileInputStream("tmp"); ObjectInputStream so = new ObjectInputStream(in); Country readed = (Country) so.readObject(); System.out.println(readed.nonSerializableClass); } } 

但在阅读时, nonSerializableClass字段的值是:null