java反射-通过实例来剖析一个类

前言

上一次看java反射还是在java核心技术里面看的,当时不知道干嘛用的,现在又遇见了,再学习一次,通过实例来记录,方便以后拾遗.

原理

java反射就是将内存中的字节码封装成Class对象,加载之后再对里面的内容进行剖析的这样的一个过程

流程

  • class.forname()获得class对象,你要剖析哪个类?
  • get获得你想要的部分,可能是构造器,可能是方法,可能是field.
  • 如果是私有的,你需要设置setAccessible,这样你才有私有的访问权限
  • 进行操作,方法()调用,构造器构造实例,field进行读写

实例

package reflect;

public class Student {

    private String name;
    private int grade;
    private static final String words = "hu hu";

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }

    public Student() {

    }

    public Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    private Student(String name){
        this.grade = 10;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getGrade() {
        return grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }

    private void say(String text){
        System.out.println(text+"成功");
    }

    public void sleep() {
        System.out.println("睡觉zzz");
    }

    public static void sleep(String words) {
        System.out.println("睡觉的时候打" + words);
    }

    public static void main(String[] args) {
        System.out.println("main方法");
    }

    public void work(String[] kouhao, int[] number, String name) {
        System.out.println(name + "正在工作" + kouhao + number);
    }

}

对里面的内容进行剖析

package reflect;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.junit.jupiter.api.Test;

public class Demo {


    /**
     * 解析无参数的构造函数
     *
     * @throws Exception
     */
    @Test
    public void reflect1() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Constructor constructor = clazz.getConstructor();
        Student student = (Student) constructor.newInstance();
        System.out.println(student.toString());

    }

    /**
     * @throws Exception public Student(String name, int grade)
     *                   有参数的构造器
     */
    @Test
    public void reflect2() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Constructor constructor = clazz.getConstructor(String.class, int.class);
        Student student = (Student) constructor.newInstance("张三", 96);
        System.out.println(student.toString());
    }

    /**
     * @throws Exception private Student(String name)
     *                   私有构造器
     */
    @Test
    public void reflect3() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        // 构造器是私有的加上declared
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        // 因为是私有的所以要设置accessiable
        constructor.setAccessible(true);
        Student student = (Student) constructor.newInstance("李四");
        System.out.println(student.toString());
    }

    /**
     * @throws Exception public void sleep()
     *                   无参数的实例方法
     */
    @Test
    public void reflect4() throws Exception {
        Class clzz = Class.forName("reflect.Student");
        Method method = clzz.getMethod("sleep");
        Student student = new Student();
        method.invoke(student);
    }

    /**
     * @throws Exception public static void sleep(String words)
     *                   带有一个参数的方法
     */
    @Test
    public void reflect5() throws Exception {
        Class clzz = Class.forName("reflect.Student");
        Method method = clzz.getMethod("sleep", String.class);
        Student student = new Student();
        method.invoke(student, "sleep");
    }

    /**
     * @throws Exception public void work(String[] kouhao, int[] number, String name)
     *                   多个复杂类型的方法
     */
    @Test
    public void reflect6() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Method method = clazz.getMethod("work", String[].class, int[].class, String.class);
        method.invoke(new Student(), new String[]{"1", "2", "3"}, new int[]{1, 2, 3}, "你好");
    }

    /**
     * @throws Exception public String getName
     *                   有返回值,没有参数
     */
    @Test
    public void reflect7() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Method method = clazz.getMethod("getName");
        String result = (String) method.invoke(new Student());
        System.out.println(result);
    }

    /**
     * @throws Exception private void say(String text)
     *                   私有的带参数没有返回值的方法
     */
    @Test
    public void reflect8() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Method method = clazz.getDeclaredMethod("say", String.class);
        method.setAccessible(true);
        method.invoke(new Student(), "1s");
    }

    /**
     * @throws Exception main
     */
    @Test
    public void reflect9() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Method method = clazz.getDeclaredMethod("main", String[].class);
        method.setAccessible(true);
      /*
        注意:java.lang.IllegalArgumentException: wrong number of arguments
         这里 为什么要把new String[]数组转换成对象,是因为jdk1.5有可变参数,而jdk1.4旧版本没有
         invoke(Object obj, Object ... args) 1.5
         invoke(OBject obj, Object[] args)  1.4
         不加的时候会把"2" 当做一个参数, "4"当成一个参数去找main(String str1, String str2)这个方法,
         而不是找main(String[] args) 这个数组对象为参数的方法
      */
        method.invoke(new Student(), (Object) new String[]{"2", "4"});
    }


    /**
     * @throws Exception
     * 通过反射对field的get和set操作
     */
    @Test
    public void reflect10() throws Exception {
        Class clazz = Class.forName("reflect.Student");
        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);
        Student student = new Student();
        field.set(student, "张三");
        String result = (String) field.get(student);
        System.out.println(result);
    }
}

总结

1.为什么要有反射?反射是为框架做的铺垫,各种框架都是用到了反射
2.反射如果要对私有的方法/field进行剖析就得设置访问权限setAccessible(true);
3.你需要给出完整的包的名称”包.类”这样

猜你喜欢

转载自blog.csdn.net/qq_41376740/article/details/81000706