序列化动态生成的类

时间:2013-02-23 17:58:54

标签: java serialization dynamic-class-loaders

假设我有一个抽象类

public abstract class Base implements Serializable {
    static final long serialVersionUID = 1;
    public Base(int x) { ... }
    public abstract void baseMethod();
}

然后我动态创建类

public class Temp {
    public Base getBase() {
        return new Base(2) {

            static final long serialVersionUID = 1;

            @Override
            public void baseMethod() { .... } 
        };
    }
}

我能够动态地从String生成类Temp,调用新实例,并提取基础对象并像扩展Base的任何其他实例一样使用它。当我序列化时出现问题。我可以序列化从动态Temp类中提取的Base基础对象,但之后我不能在不同的会话中反序列化,因为Temp不再在类路径上。

你能想到这个吗?必须有一种方法可以将相关的Base对象与Temp类隔离开来(在我从中提取Base类之后我从不关心它)。 Base对象不依赖于Temp类中的任何内容。

2 个答案:

答案 0 :(得分:1)

尝试在writeReplace对象上实施Temp,以便在Base对象上编写readResolve并实施Base,以便创建Temp {1}}包裹它。请参阅Serializable contract

代码看起来像这样。请注意,我实际上没有测试过这个,但它应该非常接近。

public class Base implements Serializable {
    // Existing members here

    private Object readResolve() throws ObjectStreamException {
        return new Temp(this);
    }
}

public class Temp implements Serializable {
    Base base;

    public Temp(Base base) {
        this.base = base;
    }

    // Other existing methods here

    private Object writeReplace() throws ObjectStreamException {
        return base;
    }
}

我意识到这会在这两个类之间引入一个令人讨厌的循环依赖,但我没有看到另外一种很好的方法,除了其他人建议的外部读/写方法。这种方法的优点是它支持写出Temp作为更大对象图的一部分。

答案 1 :(得分:0)

首先,理查德这是我第一次看到这个奇怪的案例,感谢他把它拿出来;) 在这里,我已经找到了解决问题的方法。我希望这可能对你有所帮助。:

import java.io.*;
abstract class Base implements Serializable
{
    protected int x ;
    private static final long serialVersionUID = 1L;
    public Base(int x) { this.x = x; }
    public abstract void baseMethod();
}
class Temp implements Serializable
{
    private static final long serialVersionUID = 2L;//Make Temp serializable also.
    public Base getBase(int i) 
    {
        Base base = new Base(i)
        {
            static final long serialVersionUID = 1L;
            @Override
            public void baseMethod() { System.out.println(x); } 
        };
        return base;
    }
}
public class ReadWriteBaseObject 
{
    public static Base createBaseObject(int i)
    {
        Temp temp = new Temp();//You might be creating your Temp object here Dynamically..
        Base base = temp.getBase(i);
        return base;
    }
    public static Base read()
    {
        ObjectInputStream oin = null;
        try
        {
            FileInputStream fin = new FileInputStream("BASE.ser");
            oin = new ObjectInputStream(fin);
            Base base = (Base)oin.readObject();
            return base;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            return null;
        }
        finally
        {
            if (oin!=null)
            {
                try
                {
                    oin.close();
                }
                catch (Exception ex){}
            }
        }
    }
    public static void write(Base base)
    {
        if (base == null)
        {
            System.out.println("Can't write null");
            return;
        }
        ObjectOutputStream os = null;
        try
        {
            FileOutputStream fos = new FileOutputStream("BASE.ser");
            os = new ObjectOutputStream(fos);
            os.writeObject(base);
            System.out.println("Wrote to file");
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if (os!=null)
            {
                try
                {
                    os.close();
                }
                catch (Exception ex){}
            }
        }
    }
    public static void main(String st[])
    {
        Base base = createBaseObject(45);
        write(base);
        Base obj = read();
        obj.baseMethod();
    }
}

修改
虽然匿名类实例可以成功序列化,但由于几个复杂的原因,Java强烈反对它。 Here是java的官方网站:

  

注意 - 内部类的序列化(即,嵌套类)   不是静态成员类),包括本地和匿名类,   因为几个原因而强烈劝阻。因为内在的阶级   在非静态上下文中声明包含隐式非瞬态   引用封闭类实例,序列化这样的内部   类实例将导致其关联外部的序列化   类实例也是如此。由javac生成的合成字段(或   其他JavaTM编译器)实现内部类   依赖于实现,可能因编译器而异;分歧   在这些领域可以破坏兼容性并导致
  冲突的默认serialVersionUID值。分配给的名称   本地和匿名内部类也依赖于实现   编译器之间可能有所不同。由于内部类不能声明   除了编译时常量字段之外的静态成员,它们不能   使用serialPersistentFields机制来指定serializable   领域。最后,因为内部类与外部相关联   实例没有零参数构造函数(构造函数)   这样的内部类隐式地接受封闭的实例作为   前置参数),它们无法实现Externalizable。没有   但是,上面列出的问题适用于静态成员类。

要了解有关Java中序列化的更多信息,您可以观看here