Рефлексия — это механизм, который позволяет программе получать информацию о своей собственной структуре и поведении во время выполнения, включая классы, методы, поля и другие элементы. Это позволяет программе динамически создавать и манипулировать объектами, вызывать методы и получать доступ к полям, не зная заранее их имен или типов. Рефлексия широко используется в таких областях, как тестирование, отладка и создание фреймворков и библиотек
Использование рефлексии
Рефлексия в Java может быть использована для различных целей, таких как динамическое создание и манипулирование объектами, вызов методов и доступ к полям классов без знания их имен или типов заранее, получение доступа к приватным полям
Класс, с которым будем работать
public class Test {
private String value;
private Test(String value) {
this.value = value;
}
public Test() {}
public String getValue() {
return value;
}
private void setValue (String value) {
this.value = value;
}
public String toString() {
return "Test{value='" + value + "'}";
}
}
Получение списка полей и методов
public class Main {
public static void getClassInfo (Object obj) {
Class<?> aClass = obj.getClass(); // Class Test
Method[] methods = aClass.getDeclaredMethods(); // [public java.lang.String Test.getValue()]
Field[] fields = aClass.getFields();// []
Field[] declaredFields = aClass.getDeclaredFields(); // [private java.lang.String Test.value]
Constructor<?>[] constructors = aClass.getConstructors(); // [public Test()]
System.out.println(aClass);
System.out.println(Arrays.tostring(methods));
System.out.println(Arrays.toString (fields));
System.out.println(Arrays.toString(declaredFields));
System.out.println(Arrays.toString(constructors));
}
public static void main (String[] args) {
var test = new Test();
getClassInfo(test);
}
}
Получение доступа к приватным полям
class Main {
public static void setPrivateValue(Object obj, String fieldName, String newValue) {
Class<?> aClass = obj.getclass();
try {
Field field = aClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, newValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main (String[] args) {
var test = new Test();
System.out.println(test);
setPrivateValue(test, "value", "newValue");
System.out.printin(test);
}
}
Вызов конструкторов
class Main {
public static Test createTestobjectWithValue(String value) {
try {
var constructor = Test.class.getDeclaredConstructor(String.class); // Получение конструктора класса
constructor.setAccessible(true); // Изменение прав доступа к метода
return constructor.newInstance(value); // Создание нового объекта
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main (String[] args) {
var test = createTestObjectwithValue("newvalue");
System.out.println(test); //=> Test {value= 'newValue'}
}
}
Вызов метода по имени
class App {
public static void callPrivateMethod(Object obj, String methodName, String parameter) {
Class<?> aClass = obj.getClass();
try {
Method method = aClass.getDeclaredMethod(methodName, String.class)
method.setAccessible(true);
method.invoke(obj, parameter);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
public static void main (String[] args) {
var test = new Test();
System.out.println(test); //=> Test{value=null)
callPrivateMethod(test, "setValue", "newValue");
System.out.println(test); //=> Test{value=newValue)
}
}
Аннотации
Определение собственной аннотации
@Retention(RetentionPolicy.RUNTIME) // Видимость аннотации: SOURCE, CLASS, RUNTIME
@Target (ElementType.METHOD) // Типы аннотируемых элементов: TYPE, FIELD, METHOD, PARAMETER и пр.
public @interface Cmd {
String name(); // Параметры аннотаций
String description();
}
Использование созданной аннотации
public class Commands {
private final Map<String, String> availableCommands;
public Commands() {
this.availableCommands = new HashMap<>();
var methods = this.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Cmd.class)) {
Cmd cmdInfo = method.getAnnotation(Cmd.class);
availableCommands.put(cmdInfo.name(), cmdInfo.description());
}
}
}
@Cmd(name = "Exit", description = "ExitApplication")
public void exit() {
System.out.println("exit");
}
@Cmd (name = "Help", description = "Show all available commands")
public void printHelp() {
StringBuilder builder = new StringBuilder();
availableCommands.forEach((key, value) -> builder.append(key).append(": ").append(value).append("\n"));
System.out.println(builder);
}
}
class Main {
public static void main (String[] args) {
var commands = new Commands();
commands.printHelp();
}
}
Дополнительные материалы

Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.