Reflection API в Java. Класс Method. Часть 3
Данная статья:
- написана командой Vertex Academy. Надеемся, что она Вам будет полезна. Приятного прочтения!
- это одна из статей из нашего "Самоучителя по Java"
- Данная статья предполагает, что Вы уже хорошо знаете ООП.
Эта статья является ответвлением от статьи Reflection API в Java, Часть 1, где мы узнали как получить Method из класса Class.
В этой статье вы узнаете как работать с классом Method.
Класс Method
Класс Method предоставляет возможность:
- получить название метода, его модификаторы, тип возвращаемого значения и входящих параметров
- получить аннотации метода, бросаемые исключения и другую информацию
- вызвать метод, даже приватный
Для начала, создадим класс Car
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package com.vertex.reflection; import jdk.jfr.Description; class Car { private int horsepower; private final String serialNumber; public Car(int horsepower, String serialNumber) { this.horsepower = horsepower; this.serialNumber = serialNumber; } @Description("the power of an engine") public final int getHorsepower() { return horsepower; } public void setHorsepower(int horsepower) { this.horsepower = horsepower; } public String getSerialNumber() { return serialNumber; } private void startEngine() { System.out.println("Wroooommmm"); } public <T> T logAndReturn(@Deprecated T type) throws IllegalAccessException { System.out.println(type); return type; } public <T extends RuntimeException> void exceptionExample() throws T { } } |
Пример 1 Получение названия метода
1 2 3 4 5 6 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method getHorsepowerMethod = carClass.getMethod("getHorsepower"); System.out.println(getHorsepowerMethod.getName()); //output: getHorsePower |
Пример 2 Получение модификаторов метода
С методами история та же, что и с полями. Для работы с модификаторами метода необходимо воспользоваться методами класса Modifiers
1 2 3 4 5 6 7 8 9 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method getHorsepowerMethod = carClass.getMethod("getHorsepower"); int modifiers = getHorsepowerMethod.getModifiers(); System.out.println(Modifier.isPublic(modifiers)); //output: true System.out.println(Modifier.isFinal(modifiers)); //output: true System.out.println(Modifier.isVolatile(modifiers)); //output: false |
Пример 3 Получение типа возвращаемого значения
1 2 3 4 5 6 7 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method getHorsepowerMethod = carClass.getMethod("getHorsepower"); System.out.println(getHorsepowerMethod.getReturnType()); //output: int System.out.println(getHorsepowerMethod.getGenericReturnType()); //output: int |
Метод getGenericReturnType возвращает параметризованный тип. Лучше всего это видно на следующем примере
1 2 3 4 5 6 7 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method logAndReturnMethod = carClass.getMethod("logAndReturn", Object.class); System.out.println(logAndReturnMethod.getReturnType()); //output: class java.lang.Object System.out.println(logAndReturnMethod.getGenericReturnType()); //output: T |
Реальный тип возвращаемого значения будет Object т.к. во время исполнения все дженерики являются Object. А вот genericReturnType будет T, как раз тот тип, что мы указали в методе logAndReturn().
Пример 4 Получение аннотаций метода
Для получения аннотаций метода существуют методы : getAnnotations() и getDeclaredAnnotations(), getAnnotationsByType() и getDeclaredAnnotationsByType(), getAnnotation() и getDeclaredAnnotation()
Но, пары методов getAnnotations() и getDeclaredAnnotations(), getAnnotationsByType() и getDeclaredAnnotationsByType(), getAnnotation() и getDeclaredAnnotation() делают одно и то же. Как пример, javadoc для getDeclaredAnnotation():
1 2 3 |
// Only annotations on classes are inherited, for all other // objects getDeclaredAnnotation is the same as // getAnnotation. |
Поэтому мы рассмотрим только несколько из них.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method getHorsepowerMethod = carClass.getMethod("getHorsepower"); Annotation[] annotations = getHorsepowerMethod.getAnnotations(); System.out.println(Arrays.toString(annotations)); //output: [@jdk.jfr.Description(value="the power of an engine")] Description[] annotationsByType = getHorsepowerMethod.getAnnotationsByType(Description.class); System.out.println(Arrays.toString(annotationsByType)); //output: [@jdk.jfr.Description(value="the power of an engine")] Description descriptionAnnotation = getHorsepowerMethod.getAnnotation(Description.class); System.out.println(descriptionAnnotation); //output: @jdk.jfr.Description(value="the power of an engine") |
- getAnnotations() возвращает массив аннотаций метода
- getAnnotation() возвращает аннотацию по типу
- getAnnotationsByType() возвращает массив аннотаций по типу. Метод был добавлен в Java 8 вместе с @Repeatable аннотациями
Пример 5 Получение входящих параметров
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method logAndReturnMethod = carClass.getMethod("logAndReturn", Object.class); System.out.println(logAndReturnMethod.getParameterCount()); //output: 1 Parameter[] parameters = logAndReturnMethod.getParameters(); System.out.println(Arrays.toString(parameters)); //output: [T arg0] Class<?>[] parameterTypes = logAndReturnMethod.getParameterTypes(); System.out.println(Arrays.toString(parameterTypes)); //output: [class java.lang.Object] Type[] genericParameterTypes = logAndReturnMethod.getGenericParameterTypes(); System.out.println(Arrays.toString(genericParameterTypes)); //output: [T] TypeVariable<Method>[] typeParameters = logAndReturnMethod.getTypeParameters(); System.out.println(Arrays.toString(typeParameters)); //output: [T] Annotation[][] parameterAnnotations = logAndReturnMethod.getParameterAnnotations(); System.out.println(Arrays.deepToString(parameterAnnotations)); //output: [[@java.lang.Deprecated(forRemoval=false, since="")]] |
- getParameterCount() возвращает количество входящих параметров
- getParameters() возвращает массив всех входящих параметров в виде класса Parameter
- getParameterTypes() возвращает массив типов входящих параметров в виде класса Class
- getGenericParameterTypes() возвращает массив дженерик входящих типов параметров.
- getTypeParameters() возвращает массив дженериков входящих типов в виде класса TypeVariable
- getParameterAnnotations() возвращает массив аннотаций входящих параметров
Пример 6 Получение бросаемых исключений
1 2 3 4 5 6 7 8 9 10 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method exceptionExampleMethod = carClass.getMethod("exceptionExample"); Class<?>[] exceptionTypes = exceptionExampleMethod.getExceptionTypes(); System.out.println(Arrays.toString(exceptionTypes)); //output: [class java.lang.RuntimeException] Type[] genericExceptionTypes = exceptionExampleMethod.getGenericExceptionTypes(); System.out.println(Arrays.toString(genericExceptionTypes)); //output: [T] |
- getExceptionTypes() возвращает массив типов исключений, которые могут быть потенциально брошены методом
- getGenericExceptionTypes() возвращает массив дженериков, которые могут быть потенциально брошены методом
Пример 7 Получение дополнительной информации
1 2 3 4 5 6 7 8 9 10 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method getHorsepowerMethod = carClass.getMethod("getHorsepower"); System.out.println(getHorsepowerMethod.getDeclaringClass()); //output: class com.vertex.reflection.Car System.out.println(getHorsepowerMethod.isSynthetic()); //output: false System.out.println(getHorsepowerMethod.isBridge()); //output: false System.out.println(getHorsepowerMethod.isDefault()); //output: false System.out.println(getHorsepowerMethod.isVarArgs()); //output: false |
- getDeclaringClass() возвращает класс, в котором объявлено поле
- isSynthetic() возвращает true, если метод был создан компилятором, а не разработчиком
- isBridge() возвращает true, если метод является bridge-методом по Java Language Specification (JLS)
- isDefault() возвращает true, если метод является методом по умолчанию по JLS
- isVarArgs() возвращает true, если во входящих параметрах метода присутствует varargs
Пример 8 Вызов public метода
Для вызова метода с помощью рефлексии существует метод invoke() который принимает объект на котором будет вызываться этот метод и vararg список входящих параметров
1 2 3 4 5 6 7 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method getHorsepowerMethod = carClass.getMethod("getHorsepower"); Object resultValue = getHorsepowerMethod.invoke(car); System.out.println(resultValue); //output: 100 |
Вызов метода с параметрами выглядит так
1 2 3 4 5 6 7 8 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method setHorsepowerMethod = carClass.getMethod("setHorsepower", int.class); System.out.println("Before change: " + car.getHorsepower()); //output: 100 setHorsepowerMethod.invoke(car, 350); System.out.println("After change: " + car.getHorsepower()); //output: 350 |
Пример 9 Вызов private метода
Как мы уже знаем, доступ ко всему приватному требует вызова setAccessible(true), методы не являются исключением
1 2 3 4 5 6 |
Car car = new Car(100, "AA180A1"); Class<? extends Car> carClass = car.getClass(); Method startEngineMethod = carClass.getDeclaredMethod("startEngine"); startEngineMethod.setAccessible(true); startEngineMethod.invoke(car); //output: Wroooommmm |
На этом урок заканчивается
В этом уроке мы узнали:
- как получить название метода, его модификаторы, тип возвращаемого значения и входящих параметров
- как получить аннотации метода, бросаемые исключения и другую информацию
- как вызвать метод, в том числе приватный
Спасибо, что были с нами! 🙂
Надеемся, что наша статья была Вам полезна. Можно записаться к нам на курсы по Java на сайте.