深入探讨反射机制:Java中反射的概念、应用与实战案例

1. 反射概述

1.1 什么是反射?

反射是框架设计的灵魂。

反射就是类在运行期间,把类中成员抽取为其他类的过程就是反射。

Alt

1.2 为什么使用反射?

反射是为了解决在运行期,对某个实例一无所知的情况下,如何调用其方法或属性。

例子: spring框架中只需要传入类的路径,spring框架就会帮你创建类的对象。

阿里巴巴 腾讯 国企写项目—使用第三方的框架 。

2. Class

2.1 获取Class反射类的方式

提供了三种模式:

通过类名.class获取、通过对象.getClass()获取、通过Class.forName(“全类名”)获取

Student实体类

public class Student extends People {
    private String name;
    private int age;
    public void show() {
    }
    public void show(String name) {
        System.out.println("我的名字是:"+name);
    }
    private void fun(String name,int age) {
        System.out.println("我的名字是:"+name+"今年"+age+"岁了");
    }
}

测试类

aClass1、aClass2、aClass3三者只是通过不同方式来获取到的反射类对象,指向的都是同一个引用地址。

public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException{
        //第一种:通过类名.class获取
        Class aClass1 = Student.class;
        //第二种:通过对象.getClass()获取
        Student student = new Student();
        Class aClass2 = student.getClass();
        //第三种:通过Class.forName("全类名")获取
        Class aClass3 = Class.forName("com.ykx.entity.Student");
        System.out.println(aClass3);
    }
}

2.2. Class类中常用的方法

aClass.newInstance(); // 通过反射类创建实例对象
aClass.getAnnotation(Myannotation.class); // 获取注解
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) //作用范围为类
@Retention(RetentionPolicy.RUNTIME) //运行期可见
public @interface Myannotation {
    String value();
}
测试类
public static void main(String[] args) throws Exception{
        //通过类名获取反射类
        Class<Student> aClass = Student.class;
        //1. 通过反射类创建实例对象
        Student student = aClass.newInstance();
        System.out.println(student);
        //2. 获取反射类上的注解
        Myannotation annotation = aClass.getAnnotation(Myannotation.class);
        System.out.println(annotation.value());
    }

3. Method

3.1 获取Method方法类的方式

getDeclaredMethods();//得到本类中所有的方法。
getDeclaredMethod("方法名",参数类型);//获取本类中指定的方法对象

getMethods();//获取本类以及父辈类中public修饰的方法。
getMethod("方法名",参数类型);//获取本类以及父辈类中指定public修饰的方法。
public static void main(String[] args) throws Exception{
        //通过类名获取反射类
        Class<Student> studentClass = Student.class;
    
        //1. 获取本类中所有方法--getDeclaredMethods();
        Method[] declaredMethods = studentClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("declaredMethod:"+declaredMethod);
        }

        //2. 获取本类中指定的方法对象--getDeclaredMethod("方法名",参数类型);
        Method show = studentClass.getDeclaredMethod("show", String.class);
        System.out.println("show:"+show);

        //3. 获取本类以及父类中public修饰的方法--getMethods();
        Method[] methods = studentClass.getMethods();
        for (Method method : methods) {
            System.out.println("method:"+method);
        }

        //4. 获取本类以及父类中public修饰的指定方法--getMethod("方法名",参数类型);
        Method show1 = studentClass.getMethod("show", String.class);
    }

3.2 Method类对象中常用的方法

  1. invoke()方法

    反射类获取的方法.invoke—表示方法执行。

    invoke(调用对象)–参数列表中的参数表示是谁调用。

  2. setAccessible()方法

    当试图访问并获取实体类中的私有属性或者方法时,是不被允许的。

    通过设置该方法,参数有两个值

    ​ --true表示可访问,打破不可访问私有规则

    ​ --默认为false,表示不可访问私有属性

