我有一个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);
}
但是有没有另一种方法来实现我在最后一行尝试做的事情,即使用命名的String变量来引用对象的字段?换句话说,我想这样做:objectInstance.stringVariable
(其中stringVariable匹配objectInstance字段的名称。
答案 0 :(得分:3)
你正在寻找反思。这个主题上有一个Java tutorial可以帮助您入门,然后有很多很多库可以让反思变得更容易,例如Commons BeanUtils和Spring's util package中的几个类。几乎任何框架都会有一些反射辅助类,因为直接使用反射它会非常混乱。
作为您案例的简单示例,使用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();
}
}