JAVA的反射

什么是反射

在运行时通过Class对象动态获取类信息,并且可以操作类或对象的内部属性。反射可以动态创建对象并调用其属性。而这种动态获取信息以及动态调用对象方法的功能就是JAVA的反射。

反射可以做什么

  1. 开发框架,例如Spring中动态创建bean
  2. IDE的代码提示
  3. 调试器,例如IDEA里的 Watches

一段简单的反射代码

//根据类的全限定名通过反射获取实例
Class c = Class.forName("com.it.boot_demo.entity.UserEntity");
System.out.println(c);
System.out.println(c.getName());
System.out.println(c.getSimpleName());

Class类详解

在反射中的作用

  1. 提供方法用于访问运行期间类的元数据;
  2. 提供方法用于检查和修改类的运行时行为;

获取Class的三种方式

//UserEntity为演示用实体类,包含用户名等属性
//通过forName方式获取Class
Class c1 = Class.forName("com.it.boot_demo.entity.UserEntity");
//类名.class
Class c2 = UserEntity.class;
//Object类的getClass()获取
UserEntity userEntity = new UserEntity();
Class c3 = userEntity.getClass();

演示对象:

public class UserEntity {
    private Integer id;
    private String username;
    private String email;
    private String address;
    //....省略构造方法和getter setter
}

Class类概览

通过反射可以访问主要的描述信息,贴一下网上的图

JAVA的反射_第1张图片
image

判断Class对应的类型

JAVA的反射_第2张图片
image

通过反射创建实例对象

  1. 通过Class对象的newInstance()方法创建,这种方式只能调用无参构造方法;
  2. 通过Constructor对象的newInstance()方法创建,这种方式适用于有参构造方法,并且还可以破坏单例模式,调用私有构造方法;

这里给出两种方式调用无参构造创建实例的代码:

Class.newInstance()

Class c = Class.forName("com.it.boot_demo.entity.UserEntity");
UserEntity userEntity = (UserEntity) c.newInstance();

Constructor对象的newInstance()

Class c = Class.forName("com.it.boot_demo.entity.UserEntity");
UserEntity userEntity = (UserEntity) c.getDeclaredConstructor().newInstance();

由于 Class.newInstance() 这种方式在JDK1.9中已经被废弃,不建议再使用,所以推荐构造器创建实例的方式。

Field类

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。提供了获取 public 、private字段,获取包括和不包括继承字段的API。具体API和用法可以参考官方文档,这里贴一篇相当不错的博客。需要特别注意的是被final关键字修饰的Field字段是安全的,在运行时可以接收任何修改,但最终其实际值是不会发生改变的。

https://blog.csdn.net/javazejian/article/details/70768369#commentBox

Type类

Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。

类型 常见表示
原始类型 类,枚举,数组,注解等
参数化类型 常用的泛型如 List、Map等
数组类型 不是指基本类型的 String[] ,int[] ,而是指带有泛型的数组 T[]
基本类型 java的基本类型 int,float,byte等

Type类型展开讲就又是比较多的内容了,这里就不展开讲了。对于几种类型的默认实现,大家可以去网上看一看博客。

Method类

method提供关于类或接口上单独的某个方法的信息,提供了获取方法参数类型,获取返回参数类型,获取参数长度等API,使用起来也比较简单,具体使用可以参考API,这里略过。

Array类

java.lang.reflect.Array 这个类被声明为final,不可被继承。提供了动态创建和访问数组的API,Array 允许在执行 get 或 set 操作进行取值和赋值。

简单总结

JAVA反射相关的很多API都是native的,也就是说并不是通过java代码来实现的,属于底层实现。所以这里不去讲这些源码,API贴太多也没太大意义,其实实际开发中反射用到的并不是很多,而写框架就用的比较多了。网上很多大佬都讲了反射,这篇文章也参考了不少。这里给出我对反射的理解。反射是要在运行时创建和操作一个对象,对于JVM来说要通过反射操作的这个类就是一个黑盒子。但是JAVA语言对于一个对象是有一些通用的定义的,比如会有属性,会有方法,属性又会有各种类型,方法又会有无参和有参,有返回和无返回的区别。知道了这些信息之后还需要通过构造方法来创建对象的实例,而反射提供给我们的就是这些API。

反射的注意事项

  1. 反射会额外的消耗系统性能,如果不需要动态创建对象,尽量不要使用反射
  2. 反射调用方法可以忽略权限检查,可能会造成一定的安全问题

JAVA的反射_第3张图片
image

你可能感兴趣的:(JAVA的反射)