加载 POJO 父项时初始化 Java OOP 瞬态字段

Posted

技术标签:

【中文标题】加载 POJO 父项时初始化 Java OOP 瞬态字段【英文标题】:Java OOP transient field initialising upon loading POJO parent 【发布时间】:2019-03-04 01:55:12 【问题描述】:

所以我有一个非常大的类,其中包含数百个瞬态对象,每次加载父级(在本例中为 Person.class)时都需要重新初始化。 (Peron.class 被加载并保存)

以下是我目前的班级结构的示例:

public final class Person 

    private transient ObjectA a;
    private transient ObjectB b;
    private transient ObjectC c;
    private transient ObjectD d;
    //and hundreds more...

    public Person() 

        initTransientObjects();

    

    private void initTransientObjects() 

        a = new ObjectA();
        b = new ObjectB();
        c = new ObjectC();
        d = new ObjectD();
        //and hundreds more...
     

    public void onReloadAfterFirstSave() 
        initTransientObjects();
    


这使得编写新对象变得非常乏味,我想知道是否有一种方法可以像这样更紧凑:

public final class Person 

    private transient ObjectA a = new ObjectA();
    private transient ObjectB b = new ObjectB();
    private transient ObjectC c = new ObjectC();
    private transient ObjectD d = new ObjectD();
    //and hundreds more...
    //this way I only have to type the new object once instead of twice

    public void onReloadAfterFirstSave() 
        //what here? because now transient fields are null
    


请注意,我不能使用上面的原因是,显然当 Person 再次加载时,瞬态字段将不会被加载,因此会自动设置为 null。

我应该在这里做什么?

编辑:

我还保存在 Person 类中的非瞬态对象以及这些瞬态字段,这就是为什么不能使用它的原因:

Peron person = new Person(); //every load

【问题讨论】:

这看起来很奇怪......你是在将对象写入磁盘吗?为什么要在 Person 类中引用这么多不同的类型? 它被保存为一个对象,但把它想象成一个真实的人,他会有很多属性,比如电视、汽车、房子等...... 如果你序列化这个人而不是它的数据——它仍然没有任何意义。你需要一种不同的抽象。在不知道你在构建什么的情况下,你的代码很难重构。 更不用说你所有的对象在每次“reloadafterfirstsave”之后都会失去它的状态,此时它与仅仅执行“person = new Person()”没有什么不同(除非你有非瞬态属性你没有提到的) 我确实序列化了一些 Person 的数据(这不是暂时的;这里没有显示,因为这不是问题所在),但是这个人会有一些需要每次重置的东西加载,例如,car 和 house 不会是瞬态的并且会被保存,但是,像 TodaysTVProgramSchedule.class 这样的对象会改变(假设玩家每天都重新加载) 【参考方案1】:

你可以试试这个,但我不赞成这样做,主要是因为你需要非常小心例外情况。 我会假设您的 ObjectA、ObjectB、ObjectC 的构造函数不是空的,如果是,那么这将更容易实现。

我为你做了一个示例类

import java.lang.reflect.InvocationTargetException;
import java.util.Random;

/**
 *
 * @author emngaiden
 */
public class Test2 

    ClassContainer[] containers;
    Object[] instantieted_objects;

    public Test2() 
        initObjects();
    

    public static void main(String[] args) 
        Test2 test=new Test2();
        StringBuilder sb=(StringBuilder)test.getObject(2);
        sb.append((String)test.getObject(0));
        sb.append(((Random)test.getObject(1)).nextDouble());
        System.out.println(sb.toString());
    

    public Object getObject(int i)
        return this.instantieted_objects[i];
    

    private void initObjects() 
        //total number of objects ObjectA, ObjectB etc...
        int number_of_objects = 3;
        this.containers = new ClassContainer[number_of_objects];
        this.instantieted_objects = new Object[number_of_objects];
        //create the containers, you write this only one, and can
        //share it between objects of the same class
        this.containers[0] = new ClassContainer(String.class,
                new Class[]String.class,
                new Object[]"hello world"
        );
        this.containers[1] = new ClassContainer(Random.class,
                new Class[]long.class,
                new Object[]192323l
        );
        this.containers[2] = new ClassContainer(StringBuilder.class,
                null,
                null
        );
        //poblate the objects in the array
        for(int i=0; i<this.containers.length; i++)
            try
                this.instantieted_objects[i]=instantiateObject(containers[i]);
            catch(Exception e)
                e.printStackTrace();
            
        
    

    //returns a new object instance based on the container
    private Object instantiateObject(ClassContainer container)
    throws NoSuchMethodException, InstantiationException, IllegalAccessException,
    IllegalArgumentException, InvocationTargetException 
        //no arguments for the constructor means that the constructor is empty
        if(container.args!=null)
            //get the constructor that matches the Class[] array on its arguments
            return 
                container.obj.getConstructor(container.args)
                .newInstance(container.values);
        
        else
            return container.obj.newInstance();
        
    

    //class to hold the necessary data to instantiate the object
    public class ClassContainer 

        //the target class, for ObjectA(int,int)this must be ObjectA.class 
        Class obj;
        //the argument classes, it would be int.class,int.class
        Class[] args;
        //the actual values for the constructor, it would be 1,2
        Object[] values;

        public ClassContainer(Class obj, Class[] args, Object[] values) 
            this.obj = obj;
            this.args = args;
            this.values = values;
        
    

编写代码很有趣,但我不建议使用它。

【讨论】:

有趣。我之前在其他项目上做过这个,发现创建带有额外转换所需的 getter 和 setter(这不能用 ide 自动完成)与我正在使用的仅 oop 类型方法一样乏味。但我也想听听其他人对此的看法

以上是关于加载 POJO 父项时初始化 Java OOP 瞬态字段的主要内容,如果未能解决你的问题,请参考以下文章

从项目中检索父项时出错

AAPT:检索项目的父项时出错:未找到与名称匹配的资源”

检索项目的父项时出错:找不到资源 [重复]

大于动态宽度父项时,弹性项目上的滚动条

检索项目的父项时出错:找不到与给定名称匹配的资源 [重复]

如何在使用Hibernate删除父项时删除所有子行?