Java 反射 ( 详细介绍 )

简介: 详细介绍 Java 反射的概念 、 原理 、 使用方法 、 注意事项 等,让你轻松掌握反射

反射 是 Java框架 的核心 ,无论是Tomcat、SpringMVC、Spring IOC、Spring AOP、动态代理 ,都使用到了 反射

反射的作用简单讲就是 无需 new 对象,就可以动态获取到一个类的全部信息,包括 属性、方法,构造器,以及他们的修饰符、参数、注解 等等... 从而构造出 对象实例 并对 对象实例 进行操作

因此,学好反射是必须的,接下来就学习如何使用反射

这是我们下面要进行操作的类

public class Student {
   
    private String name;
    private int age;
    public String gender;
    public String address;


    public Student() {
   
    }
    public Student(String name, int age, String address) {
   
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public Student(String name, int age, String gender, String address) {
   
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.address = address;
    }

    public String getName() {
   
        return name;
    }
    public void setName(String name) {
   
        this.name = name;
    }
    public int getAge() {
   
        return age;
    }
    public void setAge(int age) {
   
        this.age = age;
    }
    public String getGender() {
   
        return gender;
    }
    public void setGender(String gender) {
   
        this.gender = gender;
    }
    public String getAddress() {
   
        return address;
    }
    public void setAddress(String address) {
   
        this.address = address;
    }

    private void study(){
   
        System.out.println("学生在学习");
    }
    private void sleep(){
   
        System.out.println("学生在睡觉");
    }
    public String eat(String something){
   
        System.out.println("学生在吃" + something);
        return "学生已经吃完了,非常happy";
    }

    public String toString() {
   
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", address = " + address + "}";
    }
}

获取字节码文件对象(即 类对象)的三种方式

  • 通过 Class类 里面的 静态方法forName("全类名")(最常用)
  • 通过 类名.class 属性获取
  • 通过对象获取字节码文件对象 -- 对象名.getClass()

什么是字节码文件对象?

java文件:就是我们自己编写的java代码。

字节码文件:就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的)

字节码文件对象:当class文件加载到内存之后,虚拟机自动创建出来的对象。这个对象里面就包含了类的所有信息。并且该对象在内存中是唯一的(存在于 JVM 的方法区中)

往后 获取类信息 的操作都是建立在 字节码文件对象 的基础上的

这三种获取 字节码文件对象 的方法是有区别的

  • Class.forName("全类名") -- 在 java文件阶段 就可以获取 字节码文件对象,因此这是最常用的
  • 类名.class -- 要在 类加载完成阶段 才能获取
  • 对象名.getClass) -- 要在 对象已经被创建出来的阶段 才能获取

代码示例

//第一种方法
Class clazz1 = Class.forName("com.zhuyuanjie.reflectdemo.Student");

//第二种方法
Class clazz2 = Student.class;

//第三种方法
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true

获取 构造方法 并使用

不许通过 new ,我们也能通过反射获取到实例对象

大致步骤 -- 获取构造器对象,调用构造器的 newInstance 方法就可以创建出实例对象

——— 1.首先获取构造器对象 ————

方法如下:

方法名 说明
Constructor<?>[] getConstructors() 获得所有的构造(只能public修饰)
Constructor<?>[] getDeclaredConstructors() 获得所有的构造(包含private修饰)
Constructor getConstructor(Class<?>... parameterTypes) 获取指定构造(只能public修饰)
Constructor getDeclaredConstructor(Class<?>... parameterTypes) 获取指定构造(包含private修饰)

观察上面表格发现,方法中如果没加 Declareed 就只能获取 public 的构造方法,而加了 Declareed 就可以获取全部,

而且方法末尾如果有 s 是获取所有,没加 s 是获取指定的构造器,需传入 指定构造器的参数列表

代码实例

        //获得class字节码文件对象
        Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");


        //获取构造方法对象
        //获取所有构造方法(public)
        Constructor[] constructors1 = clazz.getConstructors();
        for (Constructor constructor : constructors1) {
   
            System.out.println(constructor);
        }

        //获取指定的空参构造
        Constructor con1 = clazz.getConstructor();
        System.out.println(con1);

        //获取带参数的构造方法
        Constructor con2 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con2);

——— 2 调用 newInstance 方法,创建 实例对象———

//1.获取整体的字节码文件对象
Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");
//2.获取空参的构造方法
Constructor con = clazz.getConstructor();
//3.利用空参构造方法创建对象
Student stu = (Student) con.newInstance();
System.out.println(stu);

上面代码中,如果我们获取到的构造方法是 private 属性,那么我们还不能直接调用,需要调用 setAccessible(true)方法 传入参数 true,来临时取消访问权限,如下:

