获取String并从String中表示的类中创建对象

时间:2011-06-07 15:43:35

标签: java string class object instantiation

情景:

  • 我有两个名为ListLayout和GridLayout的类,它们都实现了CustomLayout。
  • 用户输入表示他们希望使用的布局的String(例如“ListLayout”)

如何根据用户输入的字符串创建ListLayout对象?我需要等同于这样做:

CustomLayout layout = new ListLayout();

理想情况下,我需要找到一个解决方案,它允许我检查输入的String是否对应于在实际创建对象之前实现CustomLayout的预定义类(因为如果它不存在则会抛出错误而且我不会事先检查。

这真让我思考......先谢谢你的帮助

9 个答案:

答案 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) {

}

例外情况可以是:LinkageErrorExceptionInInitializerErrorClassNotFoundExceptionIllegalAccessExceptionInstantiationExceptionSecurityException,建议使用如果你想以不同的方式处理它们,你可以拥有每个条款的条款。

答案 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)

两个步骤:

  1. 查找用户输入的文本是否与现有课程相对应(我可以使用reflections framework完成此操作)
  2. 实现该类的对象,通常使用Class.forName(String)
  3. 完成

答案 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的值,以确保它是一个可识别的类名。如果用户只输入简单的类名,您可能还需要预先添加包名称。