代码之家  ›  专栏  ›  技术社区  ›  marionmaiden

使用反射将值设置到对象中

  •  5
  • marionmaiden  · 技术社区  · 15 年前

    我有一个物体 很多属性 每一个都有它的getter和setter。每个属性都有一个非基元类型,我在运行时不知道。

    例如,我得到的是:

    public class a{
    
        private typeA attr1;
        private typeB attr2;
    
        public typeA getAttr1(){ return attr1; }
        public typeB getAttr2(){ return attr2; }
    
        public void setAttr1(typeA at){ attr1 = at; }
        public void setAttr2(typeB at){ attr2 = at; }
    }
    
    public class typeA{
        public typeA(){
            // doesn't matter
        }
    }
    
    public class typeB{
        public typeB(){
            // doesn't matter
        }
    }
    

    所以,通过反射,我得到了一个属性的setter方法。以标准方式设置值如下:

    a test = new a();
    a.setAttr1(new typeA());
    

    但我如何才能利用反射来做到这一点呢?我已经有了 设置属性1() 方法使用反射,但我不知道如何创建新的 类型 要插入到setter中的对象。

    4 回复  |  直到 15 年前
        1
  •  11
  •   Community CDub    8 年前

    使用 Class#newInstance()

    Class<TypeA> cls = TypeA.class;
    TypeA typeA = cls.newInstance();
    

    或者,在您的特定情况下,当您必须确定方法参数的类型时:

    Class<?> cls = setterMethod.getParameterTypes()[0];
    Object value = cls.newInstance();
    setterMethod.invoke(bean, value);
    

    你可以在 Sun tutorial on the subject . 也就是说,类名 ought 从大写开始。我已经在上面的例子中纠正了它。

    顺便说一下,您可能会发现上面提到的工具之一,而不是重新设计JavaBean反射轮。 here 也很有用。

        2
  •  3
  •   Robert Kovačević    15 年前

    使用 getDeclaredFields() 中的方法 Class 对象,若要获取所有字段,请使用 field.set(classInstance, value) 设置实例中字段的值。注意:如果字段是私有的,则可能需要将字段上的可访问标志设置为true。不需要依赖setter方法。

        3
  •  2
  •   Bill K    15 年前

    我在做一些事情时遇到过这个问题。我的一般结论是,每当我觉得需要一个有很多领域的课程时,我都是做错了。以下是我的思考过程:

    问题: -我需要大量的字段来保存这些数据 -所有这些领域都需要大量的样板文件

    解决方案:

    • 使用反射来减少样板<“您在这里”
    • 使用元数据指定应如何使用字段

    新问题:

    • 当有人看到代码时,很难理解反射。
    • 一旦您进行了足够的元处理以消除更多的样板文件,这些字段通常在代码中除了通过元数据之外没有提到——为什么它们是字段?
    • 在代码中指定元数据会很快变得庞大(顺便说一下,最简单的方法是字符串数组)

    解决方案:开始在集合中存储数据,并在外部数据文件中指定元数据

    新问题:错误变得难以发现

    仔细检查错误,并且非常清楚地显示错误消息。确保任何可能使用您的代码的其他程序员读取错误消息。尝试指出元数据何时丢失或错误,以及程序员应该如何更新metdata——包括元数据文件的位置。

    问题:无类型安全

    是的,有时候会有点烦人。我最终在元数据中包含了类型信息,这样,如果有人在字段中输入了错误的值,就可以检测到它——本质上,这会将类型安全性从构建时移动到运行时,在我的例子中这是很好的。

    问题:在对象的整个生命周期中重复需要元数据

    我不必每次使用它时都按名称查找它,而是首先解析元数据并将其放入对象中(称之为intholder)。这个持有者最终会出现在哈希表中,它将包含当前值以及对解析元数据的引用。

    例子

    以下是我的元数据在样式表的一个字段中的最终结果:

    FieldName:     Age
    FieldType      Integer
    ScreenBinding: AgeTextField
    DBBinding:     User.age
    Validation:    IntRange(0, 120); "Age is out of range"
    

    字段名可能是显示给用户的方式,也可能只是在程序中使用。一般来说,您不需要按名称直接操作这种类型的数据——当然,有时也需要这样做。

    当您确实需要使用时,请使用getint(“age”)和setint(“age”,12),而不是getage()和setage(12)——稍微详细一点,但不是真正的问题。

    如果这是一个问题,您可以使用getage/setage helper方法,并且您永远不需要知道它不是一个字段,但这确实会再次堆积在样板上。

    fieldtype:指定它的存储方式,并允许您实现类型检查。

    screenbinding和dbbinding用于将值复制到其他系统中或从其他系统中复制出来。我还使用这种机制将数据从服务器传输到客户机,然后再传输回来。

    有趣的是验证。当从屏幕上提取数据时,它可以通过非常程序化的方式传递给验证器。在提交到数据库之前,可以使用相同的验证器。

    验证器可以做的远不止这些,它们可以作为触发器(如果值改变了,就这样做)或操作(当用户提交屏幕时,就这样做)。这些是一个简单的对象,能够(通过一个接口)获取一个值——它们可以像您喜欢的那样灵活或强大,但是除了元数据之外,它们不直接绑定到任何对象。

    这种方法的唯一问题是您必须是喜欢编写fixture的程序员类型,而不是容易出错的样板文件。(是的,我发现时间量是相等的,但是当我必须实现样板文件时,我会变得非常缓慢)

    做了几次之后,我真的很喜欢这个模式,但是很难实现。下次我要做的时候,我会努力把它变成某种类型的图书馆。

        4
  •  1
  •   leonbloy    15 年前

    如果要在类的每个setter中设置“fresh”对象,通常可以通过获取 Method ,对于每个方法, Class 关于 getParameterTypes() ,对于您调用的每个类 Class.newInstance() …交叉你的手指(这应该打破原始类型-我怀疑爪哇做自动拳击在这里)。 你总是可以问一个参数是否是一个惩罚性的调用 主要的(

    为什么要为类的基元字段设置“空”实例?它们已经初始化。是否要“重置”它们?