[java] 메소드 이름을 문자열로 제공했을 때 Java 메소드를 어떻게 호출합니까?

두 개의 변수가있는 경우 :

Object obj;
String methodName = "getName";

의 클래스를 모른 채 obj식별 된 메소드를 어떻게 호출 할 수 methodName있습니까?

호출되는 메소드에는 매개 변수가 없으며 String리턴 값이 있습니다. 그것은의 자바 빈에 대한 게터 .



답변

엉덩이에서 코딩하면 다음과 같습니다.

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 에 대해 읽어보기


답변

리플렉션에서 메소드 호출 을 사용하십시오 .

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[]이며 메소드에 전달할 매개 변수를 선언합니다.

답변

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

제안 읽기 : 새 클래스 인스턴스 작성


답변

이와 같이 메소드를 호출 할 수 있습니다. 더 많은 가능성이 있지만 (반사 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);
    }



}


답변

먼저하지 마십시오. 이런 종류의 코드는 피하십시오. 코드가 잘못되어 안전하지 않은 경향이 있습니다 ( Java Programming Language에 대한 보안 코딩 지침, 버전 2.0 섹션 6 참조 ).

그렇게해야한다면, 리플렉션보다 java.beans를 선호하십시오. 콩은 반사를 감싸서 비교적 안전하고 일반적인 접근을 허용합니다.


답변

동료의 답변을 완성하려면 다음 사항에주의를 기울이십시오.

  • 정적 또는 인스턴스 호출 (한 경우 클래스의 인스턴스가 필요하지 않고 다른 경우에는 존재 하거나 존재하지 않을 수 있는 기존 기본 생성자 에 의존해야 할 수도 있음)
  • 공개 또는 비공개 메소드 호출 (후자의 경우 doPrivileged 블록 내의 메소드에서 setAccessible을 호출해야합니다 . 다른 findbugs는 행복하지 않습니다 )
  • 수많은 자바 시스템 예외를 되돌리려면 더 관리 가능한 하나의 적용 예외로 캡슐화하십시오 (따라서 아래 코드의 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;
}


답변

Object obj;

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

method.invoke(obj, null);