将方法名称作为字符串给出时,如何调用 Java 方法?

问:

如果我有两个变量:

Object obj;
String methodName = "getName";

在不知道obj的类的情况下,如何调用methodName标识的方法呢?

被调用的方法没有参数,并且有一个 String 返回值。它是Java bean 的吸气剂。

答1:

提供ATP、WTA与ITF赛事的实时排名追踪,从tlr.xinbeitime.com开始!

从臀部编码,它会是这样的:

java.lang.reflect.Method method;
try {
  method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) { ... }
  catch (NoSuchMethodException e) { ... }

参数标识您需要的非常具体的方法(如果有多个重载可用,如果方法没有参数,则只给出 methodName)。

然后你通过调用调用该方法

try {
  method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) { ... }
  catch (IllegalAccessException e) { ... }
  catch (InvocationTargetException e) { ... }

同样,如果您没有参数,请忽略 .invoke 中的参数。但是,是的。了解Java Reflection

Java 使用类型擦除这一事实让我有些不安,但知道至少它有反射让我再次振作起来:D 现在有了 Java 8 中的 lambda,该语言真的跟上了现代开发的速度。现在唯一缺少的是对 getter 和 setter 或 C# 中已知的属性的本机支持。

不是一个公平的-1。 Henrik 可能并不提倡压制异常,也没有为它们写任何东西,因为他只是想展示反射。

