Java创建具有深度空对象的实例

标签 java reflection recursion

我有一个嵌套了自定义对象类型的类。当我创建实例时,我希望使用默认值以及嵌套对象创建实例。我正在检查 Apache Bean Utils 中是否有可用的实用程序类,但还没有运气。有什么简单的方法可以做到这一点吗?如果没有,我必须编写一个递归函数来做到这一点。 例如

A{
 int x;
 B b;
 C c;    
}

B{
 boolean y;
 D d;     
}

D{
 String z;
}

Object a = A.class.newInstance();

上面应该给我一个如下所示的对象,其中 a、b、c、d 填充有默认值(仅适用于基元)

 a 
  |--> x (=0)
  |
  |--> b
  |
  |--> c
       |--> y (=false)
       |
       |--> d
            |--> x (=null)

在不更改实际类的结构的情况下,我想创建一个深度创建空对象的实例。任何想法都高度赞赏!

最佳答案

这将实现您想要的功能,但有一些警告:

  • 它假设有一个默认构造函数。
  • 它会跳过基元。
  • 它会跳过已经初始化的对象。
  • 它只会初始化指定的包(startsWith match),以避免初始化其他变得非常困惑的东西,例如 HashMap 等。
  • 仅使用简单对象进行了测试。
  • 如果您设置了安全管理器策略,您可能无法访问这些字段。
  • 如果存在任何类型的递归循环,例如 obj_A 有一个 obj_B 有一个 obj_A,那么它将因堆栈溢出而失败。
  • 它不会访问和设置父类(super class)的值(但可以这样做)。

我会问这是否是最好的解决方案,因为如果对象深处的情况与预期不一样,它很容易失败。

初始化器.java

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

import org.example.something.A;

public class Initilizer {

    public static void initialize(Object object, Set<String> packages)
            throws IllegalArgumentException,
            IllegalAccessException {
        Field[] fields = object.getClass().getDeclaredFields();

        for (Field field : fields) {
            String fieldName = field.getName();
            Class<?> fieldClass = field.getType();

            // skip primitives
            if (fieldClass.isPrimitive()) {
                System.out.println("Skipping primitive: " + fieldName);
                continue;
            }

            // skip if not in packages
            boolean inPackage = false;
            for (String pack : packages) {
                if (fieldClass.getPackage().getName().startsWith(pack)) {
                    inPackage = true;
                }
            }
            if (!inPackage) {
                System.out.println("Skipping package: "
                        + fieldClass.getPackage().getName());
                continue;
            }

            // allow access to private fields
            boolean isAccessible = field.isAccessible();
            field.setAccessible(true);

            Object fieldValue = field.get(object);
            if (fieldValue == null) {
                System.out.println("Initializing: " + fieldName);
                try {
                    field.set(object, fieldClass.newInstance());
                } catch (IllegalArgumentException | IllegalAccessException
                        | InstantiationException e) {
                    System.err.println("Could not initialize "
                            + fieldClass.getSimpleName());
                }
            } else {
                System.out
                        .println("Field is already initialized: " + fieldName);
            }

            fieldValue = field.get(object);

            // reset accessible
            field.setAccessible(isAccessible);

            // recursive call for sub-objects
            initialize(fieldValue, packages);
        }

    }

    public static void main(String[] args) throws Exception {

        A a = new A();

        // Packages to initialize
        Set<String> packages = new HashSet<>();
        packages.add("com.example");
        packages.add("org.example");

        initialize(a, packages);
    }
}

A.java

package org.example.something;

import com.example.other.B;

public class A {

    private int x;

    private B b;

    private B be = new B();

    private C c;

}

B.java

package com.example.other;

public class B {

    private boolean y;

    private D d;

}

C.java

package org.example.something;
import java.util.HashMap;

public class C {

    private HashMap doNotInit;

}

D.java

package com.example.other;

public class D {

    private String s;

}

输出

Skipping primitive: x
Initializing: b
Skipping primitive: y
Initializing: d
Skipping package: java.lang
Field is already initialized: be
Skipping primitive: y
Initializing: d
Skipping package: java.lang
Initializing: c
Skipping package: java.util

关于Java创建具有深度空对象的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23373421/

相关文章:

java - 安卓。如何使对话框按钮出现在对话框之外

java - 在 NetBeans WebApp 中将库与 JNI 结合使用

java - 如何使用 Java 中的 SIGAR 或 OSHI API 获取特定应用程序的操作系统进程详细信息?

java - getGenericExceptionTypes 和 getExceptionTypes 之间的区别

KProperty1.getDelegate 上的泛型过于严格?

java - 从堆栈跟踪元素获取实际类

c++ - C++ 中的递归帮助

java - 为什么程序没有继续进行

c++ - 在 Turbo C++ 中,可以将普通递归函数转换为尾递归来优化它吗?

java - 我可以在 Web 应用程序中使用 log4j 和 log4j.xml 或 log4j.properties 以外的文件吗?