我有几种情况,其中一个类由不同类型的任意(但固定)数量的变量组成,并且希望迭代这些变量以及在代码中使用它们的名称。有没有更聪明的方法来重新键入每个函数中的每个变量名称?
我最初的想法是使用HashMap来存储局部变量,但这似乎效率低下并且不能处理多种类型。
模拟下面的代码以缩短所需的读数,但通常是超过3个变量:
class Widget implements Parcelable {
String name, code;
Long price;
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(code);
dest.writeLong(price);
}
public Widget(Parcel o) {
name = o.name;
code = o.code;
price = o.price;
}
public String getXML() {
return "<Widget><name>"+name+"</name><code>"+code
+"</code><price>"+price+"</price></Widget>";
}
}
相反,我宁愿做类似(伪代码)的事情:
public Widget(Parcel o) {
for (Map<Name,Data> item: o.getMap()) {
this.setValue(Name, Data);
}
}
public String getXML() {
StringBuilder XML = new StringBuilder();
XML.append("<Widget>");
for (Map<Name,Data> item: o.getMap()) {
XML.append("<"+Name+">" + Data + "</"+Name+">");
}
XML.append("</Widget>");
return XML.toString();
}
我一直认为必须有一种模式来做这种事情,但也许只是我的Python历史在我的Java经历中蠢蠢欲动。
更新:这不仅仅是从成员变量中获取XML,而是在多个成员函数中循环遍历成员变量。看来我的保留节目中缺少Java的反射功能。
我新的小型构造函数让我很高兴能学到一些有用的东西,看起来像:
public Widget(Widget other) {
for (Field f : getClass().getDeclaredFields()) {
if (f.getName() == "TAG") {
continue;
}
f.set(this, f.get(other));
}
}
答案 0 :(得分:13)
通常用反射解决这个问题:
for (Field f : getClass().getDeclaredFields()) {
String name = f.getName();
String value = f.get(this);
}
但是,对于写入/读取XML,您可能希望使用JAXB而不是重新发明轮子。
答案 1 :(得分:3)
使用杰克逊:
https://github.com/FasterXML/jackson-dataformat-xml
序列化与JSON序列化非常相似:所有需要更改的是要使用的ObjectMapper实例:
// Important: create XmlMapper; it will use proper factories, workarounds
ObjectMapper xmlMapper = new XmlMapper();
String xml = xmlMapper.writeValue(new Simple());
和POJO一样:
public class Simple {
public int x = 1;
public int y = 2;
}
你会得到类似的东西:
<Simple>
<x>1</x>
<y>2</y>
</Simple>
(默认情况下输出不是缩进的:你可以使用标准的Jackson机制启用缩进)
从XML反序列化POJO 与序列化类似,反序列化与JSON反序列化没有太大区别:
ObjectMapper xmlMapper = new XmlMapper();
Simple value = xmlMapper
.readValue("<Simple><x>1</x><y>2</y></Simple>", Simple.class);
P.S。您也可以使用反射,并使用Class.getDeclaredFields()
通过所有声明的字段进行迭代。但根据我的经验,很少有人这样做。有很多第三方开源库用于不同的目的,通常它只是使用它们的更好的解决方案(例如杰克逊在这种特殊情况下)
答案 2 :(得分:2)
如果有许多类的代码遵循相同的模式,我会编写一个代码生成器来从某种定义文件生成Java源代码。然后你可以让你的生成器创建简单的代码,就像你的第一个例子一样,更容易阅读和理解(比使用通用的地图或反射或其他东西)。定义文件成为各种对象字段的“官方”来源。
由于您已经熟悉Python,因此您的定义文件可以直接构建到Python脚本中以创建源代码。例如:
Objects = {
"Widget": [
(TYPE_STRING, "name"),
(TYPE_STRING, "code"),
(TYPE_LONG, "price"),
],
# ...
}
使用TYPE_STRING
等的适当定义,编写一些从中生成Java源代码的代码应该很简单。
答案 3 :(得分:0)
我相信XStream是最简单的框架。参考Two minute tutorial,您将会有所了解。
就像创建一个映射类一样简单,例如Widget
具有所有成员属性和可能的对象嵌套,然后调用:
XStream xstream = new XStream(new DomDriver());
String xml = xstream.toXML(widgetObject); // <-- Get XML String from object
Widget widget = (Widget)xstream.fromXML(xml); //<-- Get object from XML