0

假设我有两个实现接口 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。

4

6 回答 6

1

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

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

于 2013-05-01T22:38:41.700 回答
1

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

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

于 2013-05-01T23:36:21.933 回答
0

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

于 2013-05-01T23:55:06.157 回答
0
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 <?>)类型。但它就是这样,FWIW。)

于 2013-05-02T00:15:09.580 回答
0

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

这里有一个例子—— “Class.forName()”和“Class.forName().newInstance()”有什么区别?

于 2013-05-01T22:32:39.143 回答
0

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

于 2013-05-01T22:32:45.610 回答