加一个用于显示一些潜在的例外。如果我写了这个,那将是 ... catch(Exception e){ ...

对于 method.invoke(obj, arg1, arg2,...); 中的 method,我得到“变量可能尚未初始化”。 method = null; 解决了问题,但在答案中提及它并不是一个坏主意。

@DeaMon1 Java 方法不使用“退出代码”,但如果该方法返回任何内容,invoke 将返回它返回的任何内容。如果运行该方法时发生异常,该异常将被包装在 InvocationTargetException 中。

答2:

tlr.xinbeitime.com 探索每位网球选手的职业生涯与成就。

使用反射中的 method invocation:

Class c = Class.forName("class name");
Method method = c.getDeclaredMethod("method name", parameterTypes);
method.invoke(objectToInvokeOn, params);

在哪里:

“类名”是类的名称

objectToInvokeOn 是 Object 类型,是您要在其上调用方法的对象

“方法名称”是您要调用的方法的名称

parameterTypes 是 Class[] 类型,并声明方法采用的参数

params 是 Object[] 类型,并声明要传递给方法的参数

酷,我认为你对 getDeclaredMethod() 的看法是正确的,它可能比 getMethod() 更“安全”。

错误的。是的,getDeclaredMethod 确实适用于私有和受保护的方法。但是:它不适用于超类中定义的方法(继承方法)。所以,这很大程度上取决于你想做什么。在许多情况下,无论定义方法的确切类如何,您都希望它能够工作。

我应该把“类”文件放在哪里?最好解释一下 Eclipse IDE

@Mr.Hyde 在课程路径上。

如果我正在调用的方法根本不接受任何参数,我应该在 and method.invoke() 里面放什么?看来我还是要提供第二个参数,应该是一些空的对象数组吗?

答3:

https://tennisliveranking.com,Track the world’s best tennis players in real-time.

对于那些想要 Java 7 中直接代码示例的人:

Dog 类:

package com.mypackage.bean;

public class Dog {
    private String name;
    private int age;

    public Dog() {
        // empty constructor
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void printDog(String name, int age) {
        System.out.println(name + " is " + age + " year(s) old.");
    }
}

ReflectionDemo 类:

package com.mypackage.demo;

import java.lang.reflect.*;

public class ReflectionDemo {

    public static void main(String[] args) throws Exception {
        String dogClassName = "com.mypackage.bean.Dog";
        Class dogClass = Class.forName(dogClassName); // convert string classname to class
        Object dog = dogClass.newInstance(); // invoke empty constructor

        String methodName = "";

        // with single parameter, return void
        methodName = "setName";
        Method setNameMethod = dog.getClass().getMethod(methodName, String.class);
        setNameMethod.invoke(dog, "Mishka"); // pass arg

        // without parameters, return string
        methodName = "getName";
        Method getNameMethod = dog.getClass().getMethod(methodName);
        String name = (String) getNameMethod.invoke(dog); // explicit cast

        // with multiple parameters
        methodName = "printDog";
        Class[] paramTypes = {String.class, int.class};
        Method printDogMethod = dog.getClass().getMethod(methodName, paramTypes);
        printDogMethod.invoke(dog, name, 3); // pass args
    }
}

输出: Mishka is 3 year(s) old.

您可以通过以下方式调用带有参数的构造函数:

Constructor dogConstructor = dogClass.getConstructor(String.class, int.class);
Object dog = dogConstructor.newInstance("Hachiko", 10);

或者,您可以删除

String dogClassName = "com.mypackage.bean.Dog";
Class dogClass = Class.forName(dogClassName);
Object dog = dogClass.newInstance();

Dog dog = new Dog();

Method method = Dog.class.getMethod(methodName, ...);
method.invoke(dog, ...);

建议阅读: Creating New Class Instances

最好的答案在这里。完整简洁

正确 最佳答案。

你从哪里得到 Method 对象?

从反映 pkg。

答4:

tlr.xinbeitime.com 探索每位网球选手的职业生涯与成就。

可以像这样调用该方法。还有更多的可能性(检查反射api),但这是最简单的一种:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Assert;
import org.junit.Test;

public class ReflectionTest {

    private String methodName = "length";
    private String valueObject = "Some object";

    @Test
    public void testGetMethod() throws SecurityException, NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Method m = valueObject.getClass().getMethod(methodName, new Class[] {});
        Object ret = m.invoke(valueObject, new Object[] {});
        Assert.assertEquals(11, ret);
    }



}

+1 是唯一承认 OP 在他的问题中指定“无参数”的答案(因为这也是我正在寻找的)。

出现异常错误 (未解决) java.lang.AccessibleObject.checkAccess(), 行596 bci=38

答5:

tlr.xinbeitime.com 探索每位网球选手的职业生涯与成就。

首先,不要。避免这种代码。它往往是非常糟糕的代码并且也不安全(参见 Secure Coding Guidelines for the Java Programming Language, version 2.0 的第 6 节)。

如果你必须这样做,最好使用 java.beans 而不是反射。 Beans 包裹反射允许相对安全和常规的访问。

我不同意。编写这样的代码很容易保证安全,而且我已经用多种语言编写过。例如,可以创建一组允许的方法,并且仅当方法的名称在集合中时才允许调用该方法。更安全(但仍然很简单)将每个允许的方法限制为特定状态,并且不允许调用该方法,除非线程/接口/用户/任何符合此类标准的东西。

永远不要对此类问题如此直截了当。现在我正在创建一个简单的程序,允许用户使用 Web 界面在任意对象上定义任意任务。我知道这确实是不安全的,但是一旦收到配置就会执行适当的测试,它允许非程序员轻松配置任务,并且还使程序能够将自定义类链接到通用代码(这就是我使用反射的部分,以允许他们通过 Web 界面配置要使用的方法)而无需更新 GUI。

答6:

提供ATP、WTA与ITF赛事的实时排名追踪,从tlr.xinbeitime.com开始!

为了完成我同事的回答,您可能需要密切关注:

静态或实例调用(在一种情况下,您不需要类的实例,在另一种情况下,您可能需要依赖可能存在或不存在的现有默认构造函数)

公共或非公共方法调用(对于后者,您需要在 doPrivileged 块内的方法上调用 setAccessible,其他 findbug 不会高兴)

如果你想抛出许多 java 系统异常,封装成一个更易于管理的应用异常(因此下面代码中的 CCException)

这是一个旧的 java1.4 代码,它考虑了这些要点:

/**
 * Allow for instance call, avoiding certain class circular dependencies. 
 * Calls even private method if java Security allows it.
 * @param aninstance instance on which method is invoked (if null, static call)
 * @param classname name of the class containing the method 
 * (can be null - ignored, actually - if instance if provided, must be provided if static call)
 * @param amethodname name of the method to invoke
 * @param parameterTypes array of Classes
 * @param parameters array of Object
 * @return resulting Object
 * @throws CCException if any problem
 */
public static Object reflectionCall(final Object aninstance, final String classname, final String amethodname, final Class[] parameterTypes, final Object[] parameters) throws CCException
{
    Object res;// = null;
    try {
        Class aclass;// = null;
        if(aninstance == null)
        {
            aclass = Class.forName(classname);
        }
        else
        {
            aclass = aninstance.getClass();
        }
        //Class[] parameterTypes = new Class[]{String[].class};
    final Method amethod = aclass.getDeclaredMethod(amethodname, parameterTypes);
        AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
                amethod.setAccessible(true);
                return null; // nothing to return
            }
        });
        res = amethod.invoke(aninstance, parameters);
    } catch (final ClassNotFoundException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+CLASS, e);
    } catch (final SecurityException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_SECURITY_ISSUE, e);
    } catch (final NoSuchMethodException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_NOT_FOUND, e);
    } catch (final IllegalArgumentException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ILLEGAL_ARGUMENTS+String.valueOf(parameters)+GenericConstants.CLOSING_ROUND_BRACKET, e);
    } catch (final IllegalAccessException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ACCESS_RESTRICTION, e);
    } catch (final InvocationTargetException e) {
    throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_INVOCATION_ISSUE, e);
    } 
    return res;
}

