JAVA反射


前言


一、java反射是什么

Java是先编译再运行的语言,程序中对象的类型在编译期就确定下来了;而当程序在运行时需要动态加载某些类时(这些类因为之前用不到没有被加载到JVM),通过反射可以在运行时动态地创建对象并调用其属性,我们不需要提前在编译期知道运行的对象是谁。

Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。
Java反射机制的本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取t对象的各种信息。

二、反射的原理

正常获取对象

我们一般平时是通过new的形式创建对象实际上就是通过这些Class来创建的,只不过这个class文件是编译的时候就生成的,程序相当于写死了给jvm去跑。
在这里插入图片描述

反射获取对象

  • 当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件
  • 这些class文件在程序运行时会被ClassLoader加载到JVM中,当一个类被加载以后,JVM就会在内存中自动产生一个Class对象。
  • 通过Class对象获取Field/Method/Construcor
    在这里插入图片描述
    在这里插入图片描述

三、反射的优缺点

在这里插入图片描述
具体来说,反射带来的性能开销主要来源于以下几个方面:

  • 安全检查:反射绕过了Java的访问控制检查(如私有访问修饰符)。JVM需要进行额外的安全检查以确保操作的合法性,这也增加了开销。
  • 动态类型检查:反射在运行时才确定对象的类型和方法。这意味着JVM需要在运行时进行额外的类型检查,这通常比编译时检查要慢。
  • 方法调用开销:需要通过中间层(如Method对象)来调用目标方法,而不是直接通过编译时确定的类和方法。这种间接性增加了额外的调用开销

四、反射的应用场景

  • 框架开发:许多Java框架(如Spring、Hibernate)广泛使用反射机制来实现依赖注入、动态代理等功能。
  • 调试和测试工具:反射机制可以用来开发调试和测试工具,动态检查和操作类的内部状态。
  • 序列化和反序列化:可以使用反射机制实现自定义的序列化和反序列化逻辑。
  • 动态代理:反射机制是Java动态代理的基础,允许在运行时创建和操作代理对象。

五、反射机制常用的类及方法

1、反射机制常用的类:

Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;

2、获得Class对象的三种方法

public static void main(String[] args) throws ClassNotFoundException {

        //第一种
        ApolloRefreshConfig config = new ApolloRefreshConfig();
        Class<? extends ApolloRefreshConfig> aClass = config.getClass();
        //打印全路径
        System.out.println(aClass.getName());

        //第二种
        Class<ApolloRefreshConfig> bClass = ApolloRefreshConfig.class;
        System.out.println(aClass == bClass);

        //第三种
        Class<?> cClass = Class.forName("com.longfor.app.app.platform.app.config.ApolloRefreshConfig");
        System.out.println(aClass == cClass);
}

三种方式中,常用第三种.第一种对象都有了还要反射干什么,第二种需要导入类包,依赖太强,不导包就抛编译错误。一般都使用第三种,一个字符串可以传入也可以写在配置文件中等多种方法。

3、判断是否为某个类的实例

一般的,我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断时候为某个类的实例,他是一个native方法。

	public native boolean isInstance(Object obj);

4、通过反射来生成对象

ApolloRefreshConfig config2 = aClass.getDeclaredConstructor().newInstance();

5、其他方法

//获取包名、类名
 
clazz.getPackage().getName()//包名
 
clazz.getSimpleName()//类名
 
clazz.getName()//完整类名
 
 
//获取成员变量定义信息
 
getFields()//获取所有公开的成员变量,包括继承变量
 
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
 
getField(变量名)
 
getDeclaredField(变量名)
 
 
//获取构造方法定义信息
 
getConstructor(参数类型列表)//获取公开的构造方法
 
getConstructors()//获取所有的公开的构造方法
 
getDeclaredConstructors()//获取所有的构造方法,包括私有
 
getDeclaredConstructor(int.class,String.class)
 
 
//获取方法定义信息
 
getMethods()//获取所有可见的方法,包括继承的方法
 
getMethod(方法名,参数类型列表)
 
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
 
getDeclaredMethod(方法名,int.class,String.class)
 
 
//反射新建实例
 
clazz.newInstance();//执行无参构造创建对象
 
clazz.newInstance(222,"韦小宝");//执行有参构造创建对象
 
clazz.getConstructor(int.class,String.class)//获取构造方法
 
 
//操作属性

Field field = clazz1.getDeclaredField("someField");

field.setAccessible(true); // 设置为可访问

field.set(obj, "newValue"); // 设置属性值

Object value = field.get(obj); // 获取属性值

//调用方法

Method method = clazz1.getDeclaredMethod("someMethod", String.class);

method.setAccessible(true); // 设置为可访问

Object result = method.invoke(obj, "argument"); // 调用方法

六、常见反射示例

动态加载类和调用方法

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

Class<?> calculatorClass = Class.forName("Calculator");
Object calculatorInstance = calculatorClass.newInstance();

Method addMethod = calculatorClass.getMethod("add", int.class, int.class);
int result = (int) addMethod.invoke(calculatorInstance, 5, 3);
System.out.println("Result of add: " + result); // 输出 8

自动注入依赖

public class Repository {
    public void save() {
        System.out.println("Data saved!");
    }
}

public class Service {
    @Inject
    private Repository repository;

    public void process() {
        repository.save();
    }
}


public class DependencyInjector {
    public static void injectDependencies(Object object) throws Exception {
        Class<?> clazz = object.getClass();
        
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Inject.class)) {
                field.setAccessible(true);
                Object dependency = field.getType().newInstance();
                field.set(object, dependency);
            }
        }
    }
    
    public static void main(String[] args) throws Exception {
        Service service = new Service();
        injectDependencies(service);
        service.process(); // 输出: Data saved!
    }
}

总结

参考大神文章:java反射详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值