Java 如何将类的字符串表示形式转换为真正的对象?
我正在写一个需要命令对象的程序。一个命令包含一个字符串作为其名称,以及一个抽象操作,它表示该命令实际执行的操作。此外,命令还有一个方法init(),在程序层次结构的更高层使用,该方法实例化变量以供命令使用(提供对GUI、网络等的访问),还有一个方法execute(),在特殊线程上执行抽象操作。以下是创建和使用命令的示例:Java 如何将类的字符串表示形式转换为真正的对象?,java,string,object,Java,String,Object,我正在写一个需要命令对象的程序。一个命令包含一个字符串作为其名称,以及一个抽象操作,它表示该命令实际执行的操作。此外,命令还有一个方法init(),在程序层次结构的更高层使用,该方法实例化变量以供命令使用(提供对GUI、网络等的访问),还有一个方法execute(),在特殊线程上执行抽象操作。以下是创建和使用命令的示例: Command c = new Command("Test", new AbstractAction() { public void actionPerformed(
Command c = new Command("Test",
new AbstractAction() {
public void actionPerformed(ActionEvent a) {
System.out.println("Hello world!");
}
});
此时,调用“c.execute();”将按预期输出“Hello world!”
我的目标是拥有一个包含成对值的文本文件,可以对其进行解析以生成一个字符串名和一个AbstractAction。完成后,另一个类将遍历找到的名称和操作,为每个名称和操作创建命令对象,并将它们添加到程序中的命令列表中,然后可以在其中正常使用它们
现在,我的问题是我读入了一个表示上面私有AbstractAction主体的字符串,但是没有一种简单的方法将该字符串转换为实际的AbstractAction对象
一个可能的想法是使用AbstractAction字符串表示创建一个临时java文件,对其进行编译,从中创建一个新的AbstractAction,然后使用反射获取该引用,但这似乎有些过分。另一种方法是直接修改通过文件解析的文件源,这样就可以写出抽象操作的代码,但同样,这有点疯狂
我尝试过其他一些实现,包括强制用户创建命令的子类,将它们的源代码放入一个特殊的程序文件夹,然后在初始化时创建命令,但这最终对用户来说是一项艰巨的工作(大量冗余代码)
请让我知道是否有更好的方法来实现我想要做的事情,或者是否有更简单的方法将源字符串转换为如上所述的内部对象
编辑1:
下面是文本文件的示例:
//Anything outside of quotes is a comment
"Foo", "System.out.println("Hello world!");"
"Bar", "network.sendOverAFile(new File("test.txt"));"
从这里开始,解析器(在启动时)将读取整个文件,并将“Foo”提取为字符串名称,“System…;”提取为字符串操作。我需要将action转换为AbstractAction主体中的代码,如上面创建命令时所示。
酒吧也是如此;Bar使用init()传递的一个变量
至于我尝试的子类实现,用户必须创建自己的Command子类,并将其放入源文件夹中。子类的外观如下所示:
public class TestCommand extends Command {
public TestCommand() {
super("Test", new AbstractAction() {
public void actionPerformed(ActionEvent a) {
System.out.println("Hello!");
}
});
}
}
Foo importClass(java.lang.System); System.out.println('Hello world!');
Bar importClass(java.io.File); network.sendOverAFile(new File('test.txt'));
然后,它将被放入一个源目录,以及所有其他子类命令中,并进行编译。解析器将遍历已编译的代码段,并将相关信息添加到数组中。每次正常执行命令时,解析器都会扫描所有名称的列表,如果存在匹配项,则执行相关的抽象操作。这是可行的,但涉及到大量对外部类的引用(这可能会用几十个命令减慢程序的速度),而且对于制作插件的用户来说,这是工作量的两到三倍。因此,我觉得使用上面的文本文件技术会容易得多,但我不知道如何将代码的字符串表示形式转换为代码本身;因此,我的第一个问题。这听起来像是过度工程。您真的需要在运行时有这么大的灵活性吗,或者您只是有很多命令,并且希望在文件中以一种简单的方式引用它们 如果是后者,您的文本文件不需要包含代码;它只需要包含对应于该代码的符号标识符。这些标识符应作为枚举常量存在于代码中:
public enum Command { FOO, BAR }
public List<Action> parseActions(Path file)
throws IOException {
List<Action> actions = new ArrayList<>();
try (BufferedReader reader =
Files.newBufferedReader(file, Charset.defaultCharset())) {
String line;
while ((line = reader.readLine()) != null) {
Command command = Command.valueOf(line);
Action action = getAction(command);
actions.add(action);
}
}
return actions;
}
private Map<Command, Action> allActions;
private Action getAction(Command command) {
Objects.requireNonNull(command, "Command cannot be null");
if (allActions == null) {
allActions = new EnumMap<>(Command.class);
allActions.put(Command.FOO, new AbstractAction() {
public void actionPerformed(ActionEvent event) {
System.out.println("Hello world!");
}
};
allActions.put(Command.BAR, new AbstractAction() {
public void actionPerformed(ActionEvent event) {
network.sendOverAFile(new File("test.txt"));
}
};
// Safety check
if (!allActions.keySet().containsAll(
EnumSet.allOf(Command.class))) {
throw new RuntimeException(
"Not every Command constant has an associated Action");
}
}
return allActions.get(command);
}
您应该在代码中创建所有操作,并使用枚举常量作为键将这些操作放置在映射中。然后,您的文件可以引用这些枚举常量执行的操作:
public enum Command { FOO, BAR }
public List<Action> parseActions(Path file)
throws IOException {
List<Action> actions = new ArrayList<>();
try (BufferedReader reader =
Files.newBufferedReader(file, Charset.defaultCharset())) {
String line;
while ((line = reader.readLine()) != null) {
Command command = Command.valueOf(line);
Action action = getAction(command);
actions.add(action);
}
}
return actions;
}
private Map<Command, Action> allActions;
private Action getAction(Command command) {
Objects.requireNonNull(command, "Command cannot be null");
if (allActions == null) {
allActions = new EnumMap<>(Command.class);
allActions.put(Command.FOO, new AbstractAction() {
public void actionPerformed(ActionEvent event) {
System.out.println("Hello world!");
}
};
allActions.put(Command.BAR, new AbstractAction() {
public void actionPerformed(ActionEvent event) {
network.sendOverAFile(new File("test.txt"));
}
};
// Safety check
if (!allActions.keySet().containsAll(
EnumSet.allOf(Command.class))) {
throw new RuntimeException(
"Not every Command constant has an associated Action");
}
}
return allActions.get(command);
}
文件中的每一行都包含一个命令名,后跟JavaScript代码。所以它可能看起来像这样:
public class TestCommand extends Command {
public TestCommand() {
super("Test", new AbstractAction() {
public void actionPerformed(ActionEvent a) {
System.out.println("Hello!");
}
});
}
}
Foo importClass(java.lang.System); System.out.println('Hello world!');
Bar importClass(java.io.File); network.sendOverAFile(new File('test.txt'));
Foo importClass(java.lang.System);System.out.println('helloworld!');
Bar importClass(java.io.File);文件(新文件('test.txt');
在我看来,这样做的另一个主要缺点是,代码不会从编译器检查中受益,并且您当然不能从调试器中在代码中设置断点。总而言之,调试和维护将是一个相当头疼的问题。使用脚本语言进行实现?听起来你真的想要一个插件架构。i、 e.让您的用户子类化命令。它不应该有很多冗余代码。因此,也许可以发布您所做的。如果您在问题中包含一个或多个您希望包含在此文本文件中的可解析字符串的示例,这会有所帮助。添加了反映所需信息的编辑。