1

假设我有一个抽象类

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 类中的任何内容。

4

2 回答 2

1

尝试writeReplace在您的Temp对象上实现,以便它编写 a Base,并readResolve在您的Base对象上实现,以便它创建Temp包装它的 a 。请参阅Serializable 合约

代码看起来像这样。请注意,我实际上并没有对此进行测试,但应该非常接近。

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

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

于 2013-02-23T18:24:38.243 回答
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 仍然强烈反对它。以下是java官方网站的说明:

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

要了解有关 java 中的序列化的更多信息,您可以在此处观看

于 2013-02-23T19:02:30.837 回答