具有动态字段的Java类

时间:2010-06-27 11:21:52

标签: java dynamic field

我正在寻找构建动态Java类的聪明方法,即可以在运行时添加/删除字段的类。使用场景:我有一个编辑器,用户应该能够在运行时向模型添加字段,甚至可以在运行时创建整个模型。

一些设计目标:

  • 如果可能的话,在没有强制转换的情况下输入类型安全的自定义代码适用于动态字段(该代码将来自以不可预见的方式扩展模型的插件)。
  • 性能良好(你能打败HashMap吗?也许在设置过程中使用数组并为字段分配索引?)
  • 字段“重用”(即如果您在多个地方使用相同类型的字段,则应该可以定义一次,然后重复使用它。)
  • 依赖于其他字段值的计算字段
  • 当字段更改值(不一定通过Beans API)时,应发送信号
  • “自动”父子关系(当您将子项添加到父项时,子项中的父指针应设置为“free”)。
  • 易于理解
  • 易于使用

请注意,这是一个“圈外思考”的问题。我将在下面发布一个例子让你心情愉快: - )

5 个答案:

答案 0 :(得分:2)

显而易见的答案是,如果您关心字段的顺序,请使用HashMap(或LinkedHashMap。然后,您可以通过get(String name)set(String name, Object value)方法添加动态字段。

此代码可以在公共基类中实现。由于只有少数方法,如果你需要扩展其他方法,使用委托也很简单。

为避免出现投射问题,您可以使用type-safe object map

    TypedMap map = new TypedMap();

    String expected = "Hallo";
    map.set( KEY1, expected );
    String value = map.get( KEY1 ); // Look Ma, no cast!
    assertEquals( expected, value );

    List<String> list = new ArrayList<String> ();
    map.set( KEY2, list );
    List<String> valueList = map.get( KEY2 ); // Even with generics
    assertEquals( list, valueList );

这里的技巧是包含类型信息的键:

TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );

表现还可以。

字段重用是通过使用相同的值类型或通过扩展具有附加功能的类型安全对象映射的键类来实现的。

计算字段可以使用第二个映射来实现,该映射存储进行计算的Future个实例。

由于所有操作仅在两种(或至少几种)方法中发生,因此发送信号很简单,可以按照您喜欢的方式进行。

要实现自动父/子处理,请在子节点的“set parent”信号上安装信号侦听器,然后将子节点添加到新父节点(如有必要,将其从旧父节点中删除)。

由于没有使用框架且不需要任何技巧,因此生成的代码应该非常干净且易于理解。不使用String作为键具有额外的好处,人们不会使用字符串文字乱丢代码。

答案 1 :(得分:2)

  

如果可能的话,在没有强制转换的情况下输入类型安全的自定义代码适用于动态字段(该代码将来自以不可预见的方式扩展模型的插件)

AFAIK,这是不可能的。如果使用静态类型,则只能在没有类型转换的情况下获得类型安全性。静态类型是指在编译时已知的方法签名(在类或接口中)。

您可以做的最好的事情是拥有一系列方法,如String getStringValue(String field)int getIntValue(String field)等等。当然,你只能为预定的一组类型做到这一点。任何类型不在该集合中的字段都需要进行类型转换。

答案 2 :(得分:1)

所以基本上你是在尝试创建一种具有更多动态属性的新型对象模型,有点像动态语言?

可能值得查看Rhino的源代码(即在Java中实现的Javascript),它面临着在Java中实现动态类型系统的类似挑战。

在我的头脑中,我怀疑你会发现内部HashMaps最终最适合你的目的。

我使用类似的HashMaps动态对象模型编写了一个小游戏(Tyrant - GPL source available),它运行良好,性能不是问题。我在get和set方法中使用了一些技巧来允许动态属性修饰符,我相信你可以做同样的事情来实现你的信号和父/子关系等。

[编辑]请参阅source of BaseObject如何实施。

答案 3 :(得分:1)

您可以使用字节码操作库。这种方法的缺点是你需要创建自己的类加载器来动态地加载类中的更改。

答案 4 :(得分:1)

我做的几乎一样,它是纯Java解决方案:

  1. 用户生成自己的模型,这些模型存储为JAXB模式。
  2. Schema在Java类中即时编译并存储在其中 用户坛
  3. 所有类都被迫扩展一个“root”类,您可以在其中放置所需的所有额外功能。
  4. 使用“模型更改”实现适当的类加载器 听众。
  5. 说到性能(在我的情况下这很重要),你几乎无法击败这个解决方案。可重用性与XML文档相同。