Class clazz = Class.forName("com.zhuyuanjie.reflectdemo1.Student");

Constructor con = clazz.getConstructor();

//调用 setAccessible(true) 方法
con.setAccessible(true);

Student stu = (Student) con.newInstance();
System.out.println(stu);

该方法不止用在构造方法上,包括接下来的 属性、方法 等,只要对 private修饰 的进行操作,就需要调用

获取 成员变量(属性) 并使用

方法名 说明
Field[] getFields() 返回所有成员变量对象的数组(只能拿public的)
Field[] getDeclaredFields() 返回所有成员变量对象的数组,存在就能拿到
Field getField(String name) 返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name) 返回单个成员变量对象,存在就能拿到

可以发现以上方法名的结构,与 获取构造方法使用到的方法 一样,这里不在赘述

代码实例


        //1.获取class对象
        Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");


        //获取成员变量的对象(public + private)
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
   
            System.out.println(field);
        }

        System.out.println("===============================");
        //获得单个成员变量对象
        //如果获取的属性是不存在的,那么会报异常
        //Field field3 = clazz.getField("aaa");
        //System.out.println(field3);//NoSuchFieldException


        System.out.println("===============================");
        //获取单个成员变量(私有)
        Field field5 = clazz.getDeclaredField("name");
        System.out.println(field5);

获取到 Field 对象后,我们就能得到 成员变量 的一切信息


        //1.获取class对象
        Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");

        Field name = clazz.getDeclaredField("name");

        //临时取消访问权限
        name.setAccessible(true);

        //获取权限修饰符
        int modifiers = name.getModifiers(); //2

        //获取属性名
        String n = name.getName(); // name

        //获取数据类型
        Class<?> type = name.getType(); //class java.lang.String

        //等等... 还有很多,不在展示

还可以获取和修改 成员变量 的值

方法 说明
void set(Object obj, Object value) 赋值
Object get(Object obj) 获取值
        Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");

        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);

        //设置(修改)name的值
        //参数一:表示要修改哪个对象的name?
        //参数二:表示要修改为多少?
        field.set(s,"张三");

        //获取name的值
        //表示我要获取这个对象的name的值
        String result = (String)field.get(s); // 张三

获取 成员方法 并运行

获取 成员方法 的方法和获取 成员的变量 的方法几乎一样,就是把 Field 改为 Method

而 获取到 成员方法 后,通过调用 Object invoke(Object obj, Object... args) 进行运行

其中

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

        //1.获取字节码文件对象
        Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");

        //2.获取一个对象
        //需要用这个对象去调用方法
        Student s = new Student();

        //3.获取一个指定的方法
        //参数一:方法名
        //参数二:参数列表,如果没有可以不写
        Method eatMethod = clazz.getMethod("eat",String.class);

        //运行
        //参数一:表示方法的调用对象
        //参数二:方法在运行时需要的实际参数
        //注意点:如果方法有返回值,那么需要接收invoke的结果
        //如果方法没有返回值,则不需要接收
        String result = (String) eatMethod.invoke(s, "重庆小面");
        System.out.println(result);

同样的,如果方法是 private ,也需要调用 setAccessible(true) 方法

除了以上最常用的获取 构造方法 、成员变量 、成员方法 ,在框架中还经常通过反射获取 类 、 属性 、方法 上的注解信息

有需要可以看我的另外一篇博客,地址:

【Java 】 如何通过 反射 获取 注解信息 ?

而且我的 Gitee 上有 Tomcat 、SpringMVC 等框架的核心源码仿写,可以感受下反射在框架中的使用,Gitee 地址如下:

朱元杰的Gitee -- 框架源码仿写

目录
相关文章
|
20天前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
13 0
[Java]反射
|
2月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
62 9
Java——反射&枚举
|
1月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 2
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
29天前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
16 0
|
2月前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。
|
2月前
|
存储 安全 Java
扫盲java基础-反射(一)
扫盲java基础-反射(一)
|
2月前
|
Java
扫盲java基础-反射(二)
扫盲java基础-反射(二)
|
4月前
|
安全 Java 测试技术
day26:Java零基础 - 反射
【7月更文挑战第26天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
34 5
|
3月前
|
缓存 安全 Java
【Java 第十篇章】反射
Java 反射技术让程序能在运行时动态获取类信息并操作对象,极大提升了灵活性与扩展性。本文将介绍反射的基本概念、原理及应用,包括如何使用 `Class`、`Field`、`Method` 和 `Constructor` 类进行动态操作。此外,还将探讨反射在动态加载、框架开发与代码测试中的应用场景,并提醒开发者注意性能与安全方面的问题,帮助你更合理地运用这一强大工具。
28 0