java反射

一、反射的概述
  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
  要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。

以上的总结就是什么是反射
  反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

在这里插入图片描述
二、反射的使用
反射的使用主要有以下几个方面:
1、类加载器
1、获取class对象的三种方式;
2、通过反射获取构造方式、使用构造方法;
3、获取成员变量并调用;
4、获取成员方法并调用;
5、反射main方法;
6、反射方法的其它使用之—通过反射运行配置文件内容;
7、反射方法的其它使用之—通过反射越过泛型检查。

1、获取Class对象的三种方式:
Class类
  对象照镜子后可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
  Class 对象只能由系统建立对象
  一个类在 JVM 中只会有一个Class实例
  每个类的实例都会记得自己是由哪个 Class 实例所生成

类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序使用任何一个类时,系统都会为之生成一个java.lang.Class对象。
   类的加载通常由类加载器完成,类加载器通常由JVM提供。
    获取Class对象的三种方法如下:

1) 调用对象的getClass()方法,该方法是java.lang.Object中的一个方法;
 2) 通过类的class属性来获取该类对应的class对象,如Person.class将返回Person类对应的class对象 
3) 使用Class类的forName静态方法:forName(String  className)   
其中第一种是因为Object类中的getClass方法、因为所有类都继承Object类。从而调用Object类来获取

反射相关的主要API

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器

三、运行时类
3.1 创建运行时类的对象
调用Class对象的newInstance()方法,该方法会调用类的空参构造器来创建运行时类的对象。该方法正常运行需要2个要求:① 运行时类必须提供空参构造器;② 空参构造器的权限需要够

Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
System.out.println(person);

3.2 获取运行时类的完整结构
3.2.1 获取属性

getFields():获取当前运行时类及其父类中声明为public权限的属性
getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类)
对所获得的属性调用相应的方法,可获得对应属性的:权限修饰符、数据类型、变量名

3.2.2 获取方法

getMethods():获取当前运行时类及其父类中声明为public权限的方法
getDeclaredMethods():获取当前运行时类中声明的所有方法
对所获得的方法调用相应的方法,可获得对应方法的:注解、权限修饰符、返回值类型、方法名、形参列表、异常

getAnnotations():获取方法上的注解(注解必须是RUNTIME类型才可获取)
3.2.3 获取构造器

getConstructors():获取当前运行时类中声明为public的构造器(不包括父类)
getDeclaredConstructors():获取当前运行类中所有构造器
3.2.4 获取父类及父类的泛型

getSuperclass():获取当前运行时类的父类
getGenericSuperclass():获得当前运行时类带泛型的父类
getActualTypeArguments():获取父类的泛型
3.2.5 获取接口、包、注解

getInterfaces():获取当前运行时类的接口
getPackage():获取当前运行时类所在的包
getAnnotations():获取当前运行时类上的注解
3.3 调用运行时类的指定结构
3.3.1 调用属性

getField(String name):获取对象的某个public属性(不通用)
getDeclaredField(String name):获取对象的某个属性
setAccessible(true):将某个属性设为可访问
get(obj):获取某个对象该属性的值(静态属性可写null)
set(obj,value):设置某个对象该属性的值
3.3.2 调用方法

getMethod(String name,Class… parameterTypes):获取public方法(不通用)
getDeclaredMethod(String name,Class… parameterTypes):获取方法
setAccessible(true):将某个方法设为可访问
invoke(Object obj,Object… args):执行obj对象的该方法,返回所调用方法的返回值(静态方法不用知道具体对象,可写null)
3.3.3 调用构造器

newInstance():调用空参构造器生成对象(运行时类调用,最常用)
getDeclaredConstructor(Class… parameterTypes):获取知道构造器
setAccessible(true):将某个构造器设为可访问
newInstance(Object… args):调用此构造器创建运行时类的对象(运行时类的构造器调用)

Class<Person> aClass = Person.class;
Constructor<Person> constructor = aClass.getConstructor(String.class, int.class);
Person tom = constructor.newInstance("Tom", 12);
System.out.println(tom.toString());
Field age = aClass.getDeclaredField("age");
age.setAccessible(true);
age.set(tom, 10);
System.out.println(tom);
Method show = aClass.getDeclaredMethod("show");
show.invoke(tom);

四、 反射的优缺点:

优点:
能够在运行时动态获取类的实例,提高灵活性
与动态编译结合
缺点:
使用反射性能较低,需要解析字节码,将内存中的对象进行解析
与正常的java代码相比较,效率低。

getMethod和getDeclaredField方法会比invoke和set方法耗时;

随着测试数量级越大,性能差异的比例越趋于稳定;

不要过于频繁地使用反射,大量地使用反射会带来性能问题;

通过反射直接访问实例会比访问方法快很多,所以应该优先采用访问实例的方式。

相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)

反射应用场景:
加载配置文件 加载JDBC驱动
通过反射调用Servlet
大部分框架都会使用反射 注入属性 调用方法 实例化等等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值