public static void main(String[] args) throws Exception{
        //通过类名获取反射类
        Class<Student> studentClass = Student.class;
        //创建实例对象
        Student student = studentClass.newInstance();
        //获取学生类的不带参数的show方法
        Method methodShow = studentClass.getMethod("show");


        //invoke()---调用学生对象,执行该方法
        Object result = methodShow.invoke(student);
        System.out.println("invoke 不带参的show:"+result);

        Method methodShowName = studentClass.getMethod("show",String.class);
        Object result1 = methodShowName.invoke(student,"陆可");
        System.out.println("invoke 带参的show:"+result1);

        //setAccessible()---访问私有方法并执行
        Method methodShowPeople = studentClass.getDeclaredMethod("fun", String.class, int.class);
        methodShowPeople.setAccessible(true);
        Object result2 = methodShowPeople.invoke(student,"陆可",18);
        System.out.println("invoke 带参的fun:"+result2);
    }

在这里插入图片描述

4. Field

4.1获取Field属性的方式

getDeclaredFields();//得到本类中所有的属性
getDeclaredField("方法名",参数类型);//获取本类中指定的属性

getFields();//获取本类以及父辈类中public修饰的属性
getMethodFields("方法名",参数类型);//获取本类以及父辈类中指定public修饰的属性

4.2 Field类中常用的方法

  1. set(Object对象,值)-----为属性赋值
  2. getName()-----获取属性名
  3. getAnnotation()-----获取属性上的注解对象
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.FIELD}) //作用范围为类
@Retention(RetentionPolicy.RUNTIME) //运行期可见
public @interface Myannotation {
    String value();
}
实体类
import com.ykx.annotation.Myannotation;

@Myannotation(value = "学生类")
public class Student extends People {
    @Myannotation(value = "name--名字")
    private String name;
    @Myannotation(value = "age--年龄")
    private int age;
    public void show() {
    }
    public String show(String name) {
        System.out.println("我的名字是:"+name);
        return "我的名字是:"+name;
    }
    private void fun(String name,int age) {
        System.out.println("我的名字是:"+name+"今年"+age+"岁了");
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
测试类
public static void main(String[] args) throws Exception{
        Class<Student> studentClass = Student.class;
        Student student = studentClass.newInstance();

        //获取学生类的name属性
        Field name = studentClass.getDeclaredField("name");
        //name是私有属性,若要赋值需要设置
        name.setAccessible(true);
        //为其属性值赋值
        name.set(student,"陆可");
        System.out.println("student中name属性:"+name);
        System.out.println(student);

        //获取本类中所有属
        Field[] declaredFields = studentClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //getName-->获取属性名
            System.out.println(declaredField.getName());
            //getAnnotation-->获取每个属性对象上的注解对象
            Myannotation annotation = declaredField.getAnnotation(Myannotation.class);
            String value = annotation.value();
            System.out.println(value);
        }
    }

在这里插入图片描述

5. 案例练习

在properties属性文件中指定类的路径,通过反射完成类对象的创建以及类中属性的赋值

properties属性文件
className=com.ykx.entity.Demo01

# 通过反射类创建实例对象
测试类
public static void main(String[] args) {
        //加载属性文件步骤
        //1. 获取路径
        String path = "";
        //2. 获取流
        InputStream resourceAsStream = demo01.class.getClassLoader().getResourceAsStream("db.properties");
        //3. 创建属性类
        Properties properties = new Properties();
        try {
            //4. 加载属性文件
            properties.load(resourceAsStream);
            
            //5. 获取属性文件中ClassName的value值
            String name = properties.getProperty("className");
            //通过类路径的方式获取反射类
            Class aClass = Class.forName(name);
            //创建反射类实例对象
            Object o = aClass.newInstance();
            //获取反射类的所有属性
            Field[] declaredFields = aClass.getDeclaredFields();
            //为每个属性赋值
            for (Field declaredField : declaredFields) {
                //赋值
                declaredField.setAccessible(true);
                //随机生成一个数为其属性赋值,实体类中的属性值都设置为String数据类型
                declaredField.set(o,new Random().nextInt(100)+"");
            }
            System.out.println(o);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值