反射
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
框架:半成品软件,可以在框架的基础上进行开发,而框架本身不能运行
反射:反射是框架的灵魂。将类的各个组成部分封装为其他对象
反射的好处:可以在程序运行的过程中去操作对象、字节码文件,不需要重新编译。提高程序拓展性、复用性,解耦。
程序在计算机中的三个阶段
Class
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。
- 获得类的相关的方法 | 方法 | 用途 | | —- | —- | | asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 | | getClassLoader() | 获得类的加载器 | | getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 | | getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 | | forName(String className) | 根据类名返回类的对象 | | getName() | 获得类的完整路径名字 | | newInstance() | 创建类的实例 | | getPackage() | 获得类的包 | | getSimpleName() | 获得类的名字 | | getSuperclass() | 获得当前类继承的父类的名字 | | getInterfaces() | 获得当前类实现的类或是接口 | | .class | 获取当前对象的类 |
- 获得类中字段相关的方法 | 方法 | 用途 | | —- | —- | | getField(String name) | 获得某个公有的字段对象 | | getFields() | 获得所有公有的字段对象 | | getDeclaredField(String name) | 获得某个字段对象 | | getDeclaredFields() | 获得所有字段对象 |
- 获取类中注解相关的方法 | 方法 | 用途 | | —- | —- | | getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
- 获取类中构造器相关的方法 | 方法 | 用途 | | —- | —- | | getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 | | getConstructors() | 获得该类的所有公有构造方法 | | getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 | | getDeclaredConstructors() | 获得该类所有构造方法 |
- 获得类中方法相关的方法 | 方法 | 用途 | | —- | —- | | getMethod(String nane,Class…<?> parameterTypes) | 获得该类某个公有的方法 | | gstMethods() | 获得该类所有公有的方法 | | getDeclaredMethod(String nane,Class…<?> parameterTypes) | 获得该类某个方法 | | getDeclaredMethods() | 获得该类所有方法 |
- 类中其他重要的方法 | 方法 | 用途 | | —- | —- | | isAnnotation() | 如果是注解类型则返回true | | isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定类型注解类型则返回true | | isArray() | 如果是一个数组类则返回true | | isEnum() | 如果是枚举类则返回true | | isInstance(Object obj) | 如果obj是该类的实例则返回true | | isInstance() | 如果是接口类则返回true |
Field
Field代表类的成员变量。成员变量(字段)和成员属性是两个概念。比如:当一个User类中有一个name变量,那么这个时候我们就说它有name这个字段。但是如果没有getName和setName这两个方法,那么这个类就没有name属性。反之,如果这个类拥有getAge和 setAge这两个方法,不管有没有age字段,我们都认为它有age这个属性
方法 | 用途 |
---|---|
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj,Object value) | 设置obj中对应属性值 |
SetAccessible | 暴力反射,忽略访问权限修饰符 |
Method
Method代表类的方法(不包括构造方法)。
方法 | 用途 |
---|---|
invoke(Object obj,Object… args) | 传递object对象及参数调用该对象对应的方法 |
getName | 获取方法名 |
SetAccessible | 暴力反射,忽略访问权限修饰符 |
Invoke方法的用处:SpringAOP在切面方法执行的前后进行某些操作,就是使用的invoke方法。
Constructor(用的比较少)
Constructor代表类的构造方法。
方法 | 用途 |
---|---|
newInstance(Object… initargs) | 根据传递的参数创建类的对象 |
Constructor 类在实际开发中使用极少,几乎不会使用Constructor。因为:Constructor违背了Java的一些思想,比如:私有构造不让用户去new对象;单例模式保证全局只有一个该类的实例。而Constructor则可以破坏这个规则
案例:写一个小工具,可以帮我们创建任意类的对象,并且执行其中任意方法案例:通过反射,验证运行中泛型会被擦除
List<User> userList = new Arraylist<>();
userList.add(new User(name:"张三", age:23, idNumber:"233"));
userList.add(new User(name:"李四", age:24, idNumber:"666"));
Class<? extends List> listClass = userlist.getClass();
Method addMethod = listClass.getDeclaredMethod(name:"add", Object.class);
addMethod.invoke(userList,123);
addMethod.invoke(userList,"哈哈哈");
System.out.print1n(userList);
注解
注释:用文字描述程序,给程序员看的。
定义:用来说明程序的一个标识,给计算机看的。注解也叫元数据,是一种代码级别的说明,它是jdk1.5之后引入的一个特性,是一种特殊的接口,可以使用在字段、类、方法、包、参数等上面。
注意:注解本身并没有任何功能,仅仅起到一个标识性的作用。我们是通过反射去获取到注解,再根据是否有这个注解、注解中的一些属性去判断,执行哪种业务逻辑。
作用分类:
编写文档:通过代码里的注解标识去生成API文档(Swagger)
代码分析:通过注解去对代码进行逻辑上的分析(通过反射去操作业务)
编译检查:通过注解让编译器实现基本的编译检查(Override,SuppressWarming)<br />JDK中预定义的一些注解
Overide:检测该注解标识的方法是否是继承自父类(接口)
Deprecated:标识该内容已过时,后续的版本可能会进行移除。<br /> SuppressWarmings;压制警告,指定警告级别,这个级别下的警告全部不显示
自定义注解
在实际开发中,可能存在一些代码极其复杂或者复用性很低的业务逻辑,比如:导出Excel、缓存、将返回值转JSON、事务等等等等,这个时候就可以使用自定义注解
格式
元注解
public @interface 注解名称{
属性列表;
}
本质:本质就是个接口,该接口继承Annotation接口
属性
本质:接口中的抽象方法
属性只能是以下几种数据类型:
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
如果定义了属性,在使用的时候需要给属性赋值。如果有默认值则可以不赋值
如果只有一个属性需要赋值,并且这个属性叫value,那么就可以省略属性名
数组赋值时,值用{}包裹,如果数组中只有一个值,那么大括号可以省略。
元注解
用于描述注解的注解
@Target:描述该注解作用范围
ElementType取值:
Type:作用于类<br /> METHOD:作用于方法<br /> FIELD:作用于字段<br />@Retention:描述注解被保留的阶段<br /> RetentionPolicy.RUNTIME:当前描述的注解,会保留到class字节码文件中,并被vm读取到<br />@Documented:描述注解是否被抽取到api文档中<br />@Inherited:描述注解是否可以被继承
总结:
反射:就是在程序运行中对Class、对象等进行一些列的操作注解:注解就是个标识,相当于是给程序看的注释。注解本身不存在功能,需要通过反射去进行某些判断,根据判断结果去执行对应的逻辑,这个过程就是给注解赋予功能的过程。
反射和自定义注解,在我们刚入职的时候,是用不到的,因为刚入职那段时间一般只会写crud。但是,反射和自定义注解是框架的基础,写框架、看源码则是架构师的基础。