Java反射技术

什么是反射?

        Java中的反射是指在运行时动态地获取和操作类信息的能力。通过反射,可以在运行时获取类的构造方法、方法、字段等信息,并且可以在不知道类名的情况下创建对象、调用方法和访问字段。使用反射机制可以极大地提高程序的灵活性和可扩展性,但也会带来性能上的损失。


反射的作用是什么?

        Java反射是指程序在运行时可以动态地获取一个类的信息,包括类的属性、方法、构造方法等,以及可以动态地调用类的方法、获取和设置类的属性。Java反射提供了一种机制,使得程序能够在运行时检查和操作类、方法、属性等元素,而无需在编译时就确定这些元素的信息。它在一些框架和组件中被广泛使用,例如Spring、Hibernate等,可以实现动态配置、动态加载类和实现动态代理等功能。


如何通过反射获取class对象

        获取class对象的方式有三种:

  • 类名.class
  • 对象.getClass()
  • Class.forName("类全路径")

        首先我们先创建一个User对象并生成构造函数以及Get\Set方法,toString方法,为了方便测试写一个私有方法一个公有方法。

public class User {

    public String name;

    public int age;

    private String gender;

    private void priMethod(String name){
        System.out.println("私有方法");
    }

    private void priMethod(){
        System.out.println("私有方法");
    }

    public void pubMethod(){
        System.out.println("公有方法");
    }
    public void pubMethod(String name){
        System.out.println("公有方法");
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }

    private User(int age) {
        this.age = age;
    }

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

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

    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;
    }
}

        现在来利用三种方式来获取class对象。

//1、类名.class
Class clazz = User.class;

//2、对象.getClass()
Class clazz2 = new User().getClass();

//3、Class.forName("类全路径")
Class clazz3 = Class.forName("com.study.reflect2.User");

通过class对象获取对象实例

        得到class对象后就可以进行实例化。

//实例化
User user = (User) clazz.getDeclaredConstructor().newInstance();
User user2 = (user)Class.forName("com.study.reflect2.User").newInstance();

通过实例获取对象构造方法

1、获取public修饰的空参构造

Constructor constructor = clazz.getConstructor();
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();

2、获取public修饰的所有构造

Constructor[] constructors = clazz.getConstructors();

3、获取public修饰的指定参数构造器

Constructor constructor1 = clazz.getConstructor(String.class);
Constructor constructor2 = clazz.getConstructor(String.class, int.class, String.class);

4、获取所有构造器(包括private修饰的)

Constructor[] declaredConstructors = clazz.getDeclaredConstructors();

       获取构造函数后即可根据其参数来实例化对象,public修饰的构造函数可以利用 newInstance() 方法直接实例化,而private修饰的构造函数可以通过 constructor.setAccessible(true) 来暴力操作。

注意:实际上 setAccessible(true) 是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,值为 false 则指示反射的对象应该实施 Java 语言访问检查。同时,由于JDK的安全检查耗时较多,所以通过setAccessible(true) 的方式关闭安全检查就可以达到提升反射速度的目的。


通过class对象获取对象属性

1、获取public修饰的指定属性

Field name = clazz.getField("name");
Field age = clazz.getField("age");

2、获取指定属性(包括private修饰的)

Field name1 = clazz.getDeclaredField("name");
Field age1 = clazz.getDeclaredField("age");
Field gender1 = clazz.getDeclaredField("gender");

3、获取public修饰的所有属性

Field[] fields = clazz.getFields();

4、获取所有属性(包括private修饰的)

Field[] declaredFields = clazz.getDeclaredFields();

获取属性后可以利用实例化对象进行赋值操作:

Field[] fields = clazz.getDeclaredFields();
User user = (User)clazz.getDeclaredConstructor().newInstance();
for (Field field : fields) {
    if (field.getName().equals("name")){
        field.set(user,"张三");
    }
}

同样的,私有化属性无法直接操作,可以通过 field.setAccessible(true) 来暴力操作。


通过class对象获取对象方法

1、获取公有方法(可以指定参数类型)

Method pubMethod = clazz.getMethod("pubMethod");
Method pubMethod1 = clazz.getMethod("pubMethod",String.class);

2、获取所有方法(private + public 可以指定参数类型)

Method priMethod1 = clazz.getDeclaredMethod("priMethod");
Method priMethod2 = clazz.getDeclaredMethod("priMethod",String.class);
Method pubMethod1 = clazz.getDeclaredMethod("pubMethod");
Method pubMethod2 = clazz.getDeclaredMethod("pubMethod",String.class);

3、获取所有公有方法(包括父类的方法)

Method[] methods = clazz.getMethods();

4、获取所有方法(private + public 不包含父类方法)

Method[] declaredMethods = clazz.getDeclaredMethods();

反射会忽略泛型,可以插入不同类型数据


反射获取注解

        不论是类、属性、方法、构造函数,都可以利用反射来获取其注解,并且如果注解有值,还可以获取注解的值。

自定义注解

@Target({ElementType.CONSTRUCTOR, ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface study {
    String name() default "";
    int age() default 0;
    String[] hobby();
}

获取注解

Annotation annotation = clazz.getAnnotation(study.class);
Annotation annotation = constructor.getAnnotation(study.class);
Annotation annotation = field.getAnnotation(study.class);
Annotation annotation = method.getAnnotation(study.class);

在获取注解时可以直接将获取到的注解转成注解类型,这样我们就可以获取注解的值。

study study = (com.study.reflect.study) clazz.getAnnotation(study.class);
study study = (com.study.reflect.study) constructor.getAnnotation(study.class);
study study = (com.study.reflect.study) field.getAnnotation(study.class);
study study = (com.study.reflect.study) method.getAnnotation(study.class);
//获取内容
String name = study.name;
int age = study.age;
String[] hobby = study.hobby;

反射原理

        程序在执行之前首先都会将.java文件编译为.class文件,在使用反射时,jvm会将对应的.class文件通过类加载器加载到内存中,获取到.class文件后,就可以进行进一步操作了。


其他操作

待完善~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值