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 -- 框架源码仿写

目录
相关文章
|
3天前
|
安全 Java API
Java反射(Reflection)的技术性文章
Java反射(Reflection)的技术性文章
19 1
|
19天前
|
Java C++
Java反射的简单使用
Java反射的简单使用
25 3
|
19天前
|
Java
【专栏】Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性
【4月更文挑战第27天】本文探讨了Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性。反射通过Class、Constructor、Method和Field类实现。文中列举了反射的应用场景,如动态创建对象、调用方法、访问属性和处理注解,并提供了相关实例代码演示。
|
3天前
|
缓存 安全 Java
【Java——反射机制详解】
RTTI(Run-Time Type Identification)运行时类型识别。在《Thinking in Java》一书第十四章中有提到,其作用是在运行时识别一个对象的类型和类的信息。主要有两种方式:一种是“传统的”RTTI,它假定我们在编译时已经知道了所有的类型;另一种是“反射”机制,它允许我们在运行时发现和使用类的信息。 反射就是把java类中的各种成分映射成一个个的Java对象 例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
|
4天前
|
JSON Java 数据库连接
Java的反射
Java的反射
|
17天前
|
安全 Java API
JAVA-不安全的反射--RCE
JAVA不安全的反射造成的RCE小案例
|
19天前
|
SQL 存储 Java
【Java反射详解】
【Java反射详解】
15 1
|
19天前
|
Java
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识
【5月更文挑战第2天】JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识。入坑JAVA因它的面向对象特性、平台无关性、强大的标准库和活跃的社区支持。
43 2
|
19天前
|
Java 测试技术
滚雪球学Java(24):Java反射
【4月更文挑战第13天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 0
滚雪球学Java(24):Java反射
|
19天前
|
Java
Java 反射
Java 反射