Как вызвать метод Java, если имя метода задано в виде строки?

Если у меня две переменные:

Object obj;
String methodName = "getName";

Не зная класса obj, как я могу вызвать на нем метод, идентифицированный methodName?

Вызываемый метод не имеет параметров и возвращает значение String. Это геттер для Java bean.

Либо используйте отражение api, либо используйте заводной

Peter Kelley 02.10.2008 09:21
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
701
1
931 586
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Используйте вызов метода из отражения:

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

Где:

  • "class name" - это имя класса
  • objectToInvokeOn имеет тип Object и является объектом, для которого вы хотите вызвать метод.
  • "method name" - это имя метода, который вы хотите вызвать
  • parameterTypes имеет тип Class[] и объявляет параметры, которые принимает метод.
  • params имеет тип Object[] и объявляет параметры, передаваемые методу.

Круто, я думаю, вы правы с getDeclaredMethod (), он, вероятно, «безопаснее», чем getMethod () ..

brasskazoo 02.10.2008 09:40

Неправильный. Да, getDeclaredMethod работает с частными и защищенными методами. НО: он не работает с методами, определенными в суперклассах (унаследованные методы). Итак, это сильно зависит от того, что вы хотите делать. Во многих случаях вы хотите, чтобы он работал независимо от того, в каком именно классе определен метод.

jrudolph 02.10.2008 13:12

А куда мне положить "классный" файл? желательно объяснить для Eclipse IDE

Dr.jacky 08.08.2016 14:04

@ Мистер Хайд на пути своего класса.

Stijn de Witt 09.03.2017 14:31

Что мне следует поместить внутрь и method.invoke (), если вызываемый мной метод вообще не принимает никаких параметров? Кажется, мне все еще нужно указать второй параметр, если это какой-то пустой массив объектов?

Igor 23.04.2020 18:07

Это похоже на то, что можно сделать с пакетом Java Reflection.

http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html

В частности, под Вызов методов по имени:

import java.lang.reflect. *;

public class method2 {
  public int add(int a, int b)
  {
     return a + b;
  }

