Java之简析反射

反射

1 什么是反射

(1)Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
(2)反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

通俗的说:
(1)反射可以从类里面拿东西。
(2)类里面有字段(成员变量),构造方法,成员方法。
(3)IDEA中的提示就是反射。

2 反射的作用

1 获取任意一个类中的所有信息。
2 一个类中都有哪些具体的信息呢?
(1)成员变量(修饰符、名字、类型、值)
(2)构造方法(修饰符、名字、形参、创建对象)
(3)成员方法(修饰符、名字、形参、返回值、抛出的异常、注解、运行方法)
3 结合配置文件动态创建对象。

3 获得Class 字节码文件对象的三种方式

(1)Class.forName("完整类名");
(2)类名.Class
(3)对象.getClass()

    public static void main(String[] args) throws Exception {
        Class cla = Class.forName("day10.Dog");
        System.out.println(cla);

        Class cla2 = Dog.class;
        System.out.println(cla2);

        Dog dog = new Dog();
        Class cla3 = dog.getClass();
        System.out.println(cla3);

        System.out.println(cla == cla2);
        System.out.println(cla2 == cla3);
        System.out.println(cla == cla3);
    }

在这里插入图片描述

4 如何获取构造方法、成员变量、成员方法

4.1 获取构造方法

 getConstructors():返回所有公共构造方法对象的数组
 getDeclaredConstructors(): 返回所有构造方法对象的数组
 getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象
 getDeclaredConstructor(lass<?>... parameterTypes):返回单个私有构造方法对象


Constructor类中用于创建对象的方法
 newInstance(Objet... initargs): 根据指定的构造方法创建对象
setAccessible(boolean flag):设置为true,表示取消访问检查

实例

    public static void main(String[] args) throws Exception {
        Class cla = Class.forName("day10.Dog");

        System.out.println("得到公共的构造方法***********");
        Constructor[] con = cla.getConstructors();
        for (Constructor constructor : con) {
            System.out.println(constructor);
        }

        System.out.println("得到包括私有的所有构造方法*********");
        Constructor[] con1 = cla.getDeclaredConstructors();
        for (Constructor constructor : con1) {
            System.out.println(constructor);
        }

        System.out.println("得到单个构造方法的修饰符********");
        Constructor con2 = cla.getDeclaredConstructor(String.class);
        int modifiers = con2.getModifiers();
        System.out.println(modifiers);

        Constructor con3 = cla.getDeclaredConstructor(String.class, String.class);
        con3.setAccessible(true);
        int modifiers2 = con3.getModifiers();
        System.out.println(modifiers2);

        System.out.println("获取了类里面的所有参数***********");
        Parameter[] p1 = con3.getParameters();
        for (Parameter parameter : p1) {
            System.out.println(parameter);
        }
    }

分析
在这里插入图片描述

结果

在这里插入图片描述

API帮助文档 -> 常量字段值
在这里插入图片描述

使用反射创建对象

        Dog dog = (Dog) con3.newInstance("旺财","金毛");
        System.out.println(dog);

结果
在这里插入图片描述

4.2 获取成员变量

Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象

Field类中用于创建对象的方法
void set(Object obj, Object value):赋值
Object get(Object obj)获取值。

实例

public class MemberVariables {
    public static void main(String[] args) throws  Exception{
        Class cla = Class.forName("day10.Dog");
        System.out.println("获取公共的成员变量*********");
        Field[] fields = cla.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("获取包含私有的所有的成员变量*********");
        Field[] fields1 = cla.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println(field);
        }

        System.out.println("获取单个的成员变量*********");
        Field field = cla.getField("name");
        System.out.println(field);

        System.out.println("获取单个的成员变量*********");
        Field field1 = cla.getDeclaredField("age");
        System.out.println(field1);

        System.out.println("获取成员变量的权限修饰符*********");
        int mod = field1.getModifiers();
        System.out.println(mod);
        Class type = field1.getType();
        System.out.println(type);

        System.out.println("获取成员变量的值***********");
        Constructor con = cla.getDeclaredConstructor(String.class,String.class,int.class,double.class);
        Dog dog = (Dog)con.newInstance("旺财","金毛",8,20.5);
        field1.setAccessible(true);
        Object value = field1.get(dog);
        System.out.println(value);

        System.out.println("修改成员变量的值***********");
        field1.setAccessible(true);
        field1.set(dog,9);
        System.out.println(dog);

    }

分析
在这里插入图片描述

结果

在这里插入图片描述
在这里插入图片描述

4.3 获取成员方法

Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象


Field类中用于创建对象的方法
void set(Object obj, Object value):赋值
Object get(Object obj)获取值。

实例
在这里插入图片描述

