反射
课程内容
今天晚上第九期Java进阶班级第一次vip课:
标题:<Java基础知识回顾之反射/自定义注解实现原理/手写注解限流框架>
课程内容:
1.什么是反射、反射优缺点
2.反射的用途/反射应用场景
3.反射调用方法/给属性赋值
4.反射如何越过泛型检查
5.什么是注解/注解生效的原理
6.自定义注解实现API接口限流框架
7.自定义注解实现事务注解
反射机制
什么是反射
- Oracle 官方对反射的解释是:
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.
2.简而言之,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。
3.
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
使用反射机制可以动态获取当前class的信息比如方法的信息、注解信息、方法的参数、属性等;
.java 源代码编译.class 类加载器 jvm 字节码
反射机制的优缺点
第三方框架---创建对象 不是直接new 反射机制创建
目的:提供开发者能够更好封装框架实现扩展功能。
在一个类中 定义了一个私有属性/方法 反射机制破解私有属性
1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:
(1)反射会消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
反射的用途:
反编译:.class-->.java
1.通过反射机制访问java对象的属性,方法,构造方法等
3. JDBC加载驱动连接 class.forname
Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动
4. Spring容器框架IOC实例化对象
<bean id="mayikt" class="com.mayikt.UserEntity" /> |
5. 自定义注解生效(反射+Aop)
6. 第三方核心的框架 mybatis orm
反射技术的使用
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
1.getField、getMethod和getCostructor方法可以获得指定名字的域、方法和构造器。
2.getFields、getMethods和getCostructors方法可以获得类提供的public域、方法和构造器数组,其中包括超类的共有成员。
3.getDeclatedFields、getDeclatedMethods和getDeclaredConstructors方法可以获得类中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员。
反射常用的Api
(1)Object-->getClass
(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法:forName(String className)(最常用)
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity");
// 1.第一种获取class方式
|
运行期间,一个类,只有一个Class对象产生
验证:
import com.mayikt.entity.UserEntity;
|
反射执行构造函数
执行无参数构造函数
Class<?> userClass3 = Class.forName("com.mayikt.entity.UserEntity");
|
执行有参数构造函数
Constructor<?> constructor = userClass3.getConstructor(String.class, Integer.class);
|
反射执行给属性赋值
反射执行给公有属性赋值
// 1.给共有属性赋值
|
反射执行给私有属性赋值
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity"); |
注意:
xception in thread "main" java.lang.IllegalAccessException: Class com.mayikt.test.Test03 can not access a member of class com.mayikt.entity.UserEntity with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.set(Field.java:761)
at com.mayikt.test.Test03.main(Test03.java:28)
解决办法:
// 设置允许访问私有属性
userName.setAccessible(true);
反射执行调用方法
反射调用公有方法
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity");
|
反射调用私有方法
// 1.使用反射调用共有方法
|
Exception in thread "main" java.lang.IllegalAccessException: Class com.mayikt.test.Test04 can not access a member of class com.mayikt.entity.UserEntity with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.mayikt.test.Test04.main(Test04.java:23)
解决办法:
// 2.设置允许调用私有方法
mayikt.setAccessible(true);
反射调用方法传递参数
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity");
|
通过反射越过泛型检查
泛型用在编译期,编译过后泛型擦除(消失掉),所以是可以通过反射越过泛型检查的
ArrayList<String> strings = new ArrayList<String>();
|