Java 在枚举反序列化期间未调用readResolve()

Java 在枚举反序列化期间未调用readResolve(),java,serialization,enums,singleton,deserialization,Java,Serialization,Enums,Singleton,Deserialization,在对枚举对象进行反序列化期间,不会调用readResolve()。 我试图做的原因是比较实现单身的两种方式 Singleton可以通过两种方式实现 静态实例对象和私有构造函数的传统方法 使用单对象枚举 第二种方法需要更少的编码 我比较了这两种方法,比较了重写单例行为的方法和程序员应该注意的事项 1) 克隆 在传统方法中,不实现可克隆接口或在clone()方法中抛出错误。 在枚举方式中,不需要它,因为克隆是不可能的,因为枚举无法实现可克隆方法 2) 通过反射创建对象 在传统方法中,若实例已经初始化

在对枚举对象进行反序列化期间,不会调用readResolve()。 我试图做的原因是比较实现单身的两种方式

Singleton可以通过两种方式实现

  • 静态实例对象和私有构造函数的传统方法
  • 使用单对象枚举
  • 第二种方法需要更少的编码

    我比较了这两种方法,比较了重写单例行为的方法和程序员应该注意的事项

    1) 克隆

    在传统方法中,不实现可克隆接口或在clone()方法中抛出错误。 在枚举方式中,不需要它,因为克隆是不可能的,因为枚举无法实现可克隆方法

    2) 通过反射创建对象

    在传统方法中,若实例已经初始化,则在构造函数中抛出错误。 在枚举方式中,它是不需要的,因为我们不能反射地创建枚举对象。它抛出错误“java.lang.IllegalArgumentException:无法反射创建枚举对象”

    3) 序列化反序列化

    在传统的实现serializable接口中,或者如果实现readResolve()方法,则返回相同的实例

    现在在枚举中,默认情况下是可序列化的。因此,我实现了readResolve(),但是在反序列化完成时不调用readResolve()。 它自动给我枚举对象的最新状态。 为什么会这样

    public enum MySingletonEnum {
    instance(41,"Devendra");
    
    private MySingletonEnum(int age, String name){
            this.age = age;
            this.name = name;
    }
    
    private int age;
    private String name;
    // getters and setters
    
    public static MySingletonEnum getInstance(){
        return instance;
    }
    
      //Hook for not breaking the singleton pattern while deserializing.
    private Object readResolve() throws ObjectStreamException {
        System.out.println("The constructed obejct has age="+age+" name="+name);
        System.out.println("But now returning same instance");
          return instance;
    }
    }
    
    现在上课 我序列化了MySingletonEnum.getInstance()。所以我写的是年龄=41,名字=Devendra

    然后将MySingletonEnum.getInstance()的属性,即“Age”更改为999,“Name”更改为“Kaushik”

    然后反序列化对象

    未调用readResolve()方法。仍然反序列化的对象的年龄为999,名称为Kaushik

    public static void  trySerialization() throws FileNotFoundException, IOException, ClassNotFoundException{
        String filePath = "d:\\kaushik\\kaushik26Feb.txt";
        File f = new File(filePath);
        f.createNewFile();
    
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        oos.writeObject(MySingletonEnum.getInstance());
        oos.close();
        MySingletonEnum.getInstance().setAge(999);
        MySingletonEnum.getInstance().setName("Kaushik");
        System.out.println("Printing values before deserialize");
        MySingletonEnum.getInstance().print();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        MySingletonEnum deserializedObj = (MySingletonEnum)ois.readObject();
    
        System.out.println("deserializedObj="+deserializedObj);
        System.out.println(deserializedObj.getAge()+" ...."+deserializedObj.getName());
    
        if(deserializedObj==MySingletonEnum.getInstance()){
            System.out.println("Same instance");
        }else{
            System.out.println("Different instance");
        }
    }
    
    输出

    Printing values before deserialize
    999 ....Kaushik
    deserializedObj=instance
    999 ....Kaushik
    Same instance
    
    是不是应该显示41,德文德拉? 怎么会这样?

    因为:

    public enum MySingletonEnum {
    instance(41,"Devendra");
    
    private MySingletonEnum(int age, String name){
            this.age = age;
            this.name = name;
    }
    
    private int age;
    private String name;
    // getters and setters
    
    public static MySingletonEnum getInstance(){
        return instance;
    }
    
      //Hook for not breaking the singleton pattern while deserializing.
    private Object readResolve() throws ObjectStreamException {
        System.out.println("The constructed obejct has age="+age+" name="+name);
        System.out.println("But now returning same instance");
          return instance;
    }
    }
    
  • enum
    已经没有打破单例模式。您不需要自己实现这一点

  • 因为:

  • enum
    已经没有打破单例模式。您不需要自己实现这一点


  • 您是如何更改MySingletonEnum.getInstance()的属性的?这样做的?因为聪明的Java工程师已经确保枚举不会被序列化破坏,并且对于给定的类加载器,每个枚举实例只存在一次。查看您是如何操作的
    ,然后更改MySingletonEnum.getInstance()的属性。
    这?使用年龄和名称的setter方法,因为聪明的Java工程师已经确保枚举不会被序列化破坏,并且对于给定的类加载器,每个枚举实例只存在一次。看见