Programing

사용자 정의 열거 형도 직렬화 가능합니까?

lottogame 2020. 12. 30. 07:40
반응형

사용자 정의 열거 형도 직렬화 가능합니까?


Enum직렬화 가능 하다는 것을 이해 합니다. 따라서 그렇게하는 것이 안전합니다. (selectedCountry는 enum Country)

고객 멤버 변수가없는 원래 열거 형

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);
}

그러나 사용자 지정 열거 형 클래스에 직렬화 할 수없는 멤버가있는 경우 어떻게해야합니까? 예를 들어

원래 열거 형 고객 멤버 변수

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;
}

나는 테스트했다. 효과가있다. (직렬화 전후의 모든 멤버 변수 값을 인쇄하여 테스트했습니다. 이전과 이후는 동일합니다.)

그러나 왜 작동하는지 이해하지 못합니까? 인터페이스에서 요구하는대로 적절한 readObject및을 제공하지 않습니다 .writeObjectSerializable

효과적인 Java 항목 75 : 사용자 정의 직렬화 된 양식을 사용하는 것을 고려하십시오 . 내 열거 형에 사용자 정의 멤버 변수가있는 경우 자체 readObject을 제공해야 writeObject합니까?


작동하는 이유 Enum는의 직렬화 프로세스가 다른 클래스의 직렬화 프로세스와 다르기 때문입니다. 로부터 공식 문서 :

1.12 열거 형 상수 직렬화

Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form. To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.lang.Enum.valueOf method, passing the constant's enum type along with the received constant name as arguments. Like other serializable or externalizable objects, enum constants can function as the targets of back references appearing subsequently in the serialization stream.

That means, all your custom fields won't be serialized. In your case everything works well because your application process is still running and you are getting the same Enum instance that you passed to savedInstanceState.putSerializable.

But imagine a situation where your app get killed because Android has no enough memory. The next time user opens the app you will get a new Enum instance and all custom fields will have been lost and reinitialized by the constructor. Thus, mutable fields in an enum are always effectively transient.


As per Serializable documentation, readObject and writeObject are not needed at all, so your question might be not fully correct.

Serializable is a marker interface and doesn't have any methods.

I refer you to this answer which provides additional details about the Serialization implementation (which explains why you don't necessary need write and read functions).

And, as mentioned here by Dianne Hackborn, Parcelable is much more efficient for Android.

If you're particularly interested in Enum, refer to below paragraph:

1.12 Serialization of Enum Constants

Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form. To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.lang.Enum.valueOf method, passing the constant's enum type along with the received constant name as arguments. Like other serializable or externalizable objects, enum constants can function as the targets of back references appearing subsequently in the serialization stream.

The process by which enum constants are serialized cannot be customized: any class-specific writeObject, readObject, readObjectNoData, writeReplace, and readResolve methods defined by enum types are ignored during serialization and deserialization. Similarly, any serialPersistentFields or serialVersionUID field declarations are also ignored--all enum types have a fixed serialVersionUID of 0L. Documenting serializable fields and data for enum types is unnecessary, since there is no variation in the type of data sent.

So, I don't think that the Enum is the right choice to test internal non-serializable classes work.


The serialization of enum members is not working. The nonSerializable field is never serialized as @vmironov answered. Here is a test:

public enum Country {
Australia;

    public static class NonSerializableClass {
       public NonSerializableClass() {}
       public String dummy;
    }

    public NonSerializableClass nonSerializableClass;
}

The code writing the enum to the serialization 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);
    }
}    

On writing the value of the dummy field is: abc

The code reading the enum from the serialization 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);
    }
}

But on reading, the value of the field nonSerializableClass is: null

ReferenceURL : https://stackoverflow.com/questions/15521309/is-custom-enum-serializable-too

반응형