3

我希望能够根据HashMap条目创建类的实例。

例如,这就是我会尝试从头顶写下的内容:

public class One implements Interface {
  public void sayName() {
    System.out.println("One");
  }
}

public class Two implements Interface {
  public void sayName() {
    System.out.println("Two");
  }
}

Map<String, Interface> associations = new HashMap<String, Interface>();

associations.put("first", One);
associations.put("second", Two);

Interface instance = new associations.get("first")();

instance.sayName(); // outputs "One"

但我强烈怀疑这在 Java 中不起作用。


我的情况:我想创建一种将String名称与类关联的方法。

用户可以通过使用其“名称”来创建类的实例。

我想尝试:制作名称到类的映射(我不知道如何在映射中存储类),并从映射中获取与“名称”匹配的项目,然后实例化它。

那是行不通的。


如何将类与String名称相关联并使用我给它的“名称”实例化这些类?

4

3 回答 3

7

您可以使用Supplier函数式接口和对默认构造函数的方法引用:

Map<String, Supplier<Interface>> associations = new HashMap<>();

associations.put("first", One::new);
associations.put("second", Two::new);

要实例化一个新对象,请调用Supplier.get

Interface foo = associations.get("first").get();

如果您的构造函数需要参数,您将需要使用另一个函数式接口。对于一个和两个参数的构造函数,您可以分别使用FunctionBiFunction。再多的话,您将需要定义自己的功能接口。假设构造函数都接受一个字符串,你可以这样做:

class One implements Interface
{
    One(String foo){ }

    public void sayName() {
        System.out.println("One");
    }
}

Map<String, Function<String, Interface>> associations = new HashMap<>();
associations.put("first", One::new);

然后用于Function.apply获取实例:

Interface a = associations.get("first").apply("some string");

如果您的构造函数采用不同数量的参数,那么您就不走运了。

于 2018-04-06T16:29:55.090 回答
3

我强烈推荐Supplier迈克尔的回答中使用。或者,您应该能够使用以下内容:

var associations = Map.of("first", One.class, "second", Two.class);

var foo = associations.get("first").getConstructor().newInstance();

如果您的构造函数需要参数,只需将类传递给getConstructor并将值传递给newInstance. 例如,如果在其构造函数中Two接受一个:int

var foo = associations.get("two").getConstructor(int.class).newInstance(5);

注意:这使用 Java 10。

于 2018-04-06T16:31:54.803 回答
0

您是要存储类并按需创建新实例,还是要存储实例并仅使用它们?

public class ClassInHashMap {
    public static void main(String[] args) {
    Map<String,Class<? extends SomeInterface>> associations = new HashMap<String,Class<? extends SomeInterface>>();
        associations.put("first", One.class);
        associations.put("second", Two.class);

        try {
            Class<? extends SomeInterface> someCls = associations.get("first");
            SomeInterface instance = someCls.getDeclaredConstructor().newInstance();
            instance.sayName(); // outputs "One"
        }
        catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        catch (SecurityException e) {
            e.printStackTrace();
        }
        catch (InstantiationException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

interface SomeInterface {
    public void sayName();
}

class One implements SomeInterface {
    public void sayName() {
        System.out.println("One");
    }
}

class Two implements SomeInterface {
    public void sayName() {
        System.out.println("Two");
    }
}
于 2018-04-06T16:44:33.930 回答