我正在寻找构建动态Java类的聪明方法,即可以在运行时添加/删除字段的类。使用场景:我有一个编辑器,用户应该能够在运行时向模型添加字段,甚至可以在运行时创建整个模型。
一些设计目标:
HashMap
吗?也许在设置过程中使用数组并为字段分配索引?)请注意,这是一个“圈外思考”的问题。我将在下面发布一个例子让你心情愉快: - )
答案 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解决方案:
说到性能(在我的情况下这很重要),你几乎无法击败这个解决方案。可重用性与XML文档相同。