简体   繁体   English

如何使用相同名称的字符串引用类

[英]How to make a reference to a class using a string of the same name

Say I have two classes Foo and Bar which implement interface A. I either want to make an ArrayList of Foo or Bar. 假设我有两个实现接口A的类Foo和Bar。我想要创建一个Foo或Bar的ArrayList。 In the command line arguments, the user must input either Foo or Bar as to which object they are trying to make an ArrayList of. 在命令行参数中,用户必须输入Foo或Bar,以确定他们尝试创建ArrayList的对象。

So: 所以:

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

How do I go from the string type to a reference to the class Foo or Bar so it's doing 如何从字符串类型转到类Foo或Bar的引用,以便它正在执行

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

This way I can do the following: 这样我可以做到以下几点:

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
}    

To be clear, I don't want something like 要清楚,我不想要类似的东西

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

I want to be able to make an ArrayList with any valid class with the same name as type. 我希望能够使用与类型相同的任何有效类创建一个ArrayList。

The compiler will need to know the type, and it sounds like you want to treat the type as a runtime variable instead of a compile-time fact. 编译器需要知道类型,听起来你想将类型视为运行时变量而不是编译时事实。

Check out Get generic type of class at runtime . 检查在运行时获取泛型类 It essentially asks the same thing and you'll get good information about a possible workaround solution using reflection. 它本质上要求相同的东西,你将获得有关使用反射的可能的解决方案解决方案的良好信息。

This is not possible in Java. 这在Java中是不可能的。 You can, using reflection, retrieve a type name, but there's no way to create a generic type dynamically. 您可以使用反射检索类型名称,但无法动态创建泛型类型。

The reason is that generic types exist at compile time only and are used by the compiler to enforce static type safety. 原因是泛型类型仅在编译时存在,并且编译器使用它来强制执行静态类型安全性。 At runtime, the generic information is discarded, so it's not even meaningful (in the current Java philosophy) to do what you are asking. 在运行时,通用信息被丢弃,因此在您所要求的内容中(在当前的Java哲学中)甚至没有意义。 At runtime, generic types have been converted to Object , with the compiler having substituted type-safe casts where necessary. 在运行时,泛型类型已转换为Object ,编译器在必要时具有替换的类型安全转换。

Use Class.forName(String classNameWithPath) method - it will do what you want. 使用Class.forName(String classNameWithPath)方法 - 它会做你想要的。

There is an example over here - What is the difference between "Class.forName()" and "Class.forName().newInstance()"? 这里有一个例子 - “Class.forName()”和“Class.forName()。newInstance()”之间有什么区别?

Declare the array list as an ArrayList<A> . 将数组列表声明为ArrayList<A> That way it can store both Foo and Bar objects, because they both implement the interface A. 这样它就可以存储Foo和Bar对象,因为它们都实现了接口A.

You could maintain a list of all of the possible types that implement that interface and then iterate over their types until you find one that matches the input string. 您可以维护实现该接口的所有可能类型的列表,然后迭代它们的类型,直到找到与输入字符串匹配的类型。 Other than that I think you will have trouble doing this in Java. 除此之外,我认为你在Java中做这件事会遇到麻烦。

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

Output: 输出:

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]

(Not sure what this proves -- you still can't declare your ArrayList to be of variable (vs <?> ) type. But there it is, FWIW.) (不确定这证明了什么 - 你仍然不能声明你的ArrayList是变量(vs <?> )类型。但它是,FWIW。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM