[Java基础]反射技术

反射

反射就是拿到类文件, 然后操作类的成分(成员变量, 方法, 构造器等)

反射具体学什么?

通过加载类文件, 获取类的成分信息, 操作他们

  1. 反射第一步: 加载类,获取类的字节码 (Class对象)
  2. 获取类的构造器: Constructor对象
  3. 获取类的成员变量: Field对象
  4. 获取类的成员方法: Method对象

反射第一步: 加载类,获取类的字节码 (Class对象)

复制代码
public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        // 目标: 获取类的Class对象 (类文件)
        // 1.通过类名获取类: 类.class
        Class c1 = Student.class;
        System.out.println(c1); // class com.itheima.Student

        // 2.通过Class提供的方法获取类: Class.forName("类的全名称")
        Class c2 = Class.forName("com.itheima.Student");
        System.out.println(c2); // class com.itheima.Student

        // 3.通过Object提供的方法获取类: 对象.getClass()
        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c3); // class com.itheima.Student

        // 类文件在系统中只有一份, 三种方式拿到的类文件都是同一个class对象
        System.out.println(c1 == c2); // true
        System.out.println(c2 == c3); // true
    }
}

获取类的构造器: Constructor对象

Class提供了从类中获取构造器的方法

使用获取到的构造器: 初始化对象返回

复制代码
public class GetClassInfo {
    public static void main(String[] args) throws Exception {
        // 目标: 通过反射获取类的所有信息
        // 1.获取类文件的信息
        getClassInfo();
        // 2.获取类的构造器
    }

    // 2.获取类的构造器
    private static void getConstructors() throws Exception {
        Class c1 = Student.class;
        // 2.1获取类的全部构造器
        Constructor[] sons = c1.getDeclaredConstructors();
        for (Constructor son : sons) {
            System.out.println(son.getName() + "(" + son.getParameterCount() + "个参数)");
        }

        // 2.2获取单个构造器
        Constructor son = c1.getDeclaredConstructor(); // 获取无参构造器
        System.out.println(son.getName() + "(" + son.getParameterCount() + "个参数)");

        Constructor son2 = c1.getDeclaredConstructor(String.class, int.class); // 获取有参构造器
        System.out.println(son2.getName() + "(" + son2.getParameterCount() + "个参数)");

        // 2.3获取构造的作用就是创建对象
        Student s1 = (Student) son.newInstance();
        System.out.println(s1);

        // 2.4暴力反射 可以访问私有的构造器,成员变量和方法
        son2.setAccessible(true);
        Student s2 = (Student) son2.newInstance("张三", 19);
        System.out.println(s2);
    }

    // 1.获取类文件的信息
    private static void getClassInfo() {
        Class c1 = Student.class;
        System.out.println(c1.getName()); // 获取类的全类名 com.itheima.Student
        System.out.println(c1.getSimpleName()); // 获取类的简类名 Student
    }
}

获取类的成员变量: Field对象

Class提供了从类中获取成员变量的方法

为成员变量取值/赋值

复制代码
public class GetClassInfo {
    public static void main(String[] args) throws Exception {
        // 目标: 通过反射获取类的所有信息
        // 3.获取类的成员变量
        getFields();
        // 4.获取类的成员方法
        getMethods();

    }

    // 3.获取类的成员变量
    private static void getFields() throws Exception {
        Class c1 = Student.class;
        // 3.1获取类的全部成员变量
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName() + "(" + field.getType().getName() + ")");
        }

        // 3.2获取单个成员变量
        Field name = c1.getDeclaredField("name"); // 获取name成员变量
        System.out.println(name.getName() + "(" + name.getType().getName() + ")");

        Field age = c1.getDeclaredField("age");
        System.out.println(age.getName() + "(" + age.getType().getName() + ")");

        // 3.3获取成员变量的作用就是取值赋值
        Student student = new Student(); // 得到学生对象
        name.setAccessible(true); // 暴力反射: 绕过访问权限修饰符
        name.set(student, "李四"); // 变量赋值
        age.set(student, 18); // 变量赋值

        String sname = (String) name.get(student); // 变量取值
        int sage = (int) age.get(student); // 变量取值
    }
}

获取类的成员方法: Method对象

Class提供了从类中获取成员方法的API

执行获取到的方法

复制代码
package com.itheima;

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

