如果类名作为字符串传递,如何动态调用类的方法
Posted
技术标签:
【中文标题】如果类名作为字符串传递,如何动态调用类的方法【英文标题】:How to Dynamically call a method of a class if class name is passed as string 【发布时间】:2021-08-16 14:43:15 【问题描述】:我想创建动态对象,以便调用类的相应方法。所有类和接口都在不同的文件中,但在同一个文件夹下 给定:
interface Method
public void display();
class Car implements Method
public void display()
System.out.print("Car method");
class Honda implements Method
public void display()
System.out.print("Honda method");
public class Main
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException
String className = "Car";
Class cls = Class.forName(className);
Method method = (Method) cls.getConstructor().newInstance();
method.display();
现在,如果在字符串中传递 Honda,那么我想调用字符串方法,但是如果我在字符串中传递 Car,那么我想获取 Car 方法作为输出,但是编译后这个方法不会被调用。没有错误,但也没有预期的输出。如何获得所需的输出。请帮忙。
【问题讨论】:
最好的选择是定义一个定义display()
方法的接口。让Car
和Bicycle
实现这个接口,然后,通过newInstance()
为默认构造函数或Constructor
类为非默认构造函数实例化对象后,将生成的对象转换为该接口并将其用作该类型的常规对象。请注意,除了纯反射,您还可以深入研究MethodHandle,与反射相比,它更轻量级。
这能回答你的问题吗? Casting a class using reflection in java
警告:您使用的是原始类型 Class
。不要使用原始类型,始终提供必要的类型参数。
首先,为了清楚起见,我将接口命名为Displayable
,因为它基本上提供了这个接口。其次,“Honda”不是类名。这是一个车辆名称。您需要向Class.forName(...)
提供完全限定的类名,以便它加载实际的类定义并为其创建类对象。如果您要使用像org.acme.Car
这样的包结构,即您需要调用Class.forName("org.acme.Car")
,或者对于默认包只需调用Class.forName("Car")
。但是Honda
不是类名,至少不会出现在您的代码中
在某些时候你确实知道你想要/需要创建什么对象,这就是你初始化它的时刻。 Class.forName(...)
仅在类定义不是应用程序类路径的一部分时才需要使用,因此应用程序类加载器或其任何被要求为该类提供类对象的父级不知道类的字节. new XYZ(...)
基本上是整个样板代码的捷径,如果针对应用程序类加载器,您需要编写实例化类的对象
【参考方案1】:
您可以调用所需的方法。
Method method = cls.getMethod("display");
method.invoke(parameters);
如果允许我更新上面的代码,它会像下面这样,
interface Car
public void display();
class Honda implements Car
public void display()
System.out.print("Car method");
public class Main
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException
String className = "Car";
Class cls = Class.forName(className);
Honda honda = (Honda)cls.newInstance()
honda.display();
希望这将清除我在上面的答案中提到的Method
类。
【讨论】:
这个 Method 类会做什么?参数列表也是事先不知道的。 您可以使用这个Method
类来调用该方法。它还将返回使用method.getParameterTypes()
的方法中预期的参数。它返回对象参数类型的数组。更多信息可以在这里找到docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html
注意他的接口被命名为Method
。他的Method method = ...
声明不是指java.lang.reflect.Method
,而是指他自己的Method
-interface
@codeflush.dev 问题后来更新了这些细节。让我相应地更新我的答案。【参考方案2】:
方法 class.newInstance() 已被弃用。所以你应该使用
Class<?> clazz = Class.forName(className);
Constructor<?> ctor = clazz.getConstructor(String.class).newInstance();
Object object = ctor.newInstance(ctorArgument);
SN:在这种情况下,我假设构造函数只有一个 String 参数值。必须调用 getConstructor
方法并传递所需构造函数具有的所有类类型(正确排序)。
使用 newInstance 时,您需要传递实际构造函数的 args 值
此时您必须使用getMethod()
获取方法,这需要方法名称和所有参数的类型。要实际调用该方法,您传递要调用该方法的对象的实例(在本例中是我们的 object 并传递实际参数的值以调用它
clazz.getMethod("methodName", String.class, String.class).invoke(object, "parameter1", "parameter2");
编辑:OP 更新了两个类实现公共接口的问题。在这种情况下,您实际上可以调用您知道将让每个类都实现该接口的方法。这样,除了创建对象本身的新实例外,您不必使用任何反射魔法
使用通用界面
Method method = (Method) Class.forName(className).getConstructor().newInstance();
method.display();
最后一行会调用实现接口的对象实例的显示方法
【讨论】:
正在写构造函数> ctor = clazz.getConstructor(String.class).newInstance();强制性的?相反,我创建了 Method 对象并将其放入其中,但在调用 display 方法后,我没有收到任何错误,但也不需要输出。 如果您查看代码,我已经对其进行了一些更改。所以你能提供你的解释吗?给它。 这不是强制性的,但通常不使用任何已弃用的类/方法,因为在不久的将来它们可能会被丢弃。通常,如果它已被弃用,那是因为它通常已被性能更好/更完整的替代品取代以上是关于如果类名作为字符串传递,如何动态调用类的方法的主要内容,如果未能解决你的问题,请参考以下文章