情景:
如何根据用户输入的字符串创建ListLayout对象?我需要等同于这样做:
CustomLayout layout = new ListLayout();
理想情况下,我需要找到一个解决方案,它允许我检查输入的String是否对应于在实际创建对象之前实现CustomLayout的预定义类(因为如果它不存在则会抛出错误而且我不会事先检查。
这真让我思考......先谢谢你的帮助
答案 0 :(得分:7)
如果你不想在这里使用反射,工厂地图可能是正确的:
interface LayoutFactory {
public CustomLayout makeLayout();
}
Map<String, LayoutFactory> factories = new HashMap<String, LayoutFactory>();
factories.put("GridLayout", new LayoutFactory() {
public CustomLayout makeLayout() { return new GridLayout(); }
});
factories.put("ListLayout", new LayoutFactory() {
public CustomLayout makeLayout() { return new ListLayout(); }
});
String layoutName = ...; // user input
CustomLayout l = factories.get(layoutName).makeLayout();
当然,您还应该处理用户确实提供未知布局名称的情况(factories.get然后返回null
)。
答案 1 :(得分:2)
如果您有一个具有完全限定名称的String,那么这是用于获取类实例的代码:
try {
CustomLayout layout = (CustomLayout) Class.forName("your.package.ListLayout").newInstance();
} catch (Exception ex) {
}
例外情况可以是:LinkageError
,ExceptionInInitializerError
,ClassNotFoundException
,IllegalAccessException
,InstantiationException
和SecurityException
,建议使用如果你想以不同的方式处理它们,你可以拥有每个条款的条款。
答案 2 :(得分:2)
做这样的事情:
String userInput = //get user's input
while(!userInput.equalsIgnoreCase("ListLayout") && !userInput.equalsIgnoreCase("gridLayout")){
System.out.println("Please enter a valid option");
userInput = //get user's input again
}
CustomLayout layout;
if(userInput.equalsIgnoreCase("ListLayout")
layout = new ListLayout();
else
layout = new GridLayout();
答案 3 :(得分:2)
我个人不建议使用反射;因为重构变成了痛苦。
最好是进行字符串检查并实例化正确的类。
例如
if(userInput.equals("ListLayout")) {
CustomLayout layout = new ListLayout();
} else if (userInput.equals("GridLayout")) {
CustomLayout layout = new GridLayout();
}
这也可以像其他人指出的那样使用java反射来实现。但是如果你想稍后重构代码(例如使用eclipse重构),那么反射代码将不会被自动重构。例如,如果您使用了反射,并且如果您将ListLayout的类名更改为FancyListLayout,并执行eclipse自动重构,则反射代码将保持不变,您的代码将会中断。
答案 4 :(得分:1)
两个步骤:
Class.forName(String)
答案 5 :(得分:1)
确定。你应该研究的是反射(wiki on reflection),java提供了丰富的API。这基本上允许您从String生成对象并捕获execption,如果没有相应的类。这有一些缺点,请查看the API以获取进一步的参考。
干杯!
答案 6 :(得分:1)
反射是很自然的答案,但你可以为它创建一个工厂。
public class CustomLayoutFactory {
public CustomLayout createInstance(String layoutName) {
if("ListLayout".equals(layoutName) {
return new ListLayout();
} else if("GridLayout".equals(layoutName) {
return new GridLayout();
}
return null;
}
}
虽然不是最优雅的解决方案,但在SecurityManager
对反射过于严格的情况下,它非常有用。
答案 7 :(得分:1)
阅读所有我想强烈推荐的反对基于反思的答案,因为之后你必须非常小心地重命名你的课程。
而不是:
if ("ListLayout".equals(userInput)) {
return new ListLayout();
}
您可以在基础Layout
类中添加受保护字段:
public abstract class Layout {
protected String userInputName;
}
并修改其扩展程序如下:
public class ListLayout {
public ListLayout() {
userInputName = "listLayout"; // set protected field
}
}
然后你可以这样做:
for (Layout l : setOfAllLayouts) {
if (userInput.equals(l.getInputName)) {
return l.clone();
}
}
答案 8 :(得分:0)
应该这样做:
Class.forName(userInput).newInstance();
然后,您可以使用instanceof
来测试您最终选择的课程。但是,在执行此操作之前,我会测试userInput
的值,以确保它是一个可识别的类名。如果用户只输入简单的类名,您可能还需要预先添加包名称。