public class GetClassInfo {
    public static void main(String[] args) throws Exception {
        // 目标: 通过反射获取类的所有信息
        // 4.获取类的成员方法
        getMethods();

    }

    // 4.获取类的成员方法
    private static void getMethods() throws Exception {
        Class c1 = Student.class;
        // 4.1获取类的全部成员方法
        Method[] methods = c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "(" + method.getParameterCount() + "个参数)");
        }

        // 4.2获取单个成员方法
        Method method = c1.getDeclaredMethod("setName", String.class); // 获取setName方法
        System.out.println(method.getName() + "(" + method.getParameterCount() + "个参数)");

        // 4.3获取成员方法的目的就是执行该方法
        Student student = new Student();
        method.setAccessible(true); // 暴力反射: 绕过访问权限修饰符
        method.invoke(student, "张三"); // 执行setName方法
    }

}

反射的作用

  1. 可以得到一个类的全部成分然后操作。

  2. 可以破坏封装性。

  3. 可以绕过泛型的约束

  4. 主流的框架都会基于反射设计出一些通用的功能。

    public class Demo {
    public static void main(String[] args) throws Exception {
    // 目标: 了解反射的作用
    ArrayList<String> list = new ArrayList<>();
    list.add("张无忌");
    list.add("令狐冲");
    list.add("东方不败");

    复制代码
         // 通过反射绕过泛型的约束
         Class c1 = list.getClass();
         Method add = c1.getDeclaredMethod("add",Object.class);
         add.invoke(list,98);
         add.invoke(list,true);
    
         System.out.println(list); // [张无忌, 令狐冲, 东方不败, 98, true]
     }

    }

案例

需求: 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

  1. 定义一个方法, 接收任意对象

  2. 通过反射获取对象的Class对象, 然后获取全部的成员变量

  3. 遍历成员变量, 然后提取成本成员变量的值

  4. 把成员变量名, 变量值, 写入到文件中

    public class Demo {
    public static void main(String[] args) throws Exception {
    // 反射是框架的核心技术
    Dog dog = new Dog("哈士奇", 4);
    Student student = new Student("小明", 19, 100);

    复制代码
         SaveObjectFrameWork.saveObject(dog); // 保存dog对象到文件中
         SaveObjectFrameWork.saveObject(student); // 保存student对象到文件中
     }

    }

    public class SaveObjectFrameWork {
    // 保存任意对象的静态方法
    public static void saveObject(Object obj) throws Exception {
    // 打印流
    PrintStream ps = new PrintStream(new FileOutputStream("day8-reflect\src\com\itheima\test3\obj.txt", true));

    复制代码
         // 获取类文件
         Class c = obj.getClass();
         String simpleName = c.getSimpleName();
         ps.println("==========" + simpleName + "==========");
         // 获取所有的成员变量
         Field[] fields = c.getDeclaredFields();
         for (Field field : fields) {
             String fieldName = field.getName(); // 获取变量名
             field.setAccessible(true); // 暴力反射, 绕过权限修饰符
             Object fileValue = field.get(obj); // 获取变量值
             ps.println(fieldName + "=" + fileValue);
         }
         ps.close();
     }

    }

相关推荐
wuqingshun31415916 分钟前
蓝桥杯 10.拉马车
数据结构·c++·算法·职场和发展·蓝桥杯·深度优先
Java知识库21 分钟前
Java BIO、NIO、AIO、Netty面试题(已整理全套PDF版本)
java·开发语言·jvm·面试·程序员
techdashen21 分钟前
性能比拼: Rust vs Zig vs Go
开发语言·golang·rust
爱编程的鱼25 分钟前
C# 封装教程
开发语言·c#
0wioiw025 分钟前
Kotlin基础(①)
android·开发语言·kotlin
西瓜本瓜@36 分钟前
在 Android 中实现通话录音
android·java·开发语言·学习·github·android-studio
患得患失9491 小时前
【后端】【python】Python 爬虫常用的框架解析
开发语言·爬虫·python
我不是小upper1 小时前
详解机器学习各算法的优缺点!!
人工智能·算法·机器学习
嘵奇1 小时前
基于Spring Boot实现文件秒传的完整方案
java·spring boot·后端
V功夫兔1 小时前
Spring_MVC 高级特性详解与实战应用
java·经验分享·笔记·spring