我有一个包含有字符串类型的数据的列表- > ["classField1", "classField2", "classField3"]
我有一个方法( myMethod(List list, String className)
接受的参数列表。 所以,我可以通过参数传递名单,以myMethod的(名单列表,弦乐的className)。
在myMethod
,我想创建一个对象,那将是一个className的情况下,这是第二个参数。 从那以后,我想通过列表的数据来设置类的字段。 由于我要来获得类的动态领域的事实,上述的结果是,我要投列表中的每个字符串值,对类的每个字段的类型。
我相信里面的列表中字符串的顺序,是按照正确的顺序,以及对应于具有相同的顺序类的字段。
没有任何人有任何想法如何执行上述?
例:
["StringtempValue", "StringUnitOfMeasurement"]
=>
创建实例对象:
public class TempStruct {
private double tempValue;
private String unitOfMeasurement;
public TempStruct(double tempValue, String unitOfMeasurement) {
this.tempValue = tempValue;
this.unitOfMeasurement = unitOfMeasurement;
}
}
我试着给用以下方式解决:
其实我想创建一个现有类的一个对象,我想这样做与反思。 我使用下面的代码:
Class<?> cls = Class.forName(name);
Object clsInstance = (Object) cls.newInstance();
Field[] objectFields = clsInstance.getClass().getDeclaredFields();
但我得到一个例外,2号线,当它试图创建新对象。 正如@JB Nijet说我不知道该方法getDeclaredFields()不返回排序字段。
其实,我只接受字符串列表,所以通过使用反射我将对象转换为字符串列表的方法,之后,我想要做的正好相反。 我不认为任何其他方式来做到这一点。
对象的动态实例可以得到相当复杂,您的方案触及几个方面:
- 转换来自对象的值
String
为适当的类型 - 从类名加载正确的类和创建一个实例
- 这些值分配到对象
的每个点的充分讨论会占用一整章在无疑问铆处理Java作为一种动态的语言。 但是,假设你没有学习这些复杂性,或采取一些巨大的第三方库的依赖的时候,让我们掀起的东西,让你对你的方式。 请在任何时候都保持你的手在车内的乘坐是会得到坎坷。
让我们先解决类型转换的问题。 该值设置为Strings
,但你的对象将它们存储为double
, long
, int
等,所以我们需要解析函数String
到适当的目标类型:
static Object convert(Class<?> target, String s) {
if (target == Object.class || target == String.class || s == null) {
return s;
}
if (target == Character.class || target == char.class) {
return s.charAt(0);
}
if (target == Byte.class || target == byte.class) {
return Byte.parseByte(s);
}
if (target == Short.class || target == short.class) {
return Short.parseShort(s);
}
if (target == Integer.class || target == int.class) {
return Integer.parseInt(s);
}
if (target == Long.class || target == long.class) {
return Long.parseLong(s);
}
if (target == Float.class || target == float.class) {
return Float.parseFloat(s);
}
if (target == Double.class || target == double.class) {
return Double.parseDouble(s);
}
if (target == Boolean.class || target == boolean.class) {
return Boolean.parseBoolean(s);
}
throw new IllegalArgumentException("Don't know how to convert to " + target);
}
啊。 这是丑陋,只处理固有类型。 但是,我们不是在寻找完美这里,对不对? 所以,请加强适当的。 注意从转换String
到一些其他类型实际上是反序列化的一种形式,所以你将制约你的客户(不管是谁给你的Strings
),以提供特定格式的值。 在这种情况下,格式由的行为定义parse
方法。 练习1:在未来的某个时刻,在向后兼容的方式招致别人的愤怒更改格式。
现在,让我们做实际的实例:
static Object instantiate(List<String> args, String className) throws Exception {
// Load the class.
Class<?> clazz = Class.forName(className);
// Search for an "appropriate" constructor.
for (Constructor<?> ctor : clazz.getConstructors()) {
Class<?>[] paramTypes = ctor.getParameterTypes();
// If the arity matches, let's use it.
if (args.size() == paramTypes.length) {
// Convert the String arguments into the parameters' types.
Object[] convertedArgs = new Object[args.size()];
for (int i = 0; i < convertedArgs.length; i++) {
convertedArgs[i] = convert(paramTypes[i], args.get(i));
}
// Instantiate the object with the converted arguments.
return ctor.newInstance(convertedArgs);
}
}
throw new IllegalArgumentException("Don't know how to instantiate " + className);
}
我们采取了很多快捷键的位置,但嘿,这不是我们所创造的西斯廷教堂。 只需加载类和搜索构造函数的参数,其数量的参数的数量相匹配(即元数)。 重载相同元数的构造函数? 不,不是要去工作。 可变参数? 不,不是要去工作。 非公共构造函数? 不,不是要去工作。 如果你不能保证你的类提供一个构造函数,将所有的领域,如你的例子TempStruct
的话,那么我就收工和抢啤酒,因为这种做法是DOA。
一旦我们找到构造,环比String
参数传递给它们转换成由构造所期望的类型。 假设作品,我们再通过反射调用构造函数,挥动魔杖,说胡言乱语。 瞧:你有一个新的对象。
让我们尝试将其与一个非常牵强的例子:
public static void main(String[] args) throws Exception {
TempStruct ts =
(TempStruct)instantiate(
Arrays.asList("373.15", "Kelvin"),
TempStruct.class.getName());
System.out.println(
ts.getClass().getSimpleName() + " " +
ts.tempValue + " " +
ts.unitOfMeasurement);
}
输出:
TempStruct 373.15 Kelvin
辉煌
我曾经有过同样的问题和一个HashMap竟然是我的解决方案。
检查出来: http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html
看看在http://commons.apache.org/beanutils/包。 它允许通过名称访问字段。
文章来源: Dynamically create an object in java from a class name and set class fields by using a List with data