Funktion dynamisch aufrufen

timestamp

Mitglied Käsekuchen
Hey Forum,

ich wollte wissen ob es möglich ist in Java eine Funktion dynamisch aufzurufen. In PHP gibt es dafür die Funktion call_user_func(). Gibt es so eine Möglichkeit auch in Java oder muss ich da mit if-bedingungen ein Workaround basteln?
 
Hallo,

für sowas nutzt man in der Regel Reflection:
Java:
package de.tutorials;

import java.lang.reflect.Method;


public class DynamicCallExample {
	public static void main(String[] args) throws Exception{
		SomeObject o = new SomeObject();
		
		o.getClass().getDeclaredMethod("op").invoke(o);
		o.getClass().getDeclaredMethod("op1", String.class).invoke(o,"Hallo");
		System.out.println(o.getClass().getDeclaredMethod("op2",int.class,int.class).invoke(o,new Object[]{3,4}));
		System.out.println(o.getClass().getDeclaredMethod("op2",new Class[]{double.class,Double.class}).invoke(o,3.1,4.1));
		
		SomeObject.class.getMethod("op3").invoke(null);
		
		Method op4Method = o.getClass().getDeclaredMethod("op4");
		op4Method.setAccessible(true);
		op4Method.invoke(o);
	}
	
	static class SomeObject{
		
		public void op(){
			System.out.println("op");	
		}
		
		public void op1(String param){
			System.out.println("op1: " + param);	
		}
		
		public int op2(int a, int b){
			int sum = a+b;
			System.out.println("op2_int: " + sum);
			return sum;
		}
		
		public double op2(double a, Double b){
			double sum = a+b;
			System.out.println("op2_double: " + sum);
			return sum;
		}
		
		public static void op3(){
			System.out.println("op3");
		}
		
		private void op4(){
			System.out.println("op4");
		}
		
	}
}

Ausgabe:
Code:
op
op1: Hallo
op2_int: 7
7
op2_double: 7.199999999999999
7.199999999999999
op3
op4

Gruß Tom
 
Hi
Vielen Dank, dass hat mir schonmal sehr weitergeholfen. Ich habe deinen Beispielcode mal ein wenig an meine Bedürfnisse angepasst:
Java:
public void call_user_func(String className, String methodName){
	this.call_user_func(className, methodName, null, null);		
}
public void call_user_func(String className, String methodName, Class[] types, Object[] params){
	try{
		Class c = Class.forName(className);												
		Constructor ct = c.getConstructor();               
        c.getDeclaredMethod(methodName,types).invoke(ct.newInstance(),params);                    
	}
	catch(Exception e){
		e.printStackTrace();
	}
}

Als Testklasse nutze ich folgende:
Java:
public class TestClass {
	public int mySecretNumber;
	public TestClass(){
		this.mySecretNumber = 5;
	}
	public TestClass(int i){
		this.mySecretNumber = i;
	}
	public void TestFunction(){
		System.out.println(this.mySecretNumber);
		return;
	}
	public void TestFunction(int i){
		System.out.println(i);
	}
}

Folgender Code funktioniert einwandfrei:
Java:
Test test = new Test();		
test.call_user_func("TestClass", "TestFunction"); //Gibt 5 aus
Class[] types	= {int.class};
Object[] params = {42};
test.call_user_func("TestClass", "TestFunction", types, params ); //Gibt 42 aus

Ich würde nun noch gerne ein Objekt statt einem Klassennamen an die Funktion übergeben und dann eine Methode davon ausführen. Leider war keiner meiner Ansätze erfolgreich:
Java:
public void call_user_func(Class c, String methodName){
	try{													
		c.getClass().getMethod(methodName, null).invoke(c);
	}
	catch(Exception e){
		e.printStackTrace();
	}
}


//Aufruf:
TestClass tc = new TestClass(17);				
test.call_user_func(tc, "TestFunction");

Dies erzeugt den Fehler:
The method call_user_func(Class, String) in the type Test is not applicable for the arguments (TestClass, String)

Wenn ich im Funktionsheader TestClass als Typ des ersten Parameters angebe funktioniert es einwandfrei, verliert dann aber leider die Dynamik. Gibt es dafür auch eine Lösung?
 
Statt Class Object nutzen, da du ja ein Objekt übergeben willst und keine Klasse ;)

Java:
public void call_user_func(Object o, String methodName) {
  try {
    o.getClass().getMethod(methodName, null).invoke(o);
  } catch (Exception ex) {
    ex.printStackTrace();
  }
}
 
Vielen Dank für euere Antworten. Herausgekommen ist dabei Folgendes:
Java:
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public abstract class MethodCaller {
	public static Object execute(Object o, String methodName){	
		return MethodCaller.execute(o, methodName, null, null);
	}
	public static Object execute(Object o, String methodName, Class<?>[] types, Object[] params){
		Object ret = null;
		try{
			ret = o.getClass().getMethod(methodName, types).invoke(o, params);			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		return ret;
	}
	
	public static Object execute(String className, String methodName){
		return MethodCaller.execute(className, methodName, null, null);		
	}
	public static Object execute(String className, String methodName, Class<?>[] types, Object[] params){
		Object ret = null;
		try{			
			Class<?> c = Class.forName(className);
			boolean b = Modifier.isStatic(c.getDeclaredMethod(methodName).getModifiers());
			if( b ){				  
				ret = c.getDeclaredMethod(methodName, types).invoke(null, params);
			}
			else{
				Constructor<?> ct = c.getConstructor();                      
				ret = c.getDeclaredMethod(methodName,types).invoke(ct.newInstance(),params);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		return ret;
	}
}

Java:
//Object o => Zu übergebenes Objekt einer Klasse
//String methodName =>  Name der Methode
//String className => Namer der Klasse, zu der die Methode gehört
//Class<?>[] types => Die Typen der übergebenen Parameter, in gleicher Reihenfolge
//Object[] params => Die Parameter für die Methode

//Geben den Rückgabewert der jeweiligen Methode zurück

Object execute(Object o, String methodName)
Object execute(Object o, String methodName, Class<?>[] types, Object[] params)
Object execute(String className, String methodName)
Object execute(String className, String methodName, Class<?>[] types, Object[] params)

Habt ihr da noch Verbesserungen/Ergänzungen zu?
 
Zurück