java中的反射机制

有一句话是这么说的:反射是框架设计的灵魂

使用反射的前提是必须先得到一个类的的Class对象,在 Java 中,有三种常见获取类的 Class 对象的方式:

  1. 使用.class语法:例如 String.class,这种方式适用于已知类的情况下,在编译时就能确定类的类型。
  2. 调用对象的.getClass()方法:例如 obj.getClass(),这种方式适用于已经有一个对象实例,想要获取其类的情况。
  3. 使用静态方法 Class.forName(“ClassName”):例如 Class.forName(“java.lang.String”),这种方式适用于只知道类的名称(字符串形式),而不知道具体的类。

反射的概述:

Java 的反射机制指的是在运行时检查、获取和修改类的属性、方法、构造方法等信息的能力。它允许程序在运行时动态获取类的信息并操作类的成员。

主要概念和用途:

  1. Class 类:在 Java 中,每个类都有一个对应的 Class 对象,这个对象包含了与类相关的元数据信息,比如类的名称、访问修饰符、父类、实现的接口等。
  2. 反射 API:Java 反射提供了一组类(如 Class、Method、Field、Constructor 等)来操作类的属性、方法、构造方法等。
  3. 动态加载类:通过反射可以在运行时动态加载一个类,而不需要在编译时就将其确定下来。
  4. 运行时创建对象:可以通过反射机制在运行时创建类的对象,即使在编译时无法确定具体的类。
  5. 操作类的成员:可以获取和操作类的字段(属性)、方法、构造方法等,甚至可以调用私有成员。
  6. 框架和工具的基础:反射是很多 Java 框架和工具的基础,例如 Spring 框架、ORM(对象关系映射)工具如 Hibernate,它们利用反射机制来实现自动化配置依赖注入动态代理等功能。

怎么使用反射机制

反射中重要的一些类:

含义
java.lang.Class整个字节码对象,代表一整个类
java.lang.reflect.Method字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor字节码中的构造方法字节码,代表类中的构造方法
java.lang.reflect.Field字节码中的属性字节码,代表类中的成员变量(静态变量 + 实例变量)

其中:

Class 类

Class 代表类的实体,在运行的 java应用程序中表示类和接口。在这个类中提供了很多有用的方法:

1、获得类相关

asSubclass(Class<?> clazz) : 把传递的类的对象转换成代表其子类的对象
Cast : 把对象转换成代表类或是接口的对象
getClassLoader() : 获得类的加载器
getClasses() :返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses() :返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className) 根据类名返回类的对象
getName() : 获得类的完整路径名字
newInstance() :创建类的实例
getPackage() :获得类的包
getSimpleName() :获得类的名字
getSuperclass() : 获得当前类继承的父类的名字
getInterfaces() :获得当前类实现的类或是接口

2、获得类中属性

getField(String name) : 获得某个公有的属性对象
getFields() :获得所有公有的属性对象
getDeclaredField(String name):获得某个属性对象
getDeclareFields() :获得所有属性对象

3、获得类中构造器

getConstructor(Class… <?> parameterTypes) :获得该类中与参数类型匹配的公有构造方法 getConstructors() :获得该类的所有公有构造方法 getDeclaredConstructor(Class ...<?> parameterTypes):获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() : 获得该类所有构造方法

4、获得类中方法

getMethod(String name,Class…<?> parameterTypes) : 获得该类某个公有的方法 getMethods() : 获得该类所有公有的方法 getDeclaredMethod(String name,Class...<?> parameterTypes) : 获得该类某个方法
getDeclaredMethods() : 获得该类所有方法

示例类:

package com.money.provider;

/**
 * Author:     money
 * Description:  TODO
 * Date:    2024/6/16 11:58
 * Version:    1.0
 */

public class User {
    private String name;
    private Integer age;

    static {
        System.out.println("静态代码块执行,在构造方法前完成");
    }

    public User() {
        super();
        System.out.println("无参构造执行");
    }

    public User(String name){
        super();
        System.out.println("名字单参数构造执行");
        this.name = name;
    }

    public User(String name, Integer age) {
        super();
        System.out.println("满参构造执行");
        this.name = name;
        this.age = age;
    }

    private User(Integer age){
        System.out.println("调用私有构造方法");
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void hello(){
        System.out.println("hello方法执行,我是" + name);
    }

    private Integer add(Integer a,Integer b){
        return a + b;
    }


}

获取Class 对象:

三种方式示例:

