反射是为学习框架的底层源码做准备。

定义:反射就是加载类,并允许已编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。

反射_构造器

1.获取Class的三种方式

反射_System_02

首先要创建一个Student类


public class test {
    public static void main(String[] args) throws Exception {
        Class c1 = Student.class;
        System.out.println(c1.getName()); // 全类名
        System.out.println(c1.getSimpleName()); // 简名: Student

        Class c2 = Class.forName("com.d2_reflect.Student");
        System.out.println(c1 == c2);

        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c3 == c2);
    }
}

2.获取类的构造器

反射_成员变量_03

下面代码可以拿到cat类的构造器

public class test {
    @Test
    public void testGetConstructors() {
        // 1. 反射第一步,必须先得到这个类的Class对象
        Class c = Cat.class;

        // 2. 获取类的全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();

        // 3. 遍历数组中的每个构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());
        }
    }
            @Test
        public void testGetConstructor() throws Exception {
            // 1. 反射第一步,必须先得到这个类的Class对象
            Class c = Cat.class;
        
            // 2. 获取某个构造器,无参数构造器
            Constructor constructor = c.getDeclaredConstructor();
            System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());
        
            // 3. 获取有参数构造器
            Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);//后边加上参数类型
            System.out.println(constructor2.getName() + " ---> " + constructor2.getParameterCount());
}

}

反射_System_04

public class test {

           @Test
        public void testGetConstructor() throws Exception {
            // 1. 反射第一步,必须先得到这个类的Class对象
            Class c = Cat.class;

            // 2. 获取类的某个构造器,无参数构造器
            Constructor constructor1 = c.getDeclaredConstructor();
            System.out.println(constructor1.getName() + " ---> " + constructor1.getParameterCount());

            constructor1.setAccessible(true); // 取消检查访问权限,暴力访问
            Cat cat = (Cat) constructor1.newInstance();
            System.out.println(cat);
            
            
            
            // 3. 获取有参数构造器
            Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
            System.out.println(constructor2.getName() + " ---> " + constructor2.getParameterCount());
            
            constructor2.setAccessible(true); // 取消检查访问权限
            Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 3);
            System.out.println(cat2);

}

}

3.获取类的成员变量

反射_System_05

public class test {

    @Test
public void testGetFields() throws Exception {
    // 1. 反射第一步,必须先得到类的Class对象
    Class c = Cat.class;

    // 2. 获取类的全部成员变量
    Field[] fields = c.getDeclaredFields();

    // 3. 遍历这个成员变量数组
    for (Field field : fields) {
        System.out.println(field.getName() + " ---> " + field.getType());
    }

    // 4. 定位某个成员变量
    Field fName = c.getDeclaredField("name");
    System.out.println(fName.getName() + " ---> " + fName.getType());

    Field fAge = c.getDeclaredField("age");
    System.out.println(fAge.getName() + " ---> " + fAge.getType());
}


}

反射_构造器_06

// 赋值
Cat cat = new Cat();
fName.setAccessible(true); // 取消访问控制权限
fName.set(cat, "卡菲猫");
System.out.println(cat);

// 取值
String name = (String) fName.get(cat);
System.out.println(name);

4.获取类的成员方法

反射_System_07

  

public class test {

    @Test
    public void testGetFields() throws Exception {
        // 1. 反射第一步,必须先得到类的Class对象
       // 1. 反射第一步,先得到Class对象。
    Class c = Cat.class;

    // 2. 获取类的全部成员方法。
    Method[] methods = c.getDeclaredMethods();

    // 3. 遍历这个数组中的每个方法对象。
    for (Method method : methods) {
        System.out.println(method.getName() + " ---> "
            + method.getParameterCount() + " ---> "
            + method.getReturnType());
    }

    // 4. 获取某个方法对象
    Method run = c.getDeclaredMethod("run"); // 拿run方法,无参数。
    System.out.println(run.getName() + " ---> "
        + run.getParameterCount() + " ---> "
        + run.getReturnType());

    Method eat = c.getDeclaredMethod("eat", String.class);
    System.out.println(eat.getName() + " ---> "
        + eat.getParameterCount() + " ---> "
        + eat.getReturnType());


    }


}

反射_构造器_08

Cat cat = new Cat();
run.setAccessible(true); // 取消检查访问权限
Object rs = run.invoke(cat); // 调用无参数的run方法,用cat对象触发调用
System.out.println(rs);

eat.setAccessible(true); // 取消检查访问权限
String rs2 = (String) eat.invoke(cat, "鱼儿"); // 调用有参数的eat方法
System.out.println(rs2);

反射的作用及应用场景

基本作用:可以得到一个类的全部成分然后操作。

可以破快封装性

最重要:适合做Java的框架,基本数,主流的框架会基于反射设计出一些通用的功能。

反射_成员变量_09

public class test {
    @Test
    public void save() throws Exception {
        Student s1 = new Student("马吴彦祖", 45, '男', 185.3, "篮球,冰球,游泳");
        Teacher t1 = new Teacher("珊姐", 999.9);

        // 把任意对象的字段名和其对应的值等信息,保存到文件中去。
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);
    }
}

框架

public class ObjectFrame {
    // 目标: 保存任意对象的字段和其数据到文件中去
    public static void saveObject(Object obj) throws Exception {
        PrintStream ps = new PrintStream(new FileOutputStream("junit-output.txt", true));
        
        // obj是任意对象,剥夺有多少个字段需要保存。
        Class c = obj.getClass();
        String cName = c.getSimpleName();
        ps.println("=============== " + cName + " ===============");

        // 2. 从这个类中提取出的全部成员变量
        Field[] fields = c.getDeclaredFields();

        // 3. 遍历成员变量
        for (Field field : fields) {
            // 4. 获取变量的名字
            String name = field.getName();

            // 5. 突破javabean规范进行直接访问
            field.setAccessible(true); // 取消检查访问控制
            String value = field.get(obj) + "";
            ps.println(name + " = " + value);
        }
        ps.close();
    }
}

两个学生和老师的构造器自己写一下。