女士&们,
我是Java的新手,请原谅我,如果这很明显,但我还没发现很多。
我想在运行时为类创建动态属性(变量)(通过添加或更改属性和方法来定义可在运行时更改的对象)。
原因:我想在GAE中存储一个数据模型,可以在编译应用程序后动态扩展(是的,DataStore允许)。应该添加哪些属性也存储在DataStore中(就像使用机器人来构建机器人......有趣)。
Python允许我在运行时添加属性。 Groovy似乎也允许这样做。 “纯粹的”Java世界中唯一指向该方向的东西似乎是“动态代理”。
但是,如果他们能够做到这一点,我还无法弄清楚。
答案 0 :(得分:10)
Java无法动态添加属性。它也没有能力在运行时动态创建类或在运行时更改它们。 Java强烈且静态地键入。您可以做的最好的事情是将这些属性放入Map
或类似的。
编辑:好的,显然有些澄清是有道理的。 OP特别提到了GAE,这些方法的 none 将起作用,但我会提到它们,因为有些人似乎对他们的缺席不以为然。
Java Compiler API(Java 6+)允许您在运行时编译Java类。从技术上讲,你可以写出一个Java源文件来查看你想要的,编译它并加载它。
Java字节码库可以在运行时重写类。这被JPA(和其他)等库使用。你可以用这种方式修改类。
OP指的是a)参考GAE和b)更多按照Javascript如何允许您通过动态添加,删除或更改属性在运行时修改类或特定实例的顺序。 Java肯定不会这样做,特别是在GAE上没有。
以上内容对此不例外,就像在C ++中将类转换为char *
一样,因此您可以阅读私有成员并不意味着C ++没有私有成员。使用这两种方法实际上绕过了Java运行库,即使它们是Java的一部分。
答案 1 :(得分:2)
Java不支持它。最好的办法是在一些外部数据存储中存储/管理,您可以从Java代码中访问这些数据存储。作为基本内置示例,您可以使用在每个请求中加载的java.util.Properties
API,或者以定时间隔缓存和重新加载,或以编程方式重新加载。然后,您可以将键值对存储在.properties
文件中,该文件只放在类路径中。 Here is a Sun tutorial about the subject
属性文件可能看起来像
key1=value1 key2=value2 key3=value3
如果将它放在类路径中,则可以将其加载为
Properties properties = new Properties();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
properties.load(classLoader.getResourceAsStream("file.properties"));
String key1 = properties.getProperty("key1"); // value1
其他替代方法是例如XML文件(您可以使用任何Java XML API访问)或仅使用数据库(您可以使用JDBC API访问)。
答案 2 :(得分:2)
我不知道这是否是GAE上的一个选项(我没有检查限制)以及这是否符合您的需求但是可以查看来自CGLIB的BeanGenerator
类(替代来自DynaBean
的丑陋的BeanUtils)。引用"Death to DynaBeans"(看一下帖子):
没有人让我的CGLIB金锤 去浪费,我已经检查过了 在BeanGenerator类中进入CVS。您 像这样使用它:
BeanGenerator bg = new BeanGenerator(); bg.addProperty("foo", Double.TYPE); bg.addProperty("bar", String.class); Object bean = bg.create();
生成的类是真实的 JavaBean,这意味着你可以使用 标准bean实用程序。这包括 所有的课程
net.sf.cglib.beans
包 (BeanCopier
,BeanMap
和BulkBean
)。 尽你所能结束暴政 DynaBeans!
答案 3 :(得分:1)
可以使用动态代理。也可以在GAE上执行此操作。
首先创建类“SomeObject”,公开获取和设置属性值的方法(即getProperty(name)和setProperty(name,value))。
然后,创建一个接口“PropertyModel”,其中包含您希望生成的对象具有的方法。
调用TransparentProxy.newInstance(someObjectInstance,MyPropertyModel.class)来创建动态代理。
Java将使用指定的接口扩展您的对象someObjectInstance(顺便说一下,您可以指定多个)。当您在代理对象上调用方法时,方法调用将被重定向到下面定义的“invoke(...)”方法,您需要修改该代码以处理getter和setter并包含一些异常处理等但总的来说,这就是动态代理在Java中工作的方式。
public class TransparentProxy implements InvocationHandler
{
private final SomeObject someObject;
private TransparentProxy(SomeObject someObject)
{
this.someObject = someObject;
}
public static Object newInstance(SomeObject someObject,
Class<? extends PropertyModel> propertyModel)
{
return Proxy.newProxyInstance(someObject.getClass().getClassLoader(),
new Class[] { propertyModel }, new TransparentProxy(someObject));
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
return this.someObject.getProperty(method.getName());
}
}
答案 4 :(得分:1)
可以使用DynaClass库来动态创建JavaBeans
Map<Object, Object> properties = new HashMap<Object, Object>();
roperties.put("title", "The Italian Job");
roperties.put("dateOfRelease", "new GregorianCalendar(1969, 0, 1).getTime()");
Object movieBean = BeanCreator.createBeanFromMap(properties);