Класс java.lang.reflect.Method предоставляет информацию об одном методе класса или интерфейса и доступ к нему. Для получения информации о методах и управления ими класс Method
определеяет ряд методов. Отмечу основные из них:
String getName(): возвращает имя метода
Class[] getExceptionTypes(): возвращает генерируемые методом типы исключений в виде массива объектов Class
int getModifiers(): возвращает целое число с различными включенными и выключенными битами, которые описывают используемые модификаторы.
int getParameterCount(): возвращает количество параметров
Class[] getParameterTypes(): возвращает типы параметров метода
Class getReturnType(): возвращает тип возвращаемого значения метода
Object invoke(Object obj, Object... args): вызывает метод, представленный этим объектом метода, для указанного объекта с указанными параметрами.
Для получения методов типа применяется ряд методов класса Class:
Method[] getMethods(): возвращает массив объектов Method для открытых методов (с модификатором public) данного класса или его суперклассов
Method[] getDeclaredКласс java.lang.reflect.Methods(): возвращает массив объектов Method для всех методов данного класса. Метод возвращают массив нулевой длины, если таких методов нет или если объект
представляет собой примитивный тип или массив.
Method getMethod(String name, Class... parameterTypes): возвращает объект Method для публичного метода, имя которого передается в качестве параметра. Второй параметр указывает на типы параметров метода. Поиск также идет среди методов суперклассов. Если подобное публичный метод отсутствует, то метод генерирует исключение NoSuchMethodException
Method getDeclaredMethod(String name, Class... parameterTypes): возвращает объект Method для метода, имя которого передается в качестве параметра. Второй параметр указывает на типы параметров метода. Если подобный метод отсутствует, то метод генерирует исключение NoSuchMethodException
Например, получим все методы некоторого класса:
import java.lang.reflect.*;
public class Program{
public static void main(String[] args) {
Class cl = Operation.class;
Method[] methods = cl.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
}
}
class Operation{
static int sum(int val1, int val2){
return val1 + val2;
}
static double sum(double val1, double val2){
return val1 + val2;
}
static int subtract(int val1, int val2){
return val1 - val2;
}
}
В данном случае получаем методы класса Operation. И консоль должна нам вывести следующие строки:
static int Operation.sum(int,int) static double Operation.sum(double, double) static int Operation.subtract(int,int)
Исследуем метод sum из выше определенного класса Operation:
import java.lang.reflect.*;
public class Program{
public static void main(String[] args) {
Class cl = Operation.class;
try{
// получаем метод sum с двумя параметрами типа int
Method m = cl.getDeclaredMethod("sum", int.class, int.class);
// получаем имя метода
String methodName = m.getName();
// получаем модификаторы
String modifiers = Modifier.toString(m.getModifiers());
// получаем количество параметров
int paramsCount = m.getParameterCount();
// получаем возвращаемый тип
Class retType = m.getReturnType();
// получаем типы параметров
Class[] paramTypes = m.getParameterTypes();
// выводим информацию о методе
System.out.print(modifiers + " " + retType.getName() + " " + methodName + "(");
for (int j = 0; j < paramsCount; j++)
{
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
catch(Exception ex){
System.out.println(ex);
}
}
}
class Operation{
static int sum(int val1, int val2){
return val1 + val2;
}
static double sum(double val1, double val2){
return val1 + val2;
}
static int subtract(int val1, int val2){
return val1 - val2;
}
}
В данном случае получаем метод sum, который принимает два параметра типа int:
Method m = cl.getDeclaredMethod("sum", int.class, int.class);
Далее последовательно получаем имя, возвращаемый тип, модификаторы и типы параметров метода и выводим их на консоль. В итоге консоль должна нам вывести следующую строку:
static int sum(int, int);
Для вызова метода в классе Method определен метод invoke():
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, InvocationTargetException
Первый параметр (obj) представляет объект, для которого будет вызываться метод. Если вызываемый метод статический, то параметр obj игнорируется.
Второй параметр (args) представляет аргументы, передаваемые вызываемому методу. Если вызываемый
метод не принимает никаких параметров, то параметр args опускается.
Возвращаемое значение - это результат вызываемого метода.
Вызовем статический метод sum класса Operation:
import java.lang.reflect.*;
public class Program{
public static void main(String[] args) {
Class cl = Operation.class;
try{
// получаем метод sum с двумя параметрами типа int
Method m = cl.getDeclaredMethod("sum", int.class, int.class);
int val1 = 23;
int val2 = 4;
// вызываем метод и получаем результат
int result = (int) m.invoke(null, val1, val2);
System.out.printf("sum(%d, %d) = %d\n", val1, val2, result); // sum(23, 4) = 27
}
catch(Exception ex){
System.out.println(ex);
}
}
}
class Operation{
static int sum(int val1, int val2){
return val1 + val2;
}
static int subtract(int val1, int val2){
return val1 - val2;
}
}
Поскольку вызываемый метод sum - статический, то в качестве первого параметра передается null:
int result = (int) m.invoke(null, val1, val2);
Результаи преобразуется к типу int, так как мы значем, что метод должен возвратить значение этого типа. Консольный вывод программы:
sum(23, 4) = 27
Рассмотрим вызов нестатического метода:
import java.lang.reflect.*;
public class Program{
public static void main(String[] args) {
// объект, для которого будет вызываться метод
Person tom = new Person("Tom");
Class cl = tom.getClass();
try{
// получаем метод setName с параметром типа String
Method m = cl.getDeclaredMethod("setName", String.class);
// новое имя
String name = "Eugene";
// вызываем метод
m.invoke(tom, name);
tom.print(); // Person Eugene
}
catch(Exception ex){
System.out.println(ex);
}
}
}
class Person {
private String name;
void setName(String name){ this.name = name; }
Person(String name){ this.name = name; }
void print(){
System.out.println("Person " + name);
}
}
В данном случае для объекта Person вызываем метод setName(), который изменяет значение поля name.
Как и в случае с полями и конструкторами, механизм рефлексии Java запрещает обращение к приватным методам (определенным с модификатором private). В этом случае для доступа к методу
необходимо сделать его доступным с помощью метода setAccessible(), передав в него true:
import java.lang.reflect.*;
public class Program{
public static void main(String[] args) {
Person tom = new Person("Tom");
Class cl = tom.getClass();
try{
Method m = cl.getDeclaredMethod("setName", String.class);
m.setAccessible(true); // открываем доступ к методу
String name = "Eugene";
m.invoke(tom, name);
tom.print(); // Person Eugene
}
catch(Exception ex){
System.out.println(ex);
}
}
}
class Person {
private String name;
// приватный метод
private void setName(String name){ this.name = name; }
Person(String name){ this.name = name; }
void print(){
System.out.println("Person " + name);
}
}