777 Stimmen

Wie rufe ich eine Java-Methode auf, wenn der Name der Methode als String angegeben ist?

Wenn ich zwei Variablen habe:

Object obj;
String methodName = "getName";

Ohne Kenntnis der Klasse der obj wie kann ich die Methode aufrufen, die durch methodName darauf?

Die aufgerufene Methode hat keine Parameter, und ein String Rückgabewert. Es ist ein Getter für eine Java-Bohne .

14voto

VonC Punkte 1117238

Um die Antworten meines Kollegen zu vervollständigen, sollten Sie vielleicht genau hinschauen:

  • statische oder Instanzaufrufe (im einen Fall benötigen Sie keine Instanz der Klasse, im anderen Fall müssen Sie sich möglicherweise auf eine bestehender Standardkonstruktor die dort sein können oder auch nicht)
  • öffentlicher oder nicht-öffentlicher Methodenaufruf (bei letzterem, müssen Sie setAccessible für die Methode innerhalb eines doPrivileged-Blocks aufrufen Sonstiges findbugs werden nicht glücklich sein )
  • Kapselung in eine handlichere anwendungsspezifische Ausnahme, wenn Sie die zahlreichen Java-Systemausnahmen zurückwerfen wollen (daher die CCException im folgenden Code)

Hier ist ein alter java1.4-Code, der diese Punkte berücksichtigt:

/**
 * 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;
}

14voto

Amir Fo Punkte 3901

Indizierung (schneller)

Sie können verwenden FunctionalInterface um Methoden in einem Container zu speichern, um sie zu indizieren. Sie können Array-Container verwenden, um sie über Zahlen aufzurufen, oder Hashmap, um sie über Strings aufzurufen. Mit diesem Trick können Sie Ihre Methoden indizieren, um sie dynamisch aufzurufen schneller .

@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-Syntax

Sie können auch die Lambda-Syntax verwenden:

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

12voto

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

12voto

chickeninabiscuit Punkte 8605
Object obj;

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

method.invoke(obj, null);

10voto

Wenn Sie den Aufruf mehrmals durchführen, können Sie die in Java 7 eingeführten neuen Methodenhandles verwenden. Hier geht es um Ihre Methode, die einen String zurückgibt:

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]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X