java 反射

反射就是根据类的字节码 class 文件获取一个类的细节,包括构建出来,通过对象去调用方法,访问属性。

生活中的反射:听声辨人

为什么要用反射
- 可将要创建的对象,要调用的方法写到配置文件,然后通过反射来完成方法调用,从而降低代码的耦合性
- 基本上任何一个框架设计都会用到反射,很重要。

反射调用方法的实现步骤:
1、获取类的字节码
2、通过字节码去创建对象
3、反射得到要调用的方法对象method
4、通过反射调用方法

src/main/resources/test.xml

<?xml version="1.0" encoding="UTF-8" ?>
<students>
    <student number="001">
        <Name>张三</Name>
        <Age>18</Age>
        <Sex>男</Sex>
    </student>
    <student number="002">
        <Name>李四</Name>
        <Age>19</Age>
        <Sex>女</Sex>
    </student>
    <student number="003">
        <Name>王五</Name>
        <Age>20</Age>
        <Sex>未知</Sex>
    </student>
</students>
package com.zhuchun.stu;


import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;


/**
* @Auther: zhuchun92@163.com
* @Date: 2020年03月26日 0:59
*/
public class TestReflect {
    public static void main(String[] args) throws Exception {
        /*
        反射调用方法的实现步骤:
            1、获取类的字节码
            2、通过字节码去创建对象
            3、反射得到要调用的方法对象method
            4、通过反射调用方法
         */


        // 获取类的字节码
        // 方式一:
        Class<Student> studentClass = Student.class;
        // 方式二:
        Class<Student> studentClass1 = (Class<Student>) Class.forName("com.zhuchun.stu.Student");


        // 通过字节码调用newInstance方法创建对象,底层其实是调用字节码对应类中的默认构造函数
        Student student = studentClass.newInstance();


        // 通过反射获取该类所有 public 方法
        Method[] methods = studentClass.getMethods();  // 获取当前类中的所有 public 方法
        for (Method me : methods){
            System.out.println(me.getName());       // 打印该类中所有 public 方法
        }
        // 通过反射获取我们要调用的方法
        Method method = studentClass.getMethod("setName", String.class);
        // 通过反射,完成方法调用
        method.invoke(student,"张三");
        // 通过 getName ,得到数据
        Method method1 = studentClass.getMethod("getName");
        Object nameobj = method1.invoke(student);
        String name = nameobj.toString();
        System.out.println("通过反射获取到的name为:"+ name);



        String path = "src/main/resources/test.xml";
        List<Student> students = parseXML(path);
        for (Student stu : students){
            System.out.println(stu);
        }

    }


    public static List<Student> parseXML(String path) throws Exception {
        // 应用场景:通过 test.xml 文件中的标签来获取得到student对象,
        // 原来是通过 解析xml文件,读取element标签名来获取对象属性,如果标签名发生变更则需要变更很多代码,
        // 所以可以通过 java 反射来解决此问题
        // 如下示例:
        SAXReader saxReader = new SAXReader();//创建解析器对象 SAXReader
        Document document = saxReader.read(new File(path));// 获取 document 对象
        Element rootElement = document.getRootElement();// 获取根元素
        List<Element> studentElements = rootElement.elements("student");    // 返回是个 List 集合
        List<Student> students = new ArrayList<Student>();  // 用来接收新创建的 student 对象
        Class<Student> studentClass2 = Student.class;   // 获取类的字节码
        // 通过循环处理三个 student 元素
        for (Element studentElement : studentElements){
            List<Element> elements = studentElement.elements(); // 获取 student 中的各元素标签
            Student student1 = studentClass2.newInstance();
            for (Element element : elements) {  // 遍历 student 中的各标签
                String nameElement = element.getName();  // 获取标签名称
                nameElement = "set"+nameElement;
                Method method2 = studentClass2.getMethod(nameElement,String.class); //
                method2.invoke(student1,element.getText());
            }
            students.add(student1);
        }
        return students;
    }
}