假设我有一个抽象类
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类中的任何内容。
答案 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