предисловие
Ребята, вы знаете, что такое отражение в Java? Это не наоборот.
Отражение — это механизм Java, обычно также называемый механизмом отражения.В этой статье будет рассказано о том, что такое механизм отражения и как его использовать.
Пожалуйста, дайте сначала третью роту второму мастеру, а потом читайте дальше, спасибо.
Давайте посмотрим немного волшебства
public class Test {
private static void changeStrValue(String str, char[] value) {
// 只要执行魔法代码就可以达到下面的效果
// 施展魔法的代码稍后揭秘
}
public static void main(String[] args) {
changeStrValue("abc", new char[]{'d','e','f'});
String abc = "abc";
System.out.println("abc");
System.out.println(abc);
System.out.println("abc".equals(abc));
}
}
Это был первый раз, когда второй мастер увидел этот результат выполнения и подумал, что это очень интересно. Должно быть "abc", как оно может стать "def"?那是因为有一段神奇的代码,下文将会揭秘,只要接着读下去你就会明白了。
Каков рефлекторный механизм?
Механизм отражения Java означает, что в рабочем состоянии программы может быть сконструирован объект любого класса, класс, которому принадлежит любой объект, переменные-члены и методы любого класса, а также вызов любого объекта, свойства и методы. Эта функция динамического получения программной информации и динамического вызова объектов называется механизмом отражения языка Java. Отражение рассматривается как ключ к динамическим языкам.
Выше приведено объяснение энциклопедии. Это может быть немного абстрактно, а затем увидеть второй мастер для васобъявитьсяобъяснять.
Построить объект любого класса
В общем, если мы хотим создать объект класса, мы должны использовать ключевое слово new. Но в таких средах, как Spring, нам нужно только настроить имя класса, чтобы получить экземпляр класса. Как он это сделал?
import java.util.List;
public class Test {
/**
* 根据类名取得类实例
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param className
* @param <T>
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static <T> T getInstance(String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Class<T> clazz = (Class<T>) Class.forName(className);
return clazz.newInstance();
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
List<String> list = getInstance("java.util.ArrayList");
list.add("abc");
list.add("def");
for (String v : list) {
System.out.println(v);
}
}
}
Имя класса можно получить из конфигурационного файла во время работы программы или даже получить из сети, а затем динамически создать экземпляр класса.
Знать, к какому классу принадлежит любой объект
import java.util.ArrayList;
public class Test {
/**
* 打印对象的类名
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param o
*/
public static void printClass(Object o) {
System.out.printf(o.getClass().getName());
}
public static void main(String[] args) {
printClass(new ArrayList<>());
}
}
Понимать переменные-члены и методы любого класса
Мы вообще хотим использовать класс, мы должны сначала узнать какие там методы и свойства, сначала понять, а потом использовать. Но почему такой фреймворк, как Spring, может автоматически внедрить его для нас? Откуда он знает, какие свойства у нас есть в объекте?
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
/**
* 打印类的属性
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param clazz
*/
public static void printFields(Class clazz) {
System.out.println(clazz.getName() + "包含如下属性:");
for (Field f : clazz.getDeclaredFields()) {
System.out.println(f);
}
}
/**
* 打印类的方法
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param clazz
*/
public static void printMethods(Class clazz) {
System.out.println(clazz.getName() + "包含如下方法:");
for (Method m : clazz.getDeclaredMethods()) {
System.out.println(m);
}
}
public static void main(String[] args) {
printFields(MyClass.class);
printMethods(MyClass.class);
}
}
class MyClass {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Вызов свойств и методов любого объекта
Фреймворки, такие как Spring, могут быть внедрены, даже если свойство является закрытым и не имеет метода установки.
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
/**
* 调用一个对象的方法
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param o
* @param methodName
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
public static void callMethod(Object o, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method m = o.getClass().getDeclaredMethod(methodName);
m.setAccessible(true);
m.invoke(o);
}
/**
* 修改一个对象的属性
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param o
* @param fieldName
* @param value
* @throws IllegalAccessException
*/
public static void changeFieldValue(Object o, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field f = o.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(o, value);
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException {
MyClass o = new MyClass();
// 修改任意属性,即使是私有的
changeFieldValue(o, "name", "二当家的白帽子");
// 调用任意方法,即使是私有的
callMethod(o, "printName");
}
}
class MyClass {
// 私有属性,只可以调用set方法修改
private String name;
private void printName() {
// 私有方法,只有本类自己的实例可以调用
System.out.println("My name is " + name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Магия раскрыта
Пришло время разгадать, что такое магия на самом деле, и да, использование рефлексов тоже.
import java.lang.reflect.Field;
public class Test {
/**
* 修改字符串内部的值
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
* @param str
* @param value
*/
private static void changeStrValue(String str, char[] value) {
try {
Field f = str.getClass().getDeclaredField("value");
f.setAccessible(true);
f.set(str, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
changeStrValue("abc", new char[]{'d','e','f'});
// 这里的"abc"字符串和上面调用changeStrValue的参数"abc"会指向同一块内存
String abc = "abc";
System.out.println("abc");
System.out.println(abc);
System.out.println("abc".equals(abc));
}
}
Чтобы понять этот код, помимо механизма отражения, вам также необходимо понять, как java обрабатывает строки. «Пул строковых констант» выходит за рамки этой статьи и является отдельной темой, поэтому я не буду говорить об этом в этой статье.
Исходное содержимое строки — «abc», мы не можем изменить это содержимое в обычных условиях, поскольку String — это инвариантный класс. Но отражение Дафа может разрушить все табу.
конец
Обычные программы могут не нуждаться в написании кода отражения. Но с такой структурой, как Spring, я действительно не могу понять, как это сделать без размышлений. Даже если размышления никогда не понадобятся, понимание механики принесет нам большую пользу.