具有动态字段的Java类

具有动态字段的Java类,java,dynamic,field,Java,Dynamic,Field,我正在寻找构建动态Java类的聪明方法,也就是可以在运行时添加/删除字段的类。使用场景:我有一个编辑器,用户应该能够在运行时向模型添加字段,或者甚至在运行时创建整个模型 一些设计目标: 如果可能,为在动态字段上工作的自定义代码键入safe而不强制转换(该代码将来自以不可预见的方式扩展模型的插件) 性能良好(您能否击败HashMap?在设置过程中可能会使用数组并为字段分配索引?) 字段“重用”(即,如果在多个位置使用同一类型的字段,应该可以定义一次,然后重用) 依赖于其他字段值的计算字段 字段更

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

一些设计目标:

  • 如果可能,为在动态字段上工作的自定义代码键入safe而不强制转换(该代码将来自以不可预见的方式扩展模型的插件)
  • 性能良好(您能否击败HashMap?在设置过程中可能会使用数组并为字段分配索引?)
  • 字段“重用”(即,如果在多个位置使用同一类型的字段,应该可以定义一次,然后重用)
  • 依赖于其他字段值的计算字段
  • 字段更改值时应发送信号(不一定通过Beans API)
  • “自动”父子关系(将子对象添加到父对象时,子对象中的父对象指针应设置为“自由”)
  • 易懂
  • 易于使用

请注意,这是一个“跳出圈子思考”的问题。我将在下面发布一个示例,让您了解情况:-)

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

此代码可以在公共基类中实现。因为只有几个方法,所以如果需要扩展其他内容,使用委托也很简单

为了避免铸造问题,您可以使用:

TypedMap map=newtypedmap();
字符串应为=“你好”;
map.set(键1,预期);
字符串值=map.get(KEY1);//看,妈妈,没有演员!
资产质量(预期、价值);
List=newarraylist();
映射集(键2,列表);
List valueList=map.get(键2);//即使是泛型
资产质量(清单、价值清单);
这里的技巧是包含类型信息的密钥:

TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );
TypedMapKey-KEY1=新的TypedMapKey(“KEY1”);
TypedMapKey键2=新的TypedMapKey(“键2”);
演出可以

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

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

由于所有操作都是通过两种(或至少几种)方法进行的,因此发送信号很简单,可以按照您喜欢的任何方式进行

要实现自动父/子处理,请在子级的“set parent”(设置父级)信号上安装一个信号侦听器,然后将子级添加到新的父级(必要时将其从旧的父级中删除)


由于没有使用任何框架,也不需要任何技巧,因此生成的代码应该非常干净且易于理解。不使用字符串作为键还有一个额外的好处,那就是人们不会在代码中乱扔字符串文字。

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

可能值得一看的源代码(例如,用Java实现的Javascript),它面临着用Java实现动态类型系统的类似挑战

在我脑海中,我怀疑您会发现内部哈希映射最终最适合您的目的

我编写了一个小游戏(),它使用了类似的动态对象模型,具有HashMaps特性,它工作得很好,性能也不是问题。我在get和set方法中使用了一些技巧来允许动态属性修饰符,我相信您可以做同样的事情来实现您的信号和父/子关系等

[编辑]查看如何实施

如果可能,为在动态字段上工作的自定义代码键入safe而不强制转换(该代码将来自以不可预见的方式扩展模型的插件)

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


您所能做的最好的事情就是拥有一个包含大量方法的接口,如
String getStringValue(String字段)
int getIntValue(String字段)
等等。当然,您只能对一组预先确定的类型执行此操作。任何类型不在该集中的字段都需要类型转换。

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

我也这样做,这是纯Java解决方案:

  • 用户生成自己的模型,这些模型存储为JAXB模式
  • 模式在Java类中动态编译并存储在 用户罐
  • 所有类都必须扩展一个“根”类,在这个类中,您可以放置所需的所有额外功能
  • 适当的类加载器通过“模型更改”实现 听众

  • 说到性能(这在我的例子中很重要),您很难击败这个解决方案。可重用性与XML文档相同。

    这是我的解决方案。我相信你可以做得更好!:-)我不明白。编译时不需要知道类型安全对象映射的类型吗?既然这种方法依赖于泛型,那么不存在隐藏的类型转换吗。。。如果使用“不安全”类型,则可能导致ClassCastException?1。如果密钥不是TypedMapKey的实例,则无法在映射中存储任何内容。2.如果值的类型与键的类型不匹配,则在调用
    set()
    时会出现编译错误。因此,
    get()
    的结果只能返回正确的类型(除非
    TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
    TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );