【问题标题】:How to dynamically populate the fields of a class in Java如何在Java中动态填充类的字段
【发布时间】:2014-07-24 22:30:51
【问题描述】:

我知道以下不是一个好的设计,但这是我需要解决的问题

public final class TestBean {

    private String field1;
    private String field2;
    private String field3;

    public String getField1() {
        return field1;
    }
    public void setField1(String field1) {
        this.field1 = field1;
    }
    public String getField2() {
        return field2;
    }
    public void setField2(String field2) {
        this.field2 = field2;
    }
    public String getField3() {
        return field3;
    }
    public void setField3(String field3) {
        this.field3 = field3;
    }
}

并且类中的字段需要动态填充。

假设我有一个数组 {"abc","def"},该类应该以 field1="abc", field2="def" 和 field3="";如果数组是 {"a"} 并且 field1="a",field2="",field3="".

有可能实现吗?


更新:显然我没有很好地说明这个问题。实际上,字段不只是三个,它是从字段 1、字段 2 到字段 15。然后它不只是一个字段,还有另一个字段调用让我们说名称,从名称 1 到名称 15:

public final class TestBean {

    private String field1;
    private String field2;
    ...
    private String field15;

    private String name1;
    private String name2;
    ...
    private String name15;

}

【问题讨论】:

  • 为什么不在运行时“更改”值...?
  • 通过使用该类的对象,您可以随时填充数据
  • 是根据数组长度或值改变字段的值。
  • 你有没有考虑定义一个构造函数?因为我认为这就是你所要求的......
  • 在构造函数中传递数组并将字段初始化为构造函数中的相应值

标签: java


【解决方案1】:

你可以这样做,即使我不喜欢它(根据String[] 值构建对象不是很干净)。

public final class TestBean {

    private String field1 = "";
    private String field2 = "";
    private String field3 = "";

    public TestBean(String[] values) {
        switch (values.length) {
            case 1:
                  field1 = values[0];
                  break;
            case 2:
                  field1 = values[0];
                  field2 = values[1];
                  break;
            case 3:
                  field1 = values[0];
                  field2 = values[1];
                  field3 = values[2];
                  break;
            default:
                  break;
        }
    }

    public String getField1() {
        return field1;
    }
    public void setField1(String field1) {
        this.field1 = field1;
    }
    public String getField2() {
        return field2;
    }
    public void setField2(String field2) {
        this.field2 = field2;
    }
    public String getField3() {
        return field3;
    }
    public void setField3(String field3) {
        this.field3 = field3;
    }
}

编辑

正如您的版本所说,您需要使用不同的名称填充字段。做到这一点的最好方法是使用 Absurd-Mind 的解决方案。 您将无法使用反射,因为方法 #Class.getDeclaredFields() 返回一个未排序的数组。 CF javadoc for getDeclaredFields():

返回的数组中的元素没有排序,也不在任何 特定的顺序。

如果此数组包含字段按照它们在类中的写入顺序,则可以在迭代 String[] 时获取它并使用反射填充字段。但这里不可能。

【讨论】:

  • Absurd-Mind 解决方案更好。
【解决方案2】:

您可以使用可变参数来实现:

public TestBean(String... args) {
    field1 = "";
    field2 = "";
    field3 = "";

    if (args.length >= 1) field1 = args[0];
    if (args.length >= 2) field2 = args[1];
    if (args.length >= 3) field3 = args[2];
}

并以这种方式初始化您的对象:

new TestBean("abc", "foo");

String[] array = new String[]{"abc", "foo"};
new TestBean(array); // or this way if the array already exists

【讨论】:

  • 我更喜欢你的解决方案而不是我的解决方案:)。
  • 也许您应该使用String[] 作为构造函数参数来匹配所需的问题。
  • @lpratlong 为什么? String... 作为String[] 处理。所以这也有效:new TestBean(new String[]{"abc", "foo"});
  • @Absurd-Mind 我就是这么说的。你编辑了你的答案添加了这个new TestBean(new String[]{"abc", "foo"});所以我想你明白我在说什么:)。
【解决方案3】:

您应该修改TestBean 类,使其具有三个这样的构造函数:

public final class TestBean {

    private String field1;
    private String field2;
    private String field3;

    public TestBean() {
        this("", "", "");
    }

    public TestBean(String field1) {
        this(field1, "", "");
    }

    public TestBean(String field1, String field2) {
        this(field1, field2, "");
    }

    public TestBean(String field1, String field2, String field3) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
    }

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public String getField2() {
        return field2;
    }

    public void setField2(String field2) {
        this.field2 = field2;
    }

    public String getField3() {
        return field3;
    }

    public void setField3(String field3) {
        this.field3 = field3;
    }
}

因此,即使您只填充第一个和/或第二个字段,其余字段也将填充默认的空白字符串。

例如,以下所有用途都可以:

new TestBean();
new TestBean("abc");
new TestBean("abc", "def");
new TestBean("abc", "def", "ghi");

任何未填充到构造函数中的剩余字段将被初始化为空字符串。

【讨论】:

    【解决方案4】:

    您问题的另一个答案:

    您想要实现的目标就像代码异味。您有一个 String 字段列表(带有数字!),您希望按顺序对其进行初始化。这需要数组或集合。

    示例:

    class TestBean {
        String[] field; // String field1; becomes field[0];
        String[] name;
    }
    

    如果您真的坚持使用反射来初始化您的 bean,您可以使用以下代码,但我强烈建议您不要这样做。相反,您应该重构您的类并为我们提供更合适的设计:

    public class TestBean {
        // initialize the field with the default value
        private String field1 = "";
        private String field2 = "";
    
        private String name1 = "";
    
        // establich an order on the fields, because getFields does not
        private static final List<String> order = Arrays.asList("field1", "field2", "name1");
    
        // using var args like in my other answer
        public TestBean(String... args) {
            // declared fields, instead of getFields so we get also private fields
            for (Field f : getClass().getDeclaredFields()) {
    
                // what is the position of the field
                int index = order.indexOf(f.getName());
    
                // if we found the field and a value is given set it.
                if (index < args.length && index >= 0) {
                    try {
                        f.set(this, args[index]);                 
                    } catch (IllegalArgumentException e) {
                        // should not happen
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        // should not happen
                        e.printStackTrace();
                    }
                } // you could use an else clause to set the field default
            }
        }
    
        public static void main(String[] args) {
            TestBean tb = new TestBean("abc", "foo");
            System.out.println(tb.field1);
            System.out.println(tb.field2);
            System.out.println(tb.name1);
        }
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 2013-10-03
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 2019-01-20
      相关资源
      最近更新 更多