  public static void main(String args[])
  {
     try {
       Class cls = Class.forName("method2");
       Class partypes[] = new Class[2];
        partypes[0] = Integer.TYPE;
        partypes[1] = Integer.TYPE;
        Method meth = cls.getMethod(
          "add", partypes);
        method2 methobj = new method2();
        Object arglist[] = new Object[2];
        arglist[0] = new Integer(37);
        arglist[1] = new Integer(47);
        Object retobj 
          = meth.invoke(methobj, arglist);
        Integer retval = (Integer)retobj;
        System.out.println(retval.intValue());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }
}

Object obj;

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

method.invoke(obj, null);

Объект должен иметь как минимум value / values.

Lova Chittumuri 12.02.2018 17:38

Это действительно хорошо сработало для того, что мне было нужно. У меня был класс, который уже был создан, и мне просто нужно было получить от него метод. Добавление уловок для исключений здесь - хорошая идея, но в остальном это отлично сработало для меня. Я думаю, что моим способом избежать нулевых исключений было использование значений NULL, но я использовал очень ограниченный диапазон имен методов (буквально просто счетчик от 1 до 4).

Jain Waldrip 25.03.2019 23:41
Ответ принят как подходящий

Кодирование от бедра будет примерно таким:

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

Был немного расстроен тем фактом, что Java использует стирание типов, но знание того, что хотя бы в нем есть Reflection, снова меня подбадривает: D А теперь с лямбдами в Java 8 язык действительно идет в ногу с современной разработкой. Единственное, чего сейчас не хватает, так это встроенной поддержки геттеров и сеттеров, или свойств, как они известны в C#.

7hi4g0 01.04.2014 17:23

Не честно -1. Хенрик, вероятно, не защищает исключения исключений и ничего не писал для них, потому что он просто пытается продемонстрировать размышления.

drew 22.05.2014 00:52

Плюс один за отображение некоторых возможных исключений. Если бы я написал это, это было бы ... catch (Exception e) {...

mikbanUtah 11.12.2014 09:32

Я получил "переменная, возможно, не была инициализирована" для method в method.invoke(obj, arg1, arg2,...);. method = null; решает проблему, но упомянуть об этом в ответе - неплохая идея.

Amin 14.02.2016 21:14

Мне что-то не хватает или этот вызов не возвращает код ошибки Java. Например, если метод заканчивается чем-либо, кроме System.exit (0), этот метод не сообщит об этом? Или для этого существует исключение?

DeaMon1 19.07.2016 22:13

@ DeaMon1 Java-методы не используют «коды выхода», но если метод что-то возвращает, invoke вернет все, что вернул. Если при запуске метода возникает исключение, исключение будет заключено в InvocationTargetException.

ThePyroEagle 22.12.2016 18:28

@ThePyroEagle ага, я имел в виду код возврата из выполнения поста класса.

DeaMon1 16.01.2017 22:29

Зачем вам нет использовать catch (Exception e) для чего-то вроде этого?

Andrew 20.06.2017 19:49

@ 7hi4g0 Если вам просто нужны геттеры и сеттеры, есть projectlombok.org, который также дает вам такие вещи, как аннотации для создания автоматических регистраторов, val и var «типы», автоматические равенства и хэш-коды, создание toString и т. д. И все это без заполнения вашего кода автоматически сгенерированным кодом что никто не хочет видеть. Это довольно круто. Если бы только Java могла формализовать поддержку макросов времени компиляции, и она была бы впереди всех языков, отличных от лиспа.

Haakon Løtveit 10.08.2017 11:21

@Andrew, вы бы не хотели ловить только Exception, если хотите точно знать, в чем проблема, и соответственно обрабатывать каждый подтип исключения

RJFares 29.11.2017 10:14

Особенно с InvocationTargetException, где ваш блок catch, вероятно, throw e.getCause(); получит исключение, созданное самим целевым методом.

neXus 10.09.2018 15:54

Метод можно вызвать так. Также есть больше возможностей (проверьте 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 за единственный ответ, который признал, что ОП не указал «никаких параметров» в своем вопросе (и потому что это было то, что я тоже искал).

John Fitzpatrick 17.01.2013 21:54

Чтобы завершить ответы моего коллеги, вы можете обратить пристальное внимание на:

  • статические вызовы или вызовы экземпляра (в одном случае вам не нужен экземпляр класса, в другом вам может потребоваться полагаться на существующий конструктор по умолчанию, который может быть или не быть там)
  • вызов публичного или непубличного метода (для последнего вам нужно вызвать setAccessible для метода в блоке doPrivileged, другой findbugs не будут счастливы)
  • инкапсуляция в еще одно управляемое прикладное исключение, если вы хотите отбросить многочисленные системные исключения Java (отсюда CCException в приведенном ниже коде)

Вот старый код java1.4, который учитывает эти моменты:

/**
 * Allow for instance call, avoiding certain class circular dependencies. <br />
 * 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;
}

Во-первых, не надо. Избегайте такого кода. Обычно это действительно плохой код, а также небезопасный (см. Раздел 6 Рекомендации по безопасному кодированию для Язык программирования Java, версия 2.0).

Если вы должны это сделать, предпочтите java.beans отражению. Beans обертывает отражение, обеспечивая относительно безопасный и традиционный доступ.

Я не согласен. Такой код очень легко написать для обеспечения безопасности, и я сделал это на нескольких языках. Например, можно создать набор допустимых методов и разрешить вызов метода только в том случае, если его имя находится в наборе. Еще более безопасным (но все же безумно простым) было бы ограничение каждого разрешенного метода определенным состоянием и запрет на вызов метода, если только поток / интерфейс / пользователь / что-то еще не соответствует таким критериям.

JSON 09.02.2015 12:39

Никогда не будьте столь категоричны в подобных вопросах. Прямо сейчас я создаю простую программу, позволяющую пользователю определять произвольные задачи над произвольными объектами с помощью веб-интерфейсов. Я знаю, что это действительно небезопасно, но после получения конфигурации выполняется надлежащее тестирование, и это позволяет непрограммисту легко настраивать задачи, а также дает программам возможность связывать пользовательские классы с общим кодом (это часть, которую я использую для отражения, чтобы позволить им настраивать, какие методы использовать через веб-интерфейс) без необходимости обновлять графический интерфейс.

DGoiko 04.08.2019 22:56

для меня довольно простым и надежным способом было бы просто создать метод вызывающего метода следующим образом:

public static object methodCaller(String methodName)
{
    if (methodName.equals("getName"))
        return className.getName();
}

затем, когда вам нужно вызвать метод, просто введите что-то вроде этого

//calling a toString method is unnessary here, but i use it to have my programs to both rigid and self-explanitory 
System.out.println(methodCaller(methodName).toString()); 

Если экземпляр уже известен во время компиляции, почему бы вам просто не сделать className.getName().toString()? Вы упускаете из виду весь смысл размышлений.

BalusC 17.06.2010 00:31

Как я уже сказал, в данном случае нет необходимости, но при условии, что вы всегда будете знать, что этот экземпляр - плохая привычка программирования.

SMayne 17.06.2010 21:19

@SMayne: Я бы посоветовал удалить этот пост.

lpapp 18.04.2014 19:11

плохое программирование в этом случае скорее будет комплиментом

pdenti 12.12.2014 21:57

//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");

Для тех, кому нужен простой пример кода на 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, ...);

Предлагаемое чтение:Создание экземпляров новых классов

Лучший ответ здесь. Полный и лаконичный

Reuben JaMes Aveño Gruta 20.01.2017 10:09

Правильный лучший ответ.

Dhara Patel 10.05.2017 16:12

Где взять объект Method?

parlad 03.10.2018 10:06

Из отражения pkg.

silver 08.10.2018 14:22

Вы должны использовать отражение - инициализировать объект класса, затем метод в этом классе, а затем вызвать этот метод для объекта с параметрами по желанию. Не забудьте заключить следующий фрагмент в блок попробуй поймать

Надеюсь, это поможет!

Class<?> aClass = Class.forName(FULLY_QUALIFIED_CLASS_NAME);
Method method = aClass.getMethod(methodName, YOUR_PARAM_1.class, YOUR_PARAM_2.class);
method.invoke(OBJECT_TO_RUN_METHOD_ON, YOUR_PARAM_1, YOUR_PARAM_2);

Это отлично работает для меня:

public class MethodInvokerClass {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException, InvocationTargetException, InstantiationException {
        Class c = Class.forName(MethodInvokerClass.class.getName());
        Object o = c.newInstance();
        Class[] paramTypes = new Class[1];
        paramTypes[0]=String.class;
        String methodName = "countWord";
         Method m = c.getDeclaredMethod(methodName, paramTypes);
         m.invoke(o, "testparam");
}
public void countWord(String input){
    System.out.println("My input "+input);
}

}

Выход:

My input testparam

Я могу вызвать метод, передав его имя другому методу (например, main).

Пожалуйста, обратитесь к следующему коду, который может вам помочь.

public static Method method[];
public static MethodClass obj;
public static String testMethod = "A";

public static void main(String args[]) 
{
    obj=new MethodClass();
    method=obj.getClass().getMethods();
    try
    {
        for(int i=0;i<method.length;i++)
        {
            String name=method[i].getName();
            if (name==testMethod)
            {   
                method[i].invoke(name,"Test Parameters of A");
            }
        }
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
    }
}

Спасибо....

Это не то, как вы сравниваете строки в Java. Вы должны использовать метод .equals. В противном случае вы просто сравниваете, что это одна и та же ссылка на объект, и на самом деле вы не заботитесь о ссылках на объекты - только содержимое строки является совпадением. Вы также можете получить метод по имени через отражение, поэтому не знаете, зачем вам использовать собственный?

Lo-Tan 12.12.2019 22:41

Я так делаю:

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

с использованием import java.lang.reflect.*;

public static Object launchProcess(String className, String methodName, Class<?>[] argsTypes, Object[] methodArgs)
        throws Exception {

    Class<?> processClass = Class.forName(className); // convert string classname to class
    Object process = processClass.newInstance(); // invoke empty constructor

    Method aMethod = process.getClass().getMethod(methodName,argsTypes);
    Object res = aMethod.invoke(process, methodArgs); // pass arg
    return(res);
}

и вот как вы его используете:

String className = "com.example.helloworld";
String methodName = "print";
Class<?>[] argsTypes = {String.class,  String.class};
Object[] methArgs = { "hello", "world" };   
launchProcess(className, methodName, argsTypes, methArgs);

Method method = someVariable.class.getMethod(SomeClass);
String status = (String) method.invoke(method);

SomeClass - это класс, а someVariable - это переменная.

если someVariable действительно является объектом, вызовите someVariable.getClass (). Кроме того, вы не можете вызывать getMethod () с классом в качестве единственного аргумента. Ни один из методов не вызывается с помощью метода. Правильно: someVariable.getClass (). GetMethod ("coolMethod", parameterClasses) .invoke (arguments);

indique 01.03.2020 14:31

Если вы выполните вызов несколько раз, вы можете использовать новые дескрипторы методов, представленные в Java 7. Здесь мы переходим к вашему методу, возвращающему String:

Object obj = new Point( 100, 200 );
String methodName = "toString";  
Class<String> 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);

Jorn Vernee 04.02.2018 15:09

Student.java

class Student{
    int rollno;
    String name;

    void m1(int x,int y){
        System.out.println("add is" +(x+y));
    }

    private void m3(String name){
        this.name=name;
        System.out.println("danger yappa:"+name);
    }
    void m4(){
        System.out.println("This is m4");
    }
}

StudentTest.java

import java.lang.reflect.Method;
public class StudentTest{

     public static void main(String[] args){

        try{

            Class cls=Student.class;

            Student s=(Student)cls.newInstance();


            String x = "kichha";
            Method mm3=cls.getDeclaredMethod("m3",String.class);
            mm3.setAccessible(true);
            mm3.invoke(s,x);

            Method mm1=cls.getDeclaredMethod("m1",int.class,int.class);
            mm1.invoke(s,10,20);

        }
        catch(Exception e){
            e.printStackTrace();
        }
     }
}

Вот ГОТОВЫЕ МЕТОДЫ:

Чтобы вызвать метод без аргументов:

public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    object.getClass().getDeclaredMethod(methodName).invoke(object);
}

Чтобы вызвать метод с аргументами:

    public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
    }

Используйте вышеуказанные методы, как показано ниже:

package practice;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class MethodInvoke {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
        String methodName1 = "methodA";
        String methodName2 = "methodB";
        MethodInvoke object = new MethodInvoke();
        callMethodByName(object, methodName1);
        callMethodByName(object, methodName2, 1, "Test");
    }

    public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName).invoke(object);
    }

    public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
    }

    void methodA() {
        System.out.println("Method A");
    }

    void methodB(int i, String s) {
        System.out.println("Method B: "+"\n\tParam1 - "+i+"\n\tParam 2 - "+s);
    }
}

Выход:

Method A  
Method B:  
	Param1 - 1  
	Param 2 - Test

Индексирование (быстрее)

Вы можете использовать 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);
    }
}

Лямбда-синтаксис

Вы также можете использовать лямбда-синтаксис:

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

Этот прием кажется намного лучше, чем отражение.

John O 24.05.2020 03:31

Неужели намного лучше?

Dimitri Kopriwa 26.05.2020 20:42

@DimitriKopriwa Indexing - это способ использования оперативной памяти вместо вычислений ЦП. Для целочисленной индексации сложность алгоритма O(1).

Amir Fo 27.05.2020 09:06

Это должен был быть ответ. Очень чистое решение. Мне нужно прочитать имя метода из файла конфигурации json. Поэтому, используя эту технику, я мог бы просто использовать HashMap of <String, function> вместо отражения.

venugopal 24.06.2020 02:58

С jooR это просто:

on(obj).call(methodName /*params*/).get()

Вот более подробный пример:

public class TestClass {

    public int add(int a, int b) { return a + b; }
    private int mul(int a, int b) { return a * b; }
    static int sub(int a, int b) { return a - b; }

}

import static org.joor.Reflect.*;

public class JoorTest {

    public static void main(String[] args) {
        int add = on(new TestClass()).call("add", 1, 2).get(); // public
        int mul = on(new TestClass()).call("mul", 3, 4).get(); // private
        int sub = on(TestClass.class).call("sub", 6, 5).get(); // static
        System.out.println(add + ", " + mul + ", " + sub);
    }
}

Это печатает:

3, 12, 1

Для тех, кто вызывает метод в том же классе из нестатического метода, см. Коды ниже:

class Person {
    public void method1() {
        try {
            Method m2 = this.getClass().getDeclaredMethod("method2");
            m1.invoke(this);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public void method2() {
        // Do something
    }

}

Другие вопросы по теме