Java:反射 reflection ( 概念+相关类+使用方法)

一、反射(reflection)


1.概念

  • Java的反射机制是 在运行状态中,可以知道任何一个类的所有属性和方法
  • 可以调用任意一个对象的任意方法和属性
  • 拿到之后就可以进行修改
  • 反射就是动态获取信息、动态调用对象方法的一种功能
优点:
  • 可以获得一个类的所有属性和方法,进行调用、修改。反射运用在很多主流框架
  • 提高灵活性和扩展性,降低耦合
缺点
  • 导致效率降低
  • 可读性差,不好维护

2.反射的相关类

类名用途
Class类代表类的实体,在运行的Java程序中表示类的接口
Field类代表类的成员变量、类的属性
Method类代表类的方法
Constructor类代表类的构造方法

1.Class类

1.反射机制的起源
  • Java文件被编译后会生成.class文件
  • .class文件会被JVM解析成一个对象:java.long.Class
  • 在运行时,每个java文件最终会变成Class类对象的一个实例
  • 通过反射,获取、添加、修改这个类的属性和方法,成为一个动态的类
2.获得类相关的方法
方法用途
getClassLoader()获得类的加载器
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)
forName(String className)根据类名返回类的对象
newInstance()创建类的实例
getName()获得类的完整路径名字

在这里插入图片描述

  • 获取Class对象,通过newInstans方法创建类的实例
    public static void reflectNewInstance() {        
		Class<?> classStudent = null;
        try {
            classStudent = Class.forName("reflect.Student");
            //获取Class对象
            Student student = (Student) classStudent.newInstance();
            //强转,向下转向
            System.out.println(student);//Student{name='小明', age=20}

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }  
    }
  • newInstans方法会抛出 InstantiationException, IllegalAccessException两个异常
  • 方法的返回值是T,被擦除成了Object,所以要进行强制类型转换
3.获得类中属性的相关方法

(以下方法返回值为Field相关)

方法用途
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象
    // 反射私有属性
    public static void reflectPrivateField() {
        Class<?> classStudent = null;
        try {
            classStudent = Class.forName("reflect.Student");

            Field field = classStudent.getDeclaredField("name");
            field.setAccessible(true);
            //进行确定
            Student student = (Student) classStudent.newInstance();

            field.set(student,"王大锤");

            System.out.println(student);//Student{name='王大锤', age=20}


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
4.获得类中注解相关的方法
方法用途
getAnnotation(Class annotationClass)返回该类中与参数类型匹配的公有注解对象
getAnnotations()返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass)返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations()返回该类所有的注解对象
5.获得类中构造器相关的方法

(以下方法返回值为Constructor相关)

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

在这里插入图片描述

  • 同理,获得该类中与参数类型匹配的构造方法
  • 要传入对应构造方法中,参数类型的class对象
		  classStudent = Class.forName("reflect.Student");
            //获取Class对象
            Constructor<?> constructor = classStudent.getDeclaredConstructor(String.class, int.class);
            //获得该类中与参数类型匹配的构造方法

在这里插入图片描述

  • 这里是 constructor的newInstance()方法,传入初始化的参数列表
  • 添加对应的异常,并且进行强转
  • 因为是私有的构造方法,所以要调用setAccessible(true)方法,填上true 体现安全性(需要确认)
  • 反射打破了封装机制
 public static void reflectPrivateConstructor()   {      
	Class<?> classStudent = null;
        try {
            classStudent = Class.forName("reflect.Student");
            //获取Class对象

            Constructor<?> constructor = classStudent.getDeclaredConstructor(String.class, int.class);
            //获得该类中与参数类型匹配的构造方法
            constructor.setAccessible(true);

            Student student = (Student) constructor.newInstance("小红", 18);
            //这里是 constructor的newInstance()方法

            System.out.println(student);//Student{name='小红', age=18}

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {

        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }
}
6.获得类中方法相关的方法

(以下方法返回值为Method相关)

方法用途
getMethod(String name, Class…<?> parameterTypes)获得该类某个公有的方法
getMethods()获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes)获得该类某个方法
getDeclaredMethods()获得该类所有方法
    // 反射私有方法
    public static void reflectPrivateMethod() {
        Class<?> classStudent = null;
        try {
            classStudent = Class.forName("reflect.Student");
            Method method = classStudent.getDeclaredMethod("function", String.class);
            method.setAccessible(true);

            Student student = (Student) classStudent.newInstance();

            method.invoke(student,"不要吃");//不要吃

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

2.获取Class对象的三种方法:

1.使用 Class.forName(“类的全路径名”);

静态方法,前提是知道类的全路径名。

在这里插入图片描述

        Class<?> C1 = null;
        try {
            C1 = Class.forName("reflect.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
  • forName会抛出 ClassNotFoundException异常, ClassNotFoundException继承于Exception
  • 所以默认是一个受查异常(编译时异常),需要进行处理(JVM/手动抓取)
2.使用 .class 方法。
 Class<Student> C2 = Student.class;

仅适合在编译前就已经明确要操作的 Class

3.使用类对象的 getClass() 方法
        Student student = new Student();
        Class<? extends Student> C3 = student.getClass();
        System.out.println(C1 == C2);//true
        System.out.println(C1 == C3);//true

  • Class对象只存在一个

点击移步博客主页,欢迎光临~

偷cyk的图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值