【问题标题】:How to make a reference to a class using a string of the same name如何使用同名字符串引用类
【发布时间】:2013-05-01 22:30:08
【问题描述】:

假设我有两个实现接口 A 的类 Foo 和 Bar。我想要创建一个 Foo 或 Bar 的 ArrayList。在命令行参数中,用户必须输入 Foo 或 Bar 来说明他们试图创建 ArrayList 的对象。

所以:

public static void main(String [] args){
    String type = args[0];
    ArrayList<type> list = new ArrayList<type>();
    }

我如何从字符串类型转到对类 Foo 或 Bar 的引用,所以它正在做

ArrayList<Foo> list = new ArrayList<Foo>();
or
ArrayList<Bar> list = new ArrayList<Bar>();

这样我可以做到以下几点:

for(int i = 0 ; i < list.size() ; i++){
    list(i).doSomething();
    //doSomething is a function in interface A that Foo and Bar are required to implement
}    

明确地说,我不想要类似的东西

if (type.equals("Foo")) list = ArrayList<Foo>();

我希望能够使用任何与类型同名的有效类创建一个 ArrayList。

【问题讨论】:

  • Class.forName("mypackage.MyClass").

标签: java string class reference arraylist


【解决方案1】:

编译器需要知道类型,听起来您想将类型视为运行时变量而不是编译时事实。

查看Get generic type of class at runtime。它本质上问的是同样的事情,您将获得有关使用反射的可能解决方案的良好信息。

【讨论】:

    【解决方案2】:

    这在 Java 中是不可能的。您可以使用反射检索类型名称,但无法动态创建泛型类型。

    原因是泛型类型仅在编译时存在,编译器使用它来强制执行静态类型安全。在运行时,通用信息被丢弃,因此(在当前的 Java 哲学中)做你所要求的甚至没有意义。在运行时,泛型类型已转换为 Object,编译器在必要时会替换类型安全类型转换。

    【讨论】:

      【解决方案3】:

      使用Class.forName(String classNameWithPath) 方法 - 它会做你想做的事。

      这里有一个例子 - What is the difference between "Class.forName()" and "Class.forName().newInstance()"?

      【讨论】:

        【解决方案4】:

        将数组列表声明为ArrayList&lt;A&gt;。这样它就可以同时存储 Foo 和 Bar 对象,因为它们都实现了接口 A。

        【讨论】:

        • 我意识到我可以做到这一点,但我希望能够为任何类做到这一点,不管它实现了什么。我提供了更多关于我为什么要这样做的背景信息。不过,谢谢。
        【解决方案5】:

        您可以维护实现该接口的所有可能类型的列表,然后迭代它们的类型,直到找到与输入字符串匹配的类型。除此之外,我认为你在 Java 中会遇到麻烦。

        【讨论】:

          【解决方案6】:
          public class ForNameTest {
          public static void main(String[] argv) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
              java.util.ArrayList<String> arrayList = null;
              try {
                  Class<?> createdClass = Class.forName("java.util.ArrayList<java.lang.String>");
                  arrayList = (java.util.ArrayList<String>) (createdClass.newInstance());
                  arrayList.add("ABC");
                  System.out.println("First case " + arrayList.toString());
              }
              catch (ClassNotFoundException e) {
                  System.out.println("Exception in first case: " + e.toString());
              }
              try {
                  Class<?> createdClass = Class.forName("java.util.ArrayList");
                  arrayList = (java.util.ArrayList<String>) (createdClass.newInstance());
                  arrayList.add("ABC");
                  System.out.println("Second case " + arrayList.toString());
              }
              catch (ClassNotFoundException e) {
                  System.out.println("Exception in second case: " + e.toString());
              }
          }
          }
          

          输出:

          C:\JavaTools>javac ForNameTest.java
          Note: ForNameTest.java uses unchecked or unsafe operations.
          Note: Recompile with -Xlint:unchecked for details.
          
          C:\JavaTools>java ForNameTest
          Exception in first case: java.lang.ClassNotFoundException: java.util.ArrayList<java.lang.S
          tring>
          Second case [ABC]
          

          (不确定这证明了什么——你仍然不能将你的 ArrayList 声明为变量(vs &lt;?&gt;)类型。但它就是这样,FWIW。)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多