java 非常好用的反射框架Reflections介绍

 更新时间:2021年04月08日 10:08:17   作者:wei906  
这篇文章主要介绍了java 反射框架Reflections的使用,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据。

使用Reflections可以很轻松的获取以下元数据信息:

1)获取某个类型的所有子类;比如,有一个父类是TestInterface,可以获取到TestInterface的所有子类。

2)获取某个注解的所有类型/字段变量,支持注解参数匹配。

3)使用正则表达式获取所有匹配的资源文件

4)获取特定签名方法。

通常的用法有:

引入依赖jar

<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>

项目中使用:

// 初始化工具类
Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages(basePackages).addScanners(new SubTypesScanner()).addScanners(new FieldAnnotationsScanner()));
 
// 获取某个包下类型注解对应的类
Set<Class<?>> typeClass = reflections.getTypesAnnotatedWith(RpcInterface.class, true);
 
// 获取子类
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
 
// 获取注解对应的方法
Set<Method> resources =reflections.getMethodsAnnotatedWith(SomeAnnotation.class);
 
// 获取注解对应的字段
Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);
 
// 获取特定参数对应的方法
Set<Method> someMethods = reflections.getMethodsMatchParams(long.class, int.class);
 
Set<Method> voidMethods = reflections.getMethodsReturn(void.class);
 
Set<Method> pathParamMethods =reflections.getMethodsWithAnyParamAnnotated(PathParam.class);
 
// 获取资源文件
Set<String> properties = reflections.getResources(Pattern.compile(".*\\.properties"));

具体也可以参见官方文档

补充:Java中的反射:框架设计的灵魂

反射:框架设计的灵魂

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

反射:将类的各个组成部分封装为其他对象,这就是反射机制

好处:

1.可以在程序运行过程中,操作这些对象。

2.可以解耦,提高程序的可扩展性。

获取Class对象的方式:

1.Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象

多用于配置文件,将类名定义在配置文件中。读取文件,加载类

2.类名.class:通过类名的属性class获取

多用于参数的传递

3.对象.getClass():getClass()方法在Object类中定义着。

多用于对象的获取字节码的方式

结论:

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

例如我们有一个Person类

