Java反射知识整理

认识反射

什么是反射

Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类包括私有在内的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。

反射的优缺点

优点:

1. 反射可以根据类的全限定名去创建实例,增加程序的灵活性,避免将程序写死到代码里,达到解耦的效果。
2. 可用于开发各种通用框架。  
 很多框架都是基于配置文件的,为了保证框架的通用性,它们可能需要根据配置文件的不同加载不同的类,生成相应的对象。这个时候就需要用到反射——动态的加载需要加载的对象。

缺点:

1. 反射代码很难维护,在IDE中无法通过调用链关联进入对应的方法,同时IDE无法在编译期间发现一些问题。
	2. 反射的执行效率低,主要原因归结于反射代码只有在具体的调用中才能知道调用的具体类,因此只能以解释的方式进行,导致效率低下。
	3. 反射可以突破类的权限检查,调用私有方法,修改私有变量等,存在一定的安全问题。

反射的实际用途

  1. JDBC的数据库连接
    回想一下我们使用数据库连接的步骤中,第一步就是通过Class.forName()加载数据库的驱动程序,此处就是通过反射加载,前提是引入了相关的jar包。
  2. Spring框架的使用
    Java的反射机制在做基础框架的时候非常有用,例如Spring中用到了很多的反射机制。Spring通过XML配置模式装在Bean的过程:
1. 将xml或properties配置文件加载入内存中
2. Java类里面解析配置文件,得到对应实体类的字节码字符串以及相关属性信息
3. 使用反射机制,根据字符串获得某个类的Class实例
4. 动态配置实例的属性

这样做的好处有以下几点:

  1. 不用在代码中new对象的实例,在一定程度上达到解耦的作用
  2. 在日后的维护中更加方便,直接修改配置文件就可以,无需修改代码

使用反射

获取Class对象

Class对象是反射的根源,获取Class对象的方法共有三种:

  1. 通过Class类的forName()静态方法 (常用的一种形式)
Class<?> c1 = Class.forName("java.lang.Integer");
  1. 直接获取类的class (每个类都有一个隐含的静态成员class)
Class<?> c3 = Integer.class;
  1. 通过调用对象的getClass()方法 (通过对象调用方法,获取静态成员class)
Integer i1 = 1;
Class<?> c2 = i1.getClass();

利用Class对象创建对应实例

  1. 利用Class对象的newInstance()方法来创建该Class对象对应类的实例,要求有默认构造器。(适用于无参构造方法)
Class<User> userClass = User.class;
Object o = userClass.newInstance();
  1. 先使用Class对象获取指定的Construct对象,再调用Construct对象的newInstance()方法来创建。(适用于有参构造方法
Class<User> userClass = User.class;
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(Integer.class);
User user = declaredConstructor.newInstance(5);

判断是否是某个类的实例

  1. instanceof关键字
Class clzz = User.class;
Object o = clzz.newInstance();
boolean flag = o instanceof User;
  1. isInstance()方法
Class clzz = User.class;
Object o = clzz.newInstance();
boolean flag = User.class.isInstance(o);

利用Class对象获取类的成员信息

获取构造器

Class<User> userClass = User.class;
Constructor<?>[] constructors = userClass.getConstructors();
Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();

由实例可见,获取类中的构造器有两种方法,getConstructors()与getDeclaredContructors(),两个方法都可以获取类的构造器数组,不同的是,getConstructors()只能获取public修饰的构造器,而getDeclaredContructors()方法可以获取类中所有构造器,与访问权限无关。

获取属性字段

Class<User> userClass = User.class;
Field[] fields = userClass.getFields();
Field[] declaredFields = userClass.getDeclaredFields();

getFields():获取某个类及其父类的所有公共(public修饰)的字段。
getDeclaredFields():获取某个类自己声明的所有字段,与访问修饰符无关。

获取方法

Class<User> userClass = User.class;
Method[] methods = userClass.getMethods();
Method[] declaredMethods = userClass.getDeclaredMethods();

getMethods():获取某个类及其父类的所有public修饰的方法。
getDeclaredMethods():获取某个类自己声明的所有方法,与访问修饰符无关。

获取注解

Class clazz = User.class;
Field name = clazz.getDeclaredField("userName");
Annotation[] annotation = name.getAnnotations();