Если у меня две переменные:
Object obj;
String methodName = "getName";
Не зная класса obj, как я могу вызвать на нем метод, идентифицированный methodName?
Вызываемый метод не имеет параметров и возвращает значение String. Это геттер для Java bean.




Используйте вызов метода из отражения:
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 () ..
Неправильный. Да, getDeclaredMethod работает с частными и защищенными методами. НО: он не работает с методами, определенными в суперклассах (унаследованные методы). Итак, это сильно зависит от того, что вы хотите делать. Во многих случаях вы хотите, чтобы он работал независимо от того, в каком именно классе определен метод.
А куда мне положить "классный" файл? желательно объяснить для Eclipse IDE
@ Мистер Хайд на пути своего класса.
Что мне следует поместить внутрь и method.invoke (), если вызываемый мной метод вообще не принимает никаких параметров? Кажется, мне все еще нужно указать второй параметр, если это какой-то пустой массив объектов?
Это похоже на то, что можно сделать с пакетом 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.
Это действительно хорошо сработало для того, что мне было нужно. У меня был класс, который уже был создан, и мне просто нужно было получить от него метод. Добавление уловок для исключений здесь - хорошая идея, но в остальном это отлично сработало для меня. Я думаю, что моим способом избежать нулевых исключений было использование значений NULL, но я использовал очень ограниченный диапазон имен методов (буквально просто счетчик от 1 до 4).
Кодирование от бедра будет примерно таким:
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#.
Не честно -1. Хенрик, вероятно, не защищает исключения исключений и ничего не писал для них, потому что он просто пытается продемонстрировать размышления.
Плюс один за отображение некоторых возможных исключений. Если бы я написал это, это было бы ... catch (Exception e) {...
Я получил "переменная, возможно, не была инициализирована" для method в method.invoke(obj, arg1, arg2,...);. method = null; решает проблему, но упомянуть об этом в ответе - неплохая идея.
Мне что-то не хватает или этот вызов не возвращает код ошибки Java. Например, если метод заканчивается чем-либо, кроме System.exit (0), этот метод не сообщит об этом? Или для этого существует исключение?
@ DeaMon1 Java-методы не используют «коды выхода», но если метод что-то возвращает, invoke вернет все, что вернул. Если при запуске метода возникает исключение, исключение будет заключено в InvocationTargetException.
@ThePyroEagle ага, я имел в виду код возврата из выполнения поста класса.
Зачем вам нет использовать catch (Exception e) для чего-то вроде этого?
@ 7hi4g0 Если вам просто нужны геттеры и сеттеры, есть projectlombok.org, который также дает вам такие вещи, как аннотации для создания автоматических регистраторов, val и var «типы», автоматические равенства и хэш-коды, создание toString и т. д. И все это без заполнения вашего кода автоматически сгенерированным кодом что никто не хочет видеть. Это довольно круто. Если бы только Java могла формализовать поддержку макросов времени компиляции, и она была бы впереди всех языков, отличных от лиспа.
@Andrew, вы бы не хотели ловить только Exception, если хотите точно знать, в чем проблема, и соответственно обрабатывать каждый подтип исключения
Особенно с InvocationTargetException, где ваш блок catch, вероятно, throw e.getCause(); получит исключение, созданное самим целевым методом.
Метод можно вызвать так. Также есть больше возможностей (проверьте 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 за единственный ответ, который признал, что ОП не указал «никаких параметров» в своем вопросе (и потому что это было то, что я тоже искал).
Чтобы завершить ответы моего коллеги, вы можете обратить пристальное внимание на:
Вот старый код 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 обертывает отражение, обеспечивая относительно безопасный и традиционный доступ.
Я не согласен. Такой код очень легко написать для обеспечения безопасности, и я сделал это на нескольких языках. Например, можно создать набор допустимых методов и разрешить вызов метода только в том случае, если его имя находится в наборе. Еще более безопасным (но все же безумно простым) было бы ограничение каждого разрешенного метода определенным состоянием и запрет на вызов метода, если только поток / интерфейс / пользователь / что-то еще не соответствует таким критериям.
Никогда не будьте столь категоричны в подобных вопросах. Прямо сейчас я создаю простую программу, позволяющую пользователю определять произвольные задачи над произвольными объектами с помощью веб-интерфейсов. Я знаю, что это действительно небезопасно, но после получения конфигурации выполняется надлежащее тестирование, и это позволяет непрограммисту легко настраивать задачи, а также дает программам возможность связывать пользовательские классы с общим кодом (это часть, которую я использую для отражения, чтобы позволить им настраивать, какие методы использовать через веб-интерфейс) без необходимости обновлять графический интерфейс.
для меня довольно простым и надежным способом было бы просто создать метод вызывающего метода следующим образом:
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()? Вы упускаете из виду весь смысл размышлений.
Как я уже сказал, в данном случае нет необходимости, но при условии, что вы всегда будете знать, что этот экземпляр - плохая привычка программирования.
@SMayne: Я бы посоветовал удалить этот пост.
плохое программирование в этом случае скорее будет комплиментом
//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, ...);
Предлагаемое чтение:Создание экземпляров новых классов
Лучший ответ здесь. Полный и лаконичный
Правильный лучший ответ.
Где взять объект Method?
Из отражения pkg.
Вы должны использовать отражение - инициализировать объект класса, затем метод в этом классе, а затем вызвать этот метод для объекта с параметрами по желанию. Не забудьте заключить следующий фрагмент в блок попробуй поймать
Надеюсь, это поможет!
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. В противном случае вы просто сравниваете, что это одна и та же ссылка на объект, и на самом деле вы не заботитесь о ссылках на объекты - только содержимое строки является совпадением. Вы также можете получить метод по имени через отражение, поэтому не знаете, зачем вам использовать собственный?
Я так делаю:
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);
Если вы выполните вызов несколько раз, вы можете использовать новые дескрипторы методов, представленные в 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);
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");
}
}
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);
}
}
Этот прием кажется намного лучше, чем отражение.
Неужели намного лучше?
@DimitriKopriwa Indexing - это способ использования оперативной памяти вместо вычислений ЦП. Для целочисленной индексации сложность алгоритма O(1).
Это должен был быть ответ. Очень чистое решение. Мне нужно прочитать имя метода из файла конфигурации json. Поэтому, используя эту технику, я мог бы просто использовать HashMap of <String, function> вместо отражения.
С 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
}
}
Либо используйте отражение api, либо используйте заводной