public class Person {
    private String name;
    private int age;
    public Person(){
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    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;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

我们写一个Demo用三种方式来获取Class对象

public class Demo1 {
    public static void main(String [] args) throws Exception {
        //1、Class.forName("类名")
        Class cls1 = Class.forName("man.Person");
        System.out.println(cls1);
        //2、类名。class
        Class cls2= Person.class;
        System.out.println(cls2);
        //3、对象.getClass()
        Person p = new Person();
        Class cls3=p.getClass();
        System.out.println(cls3);
    }
}

Class对象功能:

获取功能:

1.获取成员变量们

Field[] getFields() :获取所有public修饰的成员变量

Field getField(String name) 获取指定名称的 public修饰的成员变量

Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

Field getDeclaredField(String name)

2.获取构造方法们

Constructor<?>[] getConstructors()
Constructor getConstructor(类<?>… parameterTypes)
Constructor getDeclaredConstructor(类<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors()

3.获取成员方法们:

Method[] getMethods()
Method getMethod(String name, 类<?>… parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>… parameterTypes)

4.获取全类名

String getName() * Field:成员变量

操作:

5.设置值

void set(Object obj, Object value)

6.获取值

get(Object obj)

7.忽略访问权限修饰符的安全检查

setAccessible(true):暴力反射

Constructor:构造方法

创建对象:

T newInstance(Object… initargs)

如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法* Method:方法对象

执行方法:

Object invoke(Object obj, Object… args)

获取方法名称:

String getName:获取方法名

同样对于上面的Person类我们对其新增带参数和不带参数的sleep方法并且写一个Demo来获取这些成员变量,构造方法以及成员方法

Person.java

public class Person {
    private String name;
    private int age;
    public String a;
    protected String b;
    String c;
    private String d;
    public Person(){
    }
    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 Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println("eat...");
    }
    public void eat(String food){
        System.out.println("eat..."+food);
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }
}

Demo2.java代码如下:

public class Demo2 {
    public static void main(String [] args) throws Exception {
        Class<Person> personClass = Person.class;
        //获取成员变量
        Field[] fields = personClass.getFields();
        for(Field field:fields) {
            System.out.println(field);
        }
        System.out.println("--------------");
        Field a = personClass.getField("a");//获取a的值
        Person p = new Person();
        Object value=a.get(p);
        System.out.println(value);
        a.set(p, "zhangsan");//设置a的值
        System.out.println(p);
        System.out.println("=============");
        //获取所有成员变量
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        Field d = personClass.getDeclaredField("d");
        d.setAccessible(true);//暴力反射
        Object value2 = d.get(p);
        System.out.println(value2);
        //获取构造方法
        Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
        System.out.println("=======");
        Constructor<Person> constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
        Object person1 = constructor1.newInstance();
        System.out.println(person1);
        //获取成员方法
        Method eat_method = personClass.getMethod("eat");
        Person p1 = new Person();
        eat_method.invoke(p1);
        Method eat_method1 = personClass.getMethod("eat",String.class);
        eat_method1.invoke(p1,"饭");
        System.out.println("---------");
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

运行结果如下:

public java.lang.String man.Person.a
-------------- null Person{name=‘null', age=0, a=‘zhangsan', b=‘null', c=‘null', d=‘null'}
============= private java.lang.String man.Person.name private int man.Person.age public java.lang.String man.Person.a protected
java.lang.String man.Person.b java.lang.String man.Person.c private
java.lang.String man.Person.d null public
man.Person(java.lang.String,int) Person{name=‘张三', age=23, a=‘null',
b=‘null', c=‘null', d=‘null'}
======= public man.Person() Person{name=‘null', age=0, a=‘null', b=‘null', c=‘null', d=‘null'} eat… eat…饭
--------- public java.lang.String man.Person.toString() public java.lang.String man.Person.getName() public void
man.Person.setName(java.lang.String) public void
man.Person.eat(java.lang.String) public void man.Person.eat() public
void man.Person.setAge(int) public int man.Person.getAge() public
final void java.lang.Object.wait() throws
java.lang.InterruptedException public final void
java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws
java.lang.InterruptedException public boolean
java.lang.Object.equals(java.lang.Object) public native int
java.lang.Object.hashCode() public final native java.lang.Class
java.lang.Object.getClass() public final native void
java.lang.Object.notify() public final native void
java.lang.Object.notifyAll()

案例

需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

实现:

1. 配置文件

2. 反射

步骤:

1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中

2. 在程序中加载读取配置文件

3. 使用反射技术来加载类文件进内存

4. 创建对象

5. 执行方法

为了实现创建任意类的对象,并且执行其中任意方法,我们再原有Person.java文件基础上新增Student.java,代码如下:

public class Student {
    public void sleep(){
        System.out.println("sleep...");
    }
}

那么我们需要在src目录下添加pro.properties文件并写入以下配置信息

className=man.Student
methodName=sleep

接着我们来写这个案例ReflectTest.java,代码如下

public class ReflectTest {
    public static void main(String [] args) throws Exception {
        //加载配置文件
        Properties pro = new Properties();
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);
        //获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //加载该类进内存
        Class cls = Class.forName(className);
        Object obj = cls.newInstance();
        Method method = cls.getMethod(methodName);
        method.invoke(obj);
    }
}

这样我们只需改变配置文件中的信息而不需要去改变任何代码就可以实现类以及类中的方法​,整个目录结构如下

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

相关文章

  • 一文带你搞懂Spring响应式编程

    一文带你搞懂Spring响应式编程

    相信响应式编程经常会在各种地方被提到。本篇就为大家从函数式编程一直到Spring WeFlux做一次简单的讲解,并给出一些示例,希望大家可以更好的理解响应式编程
    2022-07-07
  • Java三大特性之继承详解

    Java三大特性之继承详解

    继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。本文将来和大家详细说说Java中的继承,需要的可以了解一下
    2022-10-10
  • 浅析Java8 中 Map 接口的新方法

    浅析Java8 中 Map 接口的新方法

    这篇文章主要介绍了Java8 中 Map 接口的新方法,本文通过代码实例给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • Java使用FilenameFilter查找出目录下指定后缀的文件示例

    Java使用FilenameFilter查找出目录下指定后缀的文件示例

    这篇文章主要介绍了Java使用FilenameFilter查找出目录下指定后缀的文件,结合实例形式分析了java基于FilenameFilter类的文件遍历、查找相关操作技巧,需要的朋友可以参考下
    2019-10-10
  • idea同步yapi插件的详细步骤

    idea同步yapi插件的详细步骤

    yapi是一个很好的接口文档维护工具,其swagger功能,可将接口信息同步到yapi平台上,这篇文章主要介绍了idea同步yapi插件,需要的朋友可以参考下
    2024-04-04
  • Java实现图片文件上传

    Java实现图片文件上传

    这篇文章主要为大家详细介绍了Java实现图片文件上传,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • Mybatis中foreach标签带来的空格\换行\回车问题及解决方案

    Mybatis中foreach标签带来的空格\换行\回车问题及解决方案

    这篇文章主要介绍了解决Mybatis中foreach标签带来的空格,换行,回车问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • IDEA POJO开发神器之Groovy的使用详解

    IDEA POJO开发神器之Groovy的使用详解

    这篇文章主要介绍了IDEA POJO开发神器之Groovy的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 详解如何在springcloud分布式系统中实现分布式锁

    详解如何在springcloud分布式系统中实现分布式锁

    最近在看分布式锁的资料,本文就介绍一下利用springcloud结合redis实现分布式锁,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Spring websocket并发发送消息异常的解决

    Spring websocket并发发送消息异常的解决

    本文主要介绍了 Spring websocket并发发送消息异常的解决,当多个线程同时尝试通过 WebSocket 会话发送消息时,会抛出异常,下面就来解决一下,感兴趣的可以了解一下
    2023-09-09

最新评论