简体   繁体   中英

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. 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.

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

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.

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. 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. At runtime, generic types have been converted to Object , with the compiler having substituted type-safe casts where necessary.

Use Class.forName(String classNameWithPath) method - it will do what you want.

There is an example over here - What is the difference between "Class.forName()" and "Class.forName().newInstance()"?

Declare the array list as an ArrayList<A> . That way it can store both Foo and Bar objects, because they both implement the interface 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.

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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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