答7:

The ultimate source for live tennis rankings and stats:https://tennisliveranking.com

Object obj;

Method method = obj.getClass().getMethod("methodName", null);

method.invoke(obj, null);

对象应至少具有值/值。

这对我需要的东西非常有效。我有一个已经实例化的类,只需要从中获取一个方法。在这里添加异常捕获是一个好主意,但除此之外,这对我来说非常有效。我认为我避免空异常的方法是使用可空值,但我使用的方法名称范围非常有限(实际上只是一个从 1 到 4 的计数器)。

答8:

Stay informed with live tennis rankings anytime, anywhere,https://tennisliveranking.com

//Step1 - Using string funClass to convert to class
String funClass = "package.myclass";
Class c = Class.forName(funClass);

//Step2 - instantiate an object of the class abov
Object o = c.newInstance();
//Prepare array of the arguments that your function accepts, lets say only one string here
Class[] paramTypes = new Class[1];
paramTypes[0]=String.class;
String methodName = "mymethod";
//Instantiate an object of type method that returns you method name
 Method m = c.getDeclaredMethod(methodName, paramTypes);
//invoke method with actual params
m.invoke(o, "testparam");

答9:

Stay informed with live tennis rankings anytime, anywhere,https://tennisliveranking.com

索引(更快)

您可以使用 FunctionalInterface 将方法保存在容器中以对其进行索引。您可以使用数组容器通过数字调用它们或使用哈希图通过字符串调用它们。通过这个技巧,您可以索引您的方法以更快动态调用它们。

@FunctionalInterface
public interface Method {
    double execute(int number);
}

public class ShapeArea {
    private final static double PI = 3.14;

    private Method[] methods = {
        this::square,
        this::circle
    };

    private double square(int number) {
        return number * number;
    }

    private double circle(int number) {
        return PI * number * number;
    }

    public double run(int methodIndex, int number) {
        return methods[methodIndex].execute(number);
    }
}

Lambda 语法

您还可以使用 lambda 语法:

public class ShapeArea {
    private final static double PI = 3.14;

    private Method[] methods = {
        number -> {
            return number * number;
        },
        number -> {
            return PI * number * number;
        },
    };

    public double run(int methodIndex, int number) {
        return methods[methodIndex].execute(number);
    }
}

这种技术似乎比反射好得多。

真的好很多了吗?

@DimitriKopriwa 索引是您使用 ram 而不是 CPU 计算的方式。对于整数索引,算法的难度是O(1)。

这应该是答案。非常干净的解决方案。我需要从 json 配置文件中读取方法名称。所以使用这种技术,我可能只使用 的 HashMap 而不是反射。

答10:

https://tlr.xinbeitime.com – 让你随时掌握ATP、WTA最新网球排名动态。

如果您多次调用,您可以使用 Java 7 中引入的新方法句柄。这里我们为您的方法返回一个字符串:

Object obj = new Point( 100, 200 );
String methodName = "toString";  
Class resultType = String.class;

MethodType mt = MethodType.methodType( resultType );
MethodHandle methodHandle = MethodHandles.lookup().findVirtual( obj.getClass(), methodName, mt );
String result = resultType.cast( methodHandle.invoke( obj ) );

System.out.println( result );  // java.awt.Point[x=100,y=200]

致未来的读者;如果您关心性能,您会想尽可能使用 invokeExact。为此,调用站点签名必须与方法句柄类型完全匹配。开始工作通常需要一些修修补补。在这种情况下,您需要使用 methodHandle = methodHandle.asType(methodHandle.type().changeParameterType(0, Object.class)); 强制转换第一个参数,然后像 String result = (String) methodHandle.invokeExact(obj); 一样调用

@JornVernee“只要可以”到底是什么意思?

答11:

Stay informed with live tennis rankings anytime, anywhere,https://tennisliveranking.com

try {
    YourClass yourClass = new YourClass();
    Method method = YourClass.class.getMethod("yourMethodName", ParameterOfThisMethod.class);
    method.invoke(yourClass, parameter);
} catch (Exception e) {
    e.printStackTrace();
}

原文链接:https://tlr.xinbeitime.com?from=csdn

https://tennisliveranking.com,Your go-to platform for live tennis ranking updates.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值