Java 序列化动态生成的类

Java 序列化动态生成的类,java,serialization,dynamic-class-loaders,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() { re

假设我有一个抽象类

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() { .... } 
        };
    }
}
我能够从字符串动态生成类Temp,调用一个新实例,提取基对象,并像任何其他扩展基对象的实例一样使用它。当我序列化时,问题就出现了。我可以序列化从动态Temp类中提取的基本对象,但随后无法在其他会话中反序列化,因为Temp不再位于类路径上


你们能想办法解决这个问题吗?必须有一种方法可以从Temp类中分离出有问题的基本对象(在从Temp类中提取基类之后,我从不关心这个问题)。基本对象不依赖于Temp类中的任何内容。

尝试在
Temp
对象上实现
writeReplace
,以便写入
Base
,并在
Base
对象上实现
readResolve
,从而创建一个包装它的
Temp
。看

代码看起来像这样。请注意,我并没有实际测试这个,但它应该是相当接近

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
作为较大对象图的一部分写入。请尝试在
Temp
对象上实现
writeReplace
,以便它写入
,并在
Base
对象上实现
readResolve
,以便它创建一个包装它的
Temp
。看

代码看起来像这样。请注意,我并没有实际测试这个,但它应该是相当接近

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
作为更大对象图的一部分来编写。

首先,Richard,这是我第一次看到这种特殊情况,谢谢你的介绍;) 在这里,我找到了一些解决你问题的方法。我希望这对你有帮助

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编译器包括 取决于实现,并且可能因编译器而异;分歧 在这些字段中,可能会破坏兼容性并导致
冲突的默认SerialVersionId值。分配给某人的名字 本地和匿名内部类也依赖于实现 编译器之间可能会有所不同。因为内部类不能声明 除了编译时常量字段以外的静态成员,它们不能 使用serialPersistentFields机制指定serializable 领域。最后,因为内部类与外部类关联 实例没有零参数构造函数(的构造函数 这样的内部类隐式地接受封闭实例作为 前置参数),它们无法实现外部化。都不 但是,上面列出的问题适用于静态成员类


要了解更多关于java序列化的信息,您可以观看

首先,Richard这是我第一次看到这种特殊情况,谢谢您的介绍;) 在这里,我找到了一些解决你问题的方法。我希望这对你有帮助

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编译器包括 取决于实现,并且可能因编译器而异;分歧 在这些字段中,可能会破坏兼容性并导致
冲突的默认SerialVersionId值。分配给某人的名字 本地和匿名内部类也依赖于实现 编译器之间可能会有所不同。因为内部类不能声明 除了编译时常量字段以外的静态成员,它们不能 使用serialPersistentFields机制指定serializable 领域。最后,因为内部类与外部类关联 实例没有零参数构造函数(的构造函数 这样的内部类隐式地接受封闭实例作为 前置参数),它们无法实现外部化。都不 但是,上面列出的问题适用于静态成员类<