文章目录
- 1. 反射机制
- 1.1 什么是反射
- 1.2 反射机制的优缺点
- 1.3 反射的用途
- 1.4 反射技术的使用
- 1.4.1 反射常用的Api
- 1.4.2 反射执行构造函数
- 1.4.3 反射执行给属性赋值
- 1.4.4 反射执行调用方法
1. 反射机制
1.1 什么是反射
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.
java反射机制的核心就是在程序运行时动态的获取类的信息, 进而控制类或对象的属性和方法 它的本质就是jvm在取得class对象之后进行反编译,从而获取类的各种信息
java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁
1.2 反射机制的优缺点
反射常用于第三方框架
1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:
(1)反射会消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
目的:提供开发者能够更好封装框架实现扩展功能。
1.3 反射的用途
- 反编译:.class–>.java
- 通过反射机制访问java对象的属性,方法,构造方法等
- JDBC加载驱动连接 class.forname
Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动
- Spring容器框架IOC实例化对象
<bean id="elementheat" class="com.elementheat.UserEntity" />
- 自定义注解生效(反射+Aop)
- 第三方核心的框架 mybatis orm
1.4 反射技术的使用
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
1.getField、getMethod和getCostructor方法可以获得指定名字的域、方法和构造器。
2.getFields、getMethods和getCostructors方法可以获得类提供的public域、方法和构造器数组,其中包括超类的共有成员。
3.getDeclatedFields、getDeclatedMethods和getDeclaredConstructors方法可以获得类中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员。
1.4.1 反射常用的Api
(1) Object–>getClass
(2) 任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法:forName(String className)(最常用)
// 方法1
User user = new User();
Class userClass1 = user.getClass();
// 方法2
Class userClass2 = User.class;
// 方法3
Class userClass3 = Class.forName("com.example.demo.pojo.User")
//运行期间,一个类,只有一个Class对象产生
// userClass1==userClass2==userClass3
1.4.2 反射执行构造函数
无参构造函数
User userInstance = (User) userClass.newInstance();
有参构造函数
Constructor constructor = userClass.getConstructor(String.class, int.class);
User userInstance = (User) constructor.newInstance("test", 5);
1.4.3 反射执行给属性赋值
查看所有属性
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
Field[] declaredFields = userClass.getDeclaredFields();
Arrays.stream(declaredFields).forEach((field -> System.out.println(field.getName())));
公有属性赋值
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Field usernameField = userClass.getField("username");
usernameField.set(user,"myName");
System.out.println(user);
私有属性赋值
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Field idField = userClass.getDeclaredField("id");
//允许访问私有属性
idField.setAccessible(true);
idField.set(user,"111");
System.out.println(user);
1.4.4 反射执行调用方法
查看所有方法
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
Method[] declaredMethods = userClass.getDeclaredMethods();
Arrays.stream(declaredMethods).forEach(method -> System.out.println(method.getName()));
调用公有方法
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Method publicMethod = userClass.getMethod("publicMethod");
publicMethod.invoke(user);
调用私有方法
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Method privateMethod = userClass.getDeclaredMethod("privateMethod");
//允许调用私有方法
privateMethod.setAccessible(true);
privateMethod.invoke(user);
调用方法传递参数
Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Method paramMethod = userClass.getDeclaredMethod("paramMethod", Integer.class, Integer.class);
Object invoke = paramMethod.invoke(user,1,2);
System.out.println(invoke);
通过反射越过泛型检查
ArrayList<String> strings = new ArrayList<>();
strings.add("test");
Class<? extends ArrayList> aClass = strings.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
add.invoke(strings,5);
System.out.println(strings);
//foreach遍历时会报错 因为foreach限定了每个元素的类型, 无法强转Integer-String则报错
strings.forEach(s -> System.out.println(s));
泛型用在编译期,编译过后泛型擦除(消失掉),所以是可以通过反射越过泛型检查的