在这里插入图片描述
代码

    public static void main(String[] args) throws Exception {
        Class cla = Class.forName("day10.Dog");

        System.out.println("获取指定的方法*********************");
        Method methods = cla.getMethod("show");
        System.out.println(methods);

        System.out.println("获取异常*********************");
        Class[] excep = methods.getExceptionTypes();
        for(Class exception : excep){
            System.out.println(exception);
        }

        System.out.println("运行方法************");
        Constructor con = cla.getConstructor(String.class,String.class,int.class,double.class);
        Dog dog = (Dog) con.newInstance("小黑","德牧",5,30.5);
        methods.invoke(dog);
    }

结果
在这里插入图片描述

5 综合案例

做一个简易的配置文件:创建一个Dog对象,用反射将对象的成员变量及其对应值保存到本地文件中。

    public static void main(String[] args) throws Exception {
        Class cla = Class.forName("day10.Dog");
        Constructor con = cla.getConstructor(String.class,String.class,int.class,double.class);
        Dog dog = (Dog) con.newInstance("招财","中华田园犬",6,30.5);

        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("dog.txt"));

        Field[] fields = cla.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String name = field.getName();
            Object value = field.get(dog);
            bufferedWriter.write(name + "=" + value);
            bufferedWriter.newLine();
        }
        bufferedWriter.close();


    }

结果
在这里插入图片描述
反之,当你有一个类的配置文件时,你可以利用Properties(Properties 类是 Hashtable 的子类,该对象用于处理属性文件)和反射来对这个类进行操作。

6 反射的优点和缺点

优点
(1)反射机制可以动态地创建和使用对象,这在一些框架的开发中非常重要。它提供了灵活性,使得代码可以在运行时根据需要创建对象,并且可以对对象执行各种操作。
(2)反射机制是一些框架的核心组成部分,使得框架可以更加动态和可扩展。

缺点
(1)使用反射机制进行对象操作基本上是解释执行的,而不是直接的原生代码执行。这导致了执行速度较慢,相对于直接调用对象的方法或访问对象的属性,使用反射会带来一定的性能损失。因此,在对性能要求较高的情况下,使用反射可能会影响程序的执行速度,需要权衡利弊来选择是否使用反射机制。
(2)使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。

   public static void main(String[] args) throws Exception {
        Class cla = Class.forName("day10.Dog");
        Constructor con = cla.getConstructor();

        long start = System.currentTimeMillis();
        for(int i = 0 ; i < 100000 ; i ++) {
            Dog dog = (Dog) con.newInstance();
        }
        long end = System.currentTimeMillis();
        System.out.println("反射执行10万次所用时间 = "+ (end - start));


        long start1 = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            Dog dog = new Dog();
        }
        long end1 = System.currentTimeMillis();
        System.out.println("new执行10万次所用时间 = "+ (end1 - start1));
    }

结果
在这里插入图片描述

7 new对象和反射区别

使用new关键字创建对象和使用反射创建对象的主要区别如下:

(1)创建方式:使用new关键字创建对象时,直接调用类的构造方法进行实例化。而使用反射创建对象时,需要通过Class对象获取构造方法,然后调用构造方法进行实例化。

(2)可见性:使用new关键字创建对象时,需要在代码中显式引用类名来调用构造方法,因此构造方法必须具有相应的可见性(public、protected或默认访问修饰符)。而使用反射创建对象时,可以通过Class对象访问和调用非公共构造方法(即使是私有构造方法)。

(3)运行时确定:使用new关键字创建对象时,对象的创建在编译时就已经确定,并且编译器可以对其进行类型检查和优化。而使用反射创建对象时,对象的创建是在运行时动态确定的,无法在编译时进行类型检查和优化。

(4)异常处理:在使用new关键字创建对象时,如果构造方法抛出异常,可以在代码中使用try-catch块来捕获并处理异常。而使用反射创建对象时,由于构造方法调用是通过反射调用的,因此需要使用try-catch块来捕获InvocationTargetException异常,并从中获取原始的构造方法抛出的异常。

(5)性能:使用new关键字创建对象的性能通常比使用反射创建对象的性能更好。因为反射需要通过类的元数据进行额外的操作,如查找构造方法、参数匹配等,这些操作相对于直接调用构造方法来说更加耗时。

总体而言,使用new关键字创建对象是最常见和推荐的方式,因为它更简单、直观,并且具有更好的性能。而使用反射创建对象主要用于一些特殊需求,如动态加载类、调用私有构造方法等,在一般情况下并不常用。

Dog dog = new Dog()

在这里插入图片描述

Class cla = Class.forName("day10.Dog");

在这里插入图片描述
通过JVM的ClassLoader将class加载到内存,反射获取类信息等信息进行对成员变量和方法进行操作。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值