我有一个Book对象,它有几个不同的String字段(标题、作者、主题…),我正在设计一个GUI来显示图书集合的每个字段。我有一个面板,我希望每个字段都有一个标签(命名字段),一个TextField(显示存储在字段中的值)和一个编辑按钮,使TextField可编辑,并显示第二个按钮来保存所做的任何编辑。
我想创建一个带有单个标签、TextField和按钮的"字段面板",而不是将每个字段单独编码到面板中。然后,我想使用foreach循环为每个字段(存储在列表中)创建这些面板之一,并将这些面板加载到主面板中。
我知道以下是不可能的:
Book b = new Book();
String[] fieldTitles = {title, author, subject, publisher};
for (String str : fieldTitles) {
FieldPanel fp = new FieldPanel();
fp.namelabel.settext(str);
fp.textField.settext(b.str);
}
但是是否有另一种方法来实现我在最后一行试图做的事情,即使用命名字符串变量来引用对象的字段?换句话说,我想做:objectInstance.stringVariable
(其中stringVariable匹配objectInstance的字段名称)
你在寻找反思。有一个关于这个主题的Java教程可以让你入门,还有很多很多的库可以让反射变得更容易,比如Commons BeanUtils和Spring的util包中的几个类。几乎所有的框架都会有一些反射辅助类,因为直接使用反射是很麻烦的。
作为您的案例的一个快速示例,使用Commons BeanUtils.getProperty(),您可以说:
fp.textField.settext((String) BeanUtils.getProperty(b, str));
这里有一个完整的示例,这样你就可以看到它是如何适合的:
import java.lang.reflect.Field;
public class BasicReflectionGettingFieldValues {
public static void main(String[] args) {
FieldPanel fp = new FieldPanel();
Book b = new Book("Mostly Harmless", "Douglas Adams");
for (String str : Arrays.asList("author", "title")) {
fp.namelabel.settext(str);
fp.textField.settext(getField(b, str));
}
}
private static String getField(Book b, String str) {
try {
Field field = Book.class.getDeclaredField(str);
field.setAccessible(true);
return (String) field.get(b);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("Bad field name: " + str, e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to access field " + str + " after making it accessible", e);
}
}
static class Book {
private String title;
private String author;
Book(String title, String author) {
this.title = title;
this.author = author;
}
}
static class TextField {
void settext(String s) {
System.out.println("Setting text field to '" + s + "'");
}
}
static class NameLabel {
void settext(String s) {
System.out.println("Setting name label to '" + s + "'");
}
}
static class FieldPanel {
private NameLabel namelabel = new NameLabel();
private TextField textField = new TextField();
}
}