2011-01-22 23 views
47

Chciałbym wywołać prywatną metodę statyczną. Mam swoją nazwę. Słyszałem, że można to zrobić za pomocą mechanizmu refleksji Java. Jak mogę to zrobić?Jak wywołać prywatną metodę statyczną za pomocą refleksji (Java)?

EDYCJA: Jednym z problemów napotkanych podczas próby wywołania metody jest określenie typu jej argumentu. Moja metoda otrzymuje jeden argument, a jej typ to Map. Dlatego nie mogę wykonać Map<User, String>.TYPE (w czasie wykonywania nie ma czegoś takiego jak Map z powodu usunięcia typu Java). Czy istnieje inny sposób uzyskania tej metody?

+1

try 'MyClass.class.getDeclaredMethod ("myMethod" Map.class);' Twoim przypadku – Cratylus

+0

Zabawne rodzajową informacja o metodzie wciąż jest dostępna w czasie wykonywania. 'Method.getGenericParameterTypes' –

Odpowiedz

79

Powiedzmy chcesz zadzwonić MyClass.myMethod (int x);

Method m = MyClass.class.getDeclaredMethod("myMethod", Integer.TYPE); 
m.setAccessible(true); //if security settings allow this 
Object o = m.invoke(null, 23); //use null if the method is static 
+0

Dzięki. Moja metoda otrzymuje jeden parametr, a jej typ to Mapa . Dlatego nie mogę zrobić "Mapuj .TYPE". Czy istnieje inny sposób uzyskania tej metody? – snakile

+6

@snakile: spróbuj 'MyClass.class.getDeclaredMethod („myMethod”, Map.class)' w Twoim przypadku – Cratylus

+3

Wszystko uczono w Akademii było kłamstwo ... – rsy

0
Object insecure; //This needs to be an initialized reference 

Class c = insecure.getClass(); 
Method m = c.getMethod(name, parameterTypes); //Fill the name and types in 
m.setAccessible(true); 
m.invoke(insecure, parameters); //Fill in the parameters you would like 

Istnieje kilka sprawdzonych wyjątków, które mogą zostać wyrzucone. Zarówno parametrTypes, jak i parametry są argumentami elipsy (o zmiennej długości), należy je wypełnić w razie potrzeby. JVM według specyfikacji ma silnie typowaną konwencję wywoływania, więc musisz znać typy parametrów.

Z powiedział, że chyba piszesz jakiś kontener aplikacji składowej pojemnika serwera, RMI podobnego systemu lub JVM oparte biuletynie nie należy tego robić.

9

Invoke główny z reflection tutorial

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.Arrays; 

public class InvokeMain { 
    public static void main(String... args) { 
    try { 
     Class<?> c = Class.forName(args[0]); 
     Class[] argTypes = new Class[] { String[].class }; 
     Method main = c.getDeclaredMethod("main", argTypes); 
     String[] mainArgs = Arrays.copyOfRange(args, 1, args.length); 
     System.out.format("invoking %s.main()%n", c.getName()); 
     main.invoke(null, (Object)mainArgs); 

     // production code should handle these exceptions more gracefully 
    } catch (ClassNotFoundException x) { 
     x.printStackTrace(); 
    } catch (NoSuchMethodException x) { 
     x.printStackTrace(); 
    } catch (IllegalAccessException x) { 
     x.printStackTrace(); 
    } catch (InvocationTargetException x) { 
     x.printStackTrace(); 
    } 
    } 
} 
2

Nie, nie można powiedzieć Map<K,V>.class. Jest to spowodowane usunięciem typu . W czasie wykonywania nie ma czegoś takiego.

Na szczęście możesz można powiedzieć po prostu stary Map.class. Tak samo jest w środowisku uruchomieniowym.

Jeśli ostrzeżenia przeszkadza, szukać innych pytań związanych z leków generycznych i rodzaj skasowaniem, tam jest mnóstwo informacji na ten temat tutaj.

+0

+1 za wykreślenie typu wymazania – snakile

1

używam jednej metody, która zamyka coraz metodę docelową, a następnie powołując go. Oczywiście ma oczywiście pewne ograniczenia. Oto sposób umieścić w klasie, a jego testy JUnit:

public class Invoker { 
/** 
* Get method and invoke it. 
* 
* @author jbetancourt 
* 
* @param name of method 
* @param obj Object to invoke the method on 
* @param types parameter types of method 
* @param args to method invocation 
* @return return value 
* @throws Exception for unforseen stuff 
*/ 
public static final <T> Object invokeMethod(final String name, final T obj, 
    final Class<?>[] types, final Object... args) throws Exception { 

    Method method = obj.getClass().getDeclaredMethod(name, types); 
    method.setAccessible(true); 
    return method.invoke(obj, args); 
} 

/** 
* Embedded JUnit tests. 
*/ 
@RunWith(JUnit4.class) 
public static class InvokerTest { 
    /** */ 
    @Test 
    public void testInvoke() throws Exception { 
     class TestTarget { 
      private String hello() { 
       return "Hello world!"; 
      } 
     } 

     String actual = (String) Invoker.invokeMethod("hello", 
       new TestTarget(), new Class<?>[] {}); 
     String expected = "Hello world!"; 
     assertThat(actual, is(expected)); 

    } 
} 

}

Powiązane problemy