也是自定义的枚举可序列化?
我明白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,它们在之前和之后是相同的)
但是,我不明白为什么它可行? 由于我没有提供正确的readObject
和writeObject
,所以需要Serializable
接口。
正如在Effective Java Item 75中所指出的那样:考虑使用自定义序列化表单 ,如果我在自己的枚举中有自定义成员variables,是否需要提供自己的readObject
和writeObject
?
它的工作原因是Enum
的序列化过程与其他类的序列化过程不同。 从官方文档 :
1.12枚举常量的序列化
枚举常量序列化不同于普通的可序列化或可外部化的对象。 枚举常量的序列化forms仅由其名称组成; 常量的字段值不存在于表单中。 要序列化一个枚举常量,ObjectOutputStream写入枚举常量的名称方法返回的值。 要反序列化一个枚举常量,ObjectInputStream从stream中读取常量名称; 然后通过调用java.lang.Enum.valueOf方法获得反序列化的常量,将常量的枚举types与接收的常量名称一起作为parameter passing。 像其他可串行化或可外部化的对象一样,枚举常量可以作为序列化stream中随后出现的后向引用的目标。
这意味着,所有的自定义字段将不会被序列化。 在你的情况下,一切正常,因为你的应用程序进程仍在运行,你得到的是传递给savedInstanceState.putSerializable
Enum
实例。
但想象一下,由于Android
没有足够的内存,您的应用程序被杀死的情况。 下一次用户打开应用程序,你会得到一个新的 Enum
实例,所有的自定义字段将会被构造函数丢失并重新初始化。 因此,枚举中的可变字段总是有效的transient
。
根据Serializable文档, readObject
和writeObject
根本不需要,所以你的问题可能不完全正确。
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