将 类 存储在一个 Map 中,以便它们可以被实例化

Store classes in a Map so that they can be instantiated

我希望能够基于 HashMap 个条目创建 classes 的实例。

例如这就是我想写下的内容:

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 名称与 classes 相关联。

用户可以使用 "name".

创建 class 的实例

我想尝试:将名称映射到 classes(我不知道如何在映射中存储 classes),然后从映射中获取项目匹配 "name" 然后实例化它。

那不行。


如何将 class 与 String 名称相关联并使用我提供的 'name' 实例化这些 class?

您可以使用 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();

如果您的构造函数需要参数,则需要分别使用另一个 functional interface. For one- and two-argument constructors, you can use Function and BiFunction。如果再这样,您将需要定义自己的功能接口。假设构造函数都接受一个字符串,你可以这样做:

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");

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

我强烈建议在 中使用 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);

注意:这里使用Java10.

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

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");
    }
}