    @Test
    public void getClassTest() throws ClassNotFoundException {
        // 方式1
        Class<?> aClass = Class.forName("com.money.provider.User");
        System.out.println(aClass);
        // 方式2
        com.money.provider.User user = new com.money.provider.User();
        Class<? extends com.money.provider.User> aClass1 = user.getClass();
        System.out.println(aClass1);
        // 方式3
        Class<com.money.provider.User> userClass = com.money.provider.User.class;
        System.out.println(userClass);
    }

image.png

反射实例化
    @Test
    public void getIn() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 无参构造
        Class<com.money.provider.User> userClass = com.money.provider.User.class;
        com.money.provider.User user = userClass.newInstance();
        System.out.println(user);
        // 单参构造
        Constructor<com.money.provider.User> constructor = userClass.getConstructor(String.class);
        com.money.provider.User user1 = constructor.newInstance("money");
        System.out.println(user1);
        // 满参构造
        Constructor<com.money.provider.User> constructor1 = userClass.getConstructor(String.class, Integer.class);
        com.money.provider.User user2 = constructor1.newInstance("hahah", 1);
        System.out.println(user2);

        // 调用私有化的构造器反射实例化
        Constructor<com.money.provider.User> declaredConstructor = userClass.getDeclaredConstructor(Integer.class);
        // 打开私有修饰的访问权限
        declaredConstructor.setAccessible(true);
        com.money.provider.User user3 = declaredConstructor.newInstance(100);
        System.out.println(user3);
    }

注意:私有构造要使用getDeclaredConstructor方法,且需要把访问权限设置为true。
image.png

反射动态方法调用

Method类方法

public String getName() : 返回方法名
public int getModifiers() :获取方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号(一般配合 Modilier类)的 toString(int x)方法使用
public Class<?> getReturnType() :以Class类型,返回方法类型(一般配合Class类的getSimpleName() 方法使用) public Class<?>[] getParameterTypes() :返回方法的参数类型列表(一个方法的参数可能会有多个。)结果集一般配合Class类的getSimpleName() 方法使用
public Object invoke(Object obj,Object… args) : 调用方法

@Test
    public void TestMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        com.money.provider.User user = new com.money.provider.User();
        Class<? extends com.money.provider.User> aClass = user.getClass();
        // 反射的无参方法调用
        Method method = aClass.getMethod("hello");
        Object invoke = method.invoke(user);
        System.out.println(invoke);

        // 反射有参方法
        Method method1 = aClass.getMethod("hello",String.class);
        Object invoke1 = method1.invoke(user, "money");
        System.out.println(invoke1);

        // 反射的私有方法
        Method add = aClass.getDeclaredMethod("add", Integer.class, Integer.class);
        add.setAccessible(true);
        Object invoke2 = add.invoke(user, 1, 2);
        System.out.println(invoke2);
    }

image.png

反射读写属性

Field 类方法
public String getName() : 返回属性名
public int getModifiers() : 获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号,(一般配合 Modifier 类的toString(int x) 方法使用)
public Class<?> getType() : 以Class类型,返回属性类型(一般配合Class类的getSimpleName() 方法使用)
public void set(Object obj,Object value) : 设置属性值
public Object get(Object obj ) : 读取属性值

@Test
    public void testField() throws NoSuchFieldException, IllegalAccessException {
        com.money.provider.User user = new com.money.provider.User("money", 19);
        Class<? extends com.money.provider.User> aClass = user.getClass();
        //        反射存值
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);
        name.set(user,"测试");
        System.out.println(user.getName());

        // 反射获取值
        Field name1 = aClass.getDeclaredField("name");
        name1.setAccessible(true);
        Object o = name1.get(user);
        System.out.println(o);
        System.out.println("=============================");
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            System.out.println(declaredField.get(user));
        }

    }

image.png

动态代理提前预习,学会看下面代码,思考反射在动态代理中的作用

invoke 是 Method 类中的一个方法。表示执行方法的调用
参数1:
Object ,表示对象,要执行这个对象的方法,即接口实现类的对象
参数2:
Object … args ,表示方法执行时的参数值
返回值:
Object : 方法执行后的返回值
字节码文件.getMethod(“name”,参数的类型);

示例:

package com.money.provider;


import com.money.common.domain.User;
import com.money.common.service.UserService;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class UserServiceImplTest {

    @Test
    public void test01(){
        User user = new User();
        user.setName("你好");
        UserService userService = new UserServiceImpl();
        User user1 = userService.getUser(user);
        System.out.println(user1.getName());
    }

    @Test
    public void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        user.setName("你好");
        Method method = UserService.class.getMethod("getUser", User.class);
        User invoke = (User)method.invoke(new UserServiceImpl(), user);
        System.out.println(invoke.getName());
    }

}
  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回答: Java反射机制是指在运行状态,对于任意一个类,都能够知道这个类的所有属性和方法,以及对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取信息和动态调用对象方法的功能称为Java语言的反射机制。\[1\] Java属于先编译再运行的语言,程序对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。\[2\] 反射机制的原理是通过Java的Class类来实现的。当一个类被加载到内存时,可以认为它是一个对象,是java.lang.Class的对象。通过Class类的方法,可以获取类的属性、方法等信息,并且可以通过反射机制动态地创建对象和调用方法。\[3\] #### 引用[.reference_title] - *1* *3* [JAVA反射机制原理](https://blog.csdn.net/qq_37126357/article/details/101542688)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Java反射机制原理](https://blog.csdn.net/qq_44159028/article/details/116119561)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiyunt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值