【问题标题】:Using a string to instantiate a class使用字符串实例化一个类
【发布时间】:2018-01-23 15:23:08
【问题描述】:

假设我有 Circle、Rectangle 和 Triangle 类。

根据来自数据文件的输入,我想创建适当的对象。比如shapes.dat的第一行是C.5 0 0,我将创建一个半径为5的Circle对象。如果下一行是R.5 3 0,我将创建一个长5宽3的Rectangle对象。

我知道我可以使用基本的 if-else 逻辑,但我想知道是否有办法使用字符串作为实例化新对象的方法。有点像 Python 中的 exec() 方法。这是描述我想要的代码sn-p:

    Scanner file = new Scanner (new File("shapes.dat"));
    String s;       

    Map<Character,String> dict = new HashMap<Character,String>();
    dict.put('C', "Circle");
    dict.put('R', "Rectangle");
    dict.put('T', "Triangle");

    while (file.hasNextLine())
    {
        s = file.nextLine().trim();

        String name = dict.get(s.toCharArray()[0]);
        String data = s.split(".")[1];
        String code = name + " x = new " + name + "(data);";

        SYS.exec(code); //???

        ...

    }

【问题讨论】:

  • 你想在运行时创建一个实例?
  • @Ravi 是的,没错。
  • 您可以尝试为每种形状创建类
  • 在不使用else-if/switch 的情况下创建一个新实例是有风险的并且容易出现错误,但如果你必须这样做,this 可能会有所帮助。

标签: java string literals


【解决方案1】:

我不确定我是否理解正确,似乎很奇怪没有其他人提到这一点:

Map<Character, ShapeFactory> dict = new HashMap<>();
dict.put('C', new CircleFactory());
dict.put('R', new RectangleFactory());
dict.put('T', new TriangleFactory());

...

ShapeFactory factory = dict.get(symbol);
Shape shape = factory.create(data);

【讨论】:

  • 与您的想法相同,但我花时间解释了为什么要避免其他替代方案。我可能不会这样做:)
【解决方案2】:

您可以利用反射来动态创建实例。

String className = "com.shape.Triangle";
Class classDefinition = Class.forName(className);
Object obj = classDefinition.newInstance();

或者

只需使用if-else 来创建特定类的实例。

【讨论】:

  • 您命名 Triangle 类的方式是任意的吗?为什么选择“com.shape.Triangle”而不是“Triangle”?
  • @TiwaAina 只是让你知道,如果它驻留在某个包中,那么你应该使用完整的类名。
  • @TiwaAina 阅读 JavaDoc 对Class#forName 的评价。
  • @CardinalSystem 哦,我明白了,我们需要类的完全限定名。
【解决方案3】:

Exec 在 Python 中执行代码。
您可以使用 Java 执行相同的操作,例如使用 javassist。
您可以读取数据文件,编译语句并将它们插入到您自己的类中。
但这似乎有点过头了。

您也可以使用 java 反射,但它会产生脆弱且不清楚的代码。

而不是if else if, 我认为你应该使用抽象并按对象类型创建工厂类。

它可能看起来像:

Scanner file = new Scanner (new File("shapes.dat"));
String s;       

Map<Character, ShapeBuilder> dict = new HashMap<Character,String>();
dict.put('C', new CircleBuilder());
dict.put('R', new RectangleBuilder());
dict.put('T', new TriangleBuilder());

while (file.hasNextLine()){
    s = file.nextLine().trim();
    char shapeSymbol = ...; // computed from s
    ShapeBuilder builder = dict.get(shapeSymbol);
    Shape shape = builder.build(s);
}

【讨论】:

    【解决方案4】:

    您实际上可以使用多态性来避免 if-else 语句。因此,您可以创建实际完成这两项工作的对象,匹配一条线并创建一个形状。所以你可以使用类似下面的代码。

    public class Program {
    
        public static void main() throws FileNotFoundException {
            Scanner file = new Scanner(new File("shapes.dat"));
    
            while (file.hasNextLine()) {
                String line = file.nextLine().trim();
                Shape shape = new Matches(
                    new RectangleMatch(),
                    new TriangleMatch(),
                    new SquareMatch(),
                    new CircleMatch()
                ).map(line);
            }
        }
    
    
        public interface ShapeMatch {
            boolean matches(String line);
    
            Shape shape(String line);
        }
    
    
        public static final class RectangleMatch implements ShapeMatch {
            @Override
            public boolean matches(String line) {
                return line.startsWith("R");
            }
    
            @Override
            public Shape shape(String line) {
                String[] dimensions = line.substring(2).split(" ");
                return new Rectangle(
                    Integer.parseInt(dimensions[0]),
                    Integer.parseInt(dimensions[1]),
                    Integer.parseInt(dimensions[2])
                );
            }
        }
    
    
        public static final class CircleMatch implements ShapeMatch {
            @Override
            public boolean matches(String line) {
                return line.startsWith("C");
            }
    
            @Override
            public Shape shape(String line) {
                return new Circle(Integer.parseInt(line.substring(2, line.indexOf(" "))));
            }
        }
    
    
        public interface ShapeMapping {
            Shape map(String line);
        }
    
        public static final class Matches implements ShapeMapping {
            private final Iterable<ShapeMatch> matches;
    
            public Matches(ShapeMatch... matches) {
                this(Arrays.asList(matches));
            }
    
            public Matches(Iterable<ShapeMatch> matches) {
                this.matches = matches;
            }
    
            @Override
            public Shape map(String line) {
                for (ShapeMatch match : matches) {
                    if (match.matches(line)) {
                        return match.shape(line);
                    }
                }
    
                throw new RuntimeException("Invalid shape entry line.");
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-12-23
      • 1970-01-01
      • 2020-12-15
      • 2010-10-07
      • 1970-01-01
      • 2011-10-19
      • 1970-01-01
      • 2018-08-09
      相关资源
      最近更新 更多