反射浅析
- 普通的开发流程是已知对象来获取属性
- 而反射的流程是——已知属性来获取对象
但我认为反射本身比较抽象
可能是我一开始学Java基础没打好的原因,在学习到框架的时候。就感觉很吃力,学习流于形式。知其然,但不知其所以然。忘的比学的快。到最后还是得反过来啃下反射这块硬骨头。
反射机制
- 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
- 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射
- p对象--》类型Person类
- Class对象cls --->类型Class类
如果只是简单的了解反射有什么用,最常见的其实就两个
- 根据类名创建实例(类名可以从配置文件读取,不用new,达到解耦)
- 用Method.invoke执行方法
下面java代码的全部流程,我将大体的给大家理顺一下
反射在哪里执行?
其中反射就英语在加载阶段与运行阶段之间
直观展示,上代码,走cmd!
import java.lang.reflect.Method;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Scanner scanner = new Scanner(System.in);
System.out.printf("请输入key");
String key = scanner.next();
switch (key) {
case "1":
Dog dog = new Dog();//静态加载,依赖性很强
dog.cry();
break;
case "2":
//反射->动态加载
Class cls = Class.forName("Cat"); //加载Person类[动态加载]
Object o = cls.newInstance();
Method m = cls.getMethod("hi");
m.invoke(o);
System.out.println("ok ");
break;
default:
System.out.println("do nothing..");
}
}
}
class Dog {
public void cry() {
System.out.printf("汪汪汪");
}
}
因为new Dog()是静态加载,因此必须编写Dog
Cat类是动态加载,所以,没有编写Cat类也不会报错,只有当动态加载该类时,才会报错
出现class类说明编译成功
结果如下 说明
我们再追加Cat类的相关信息
class Cat {
public void hi() {
System.out.printf("喵喵喵");
}
}
编译 运行
All in all
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
反射技术
反射的基本的概念
使用反射机制可以动态获取当前class的信息 比如方法的信息、注解信息、方法的参数、属性等;
反射技术应用的场景
-
JDBC加载驱动连接 class.forname
-
Spring容器框架IOC实例化对象
-
自定义注解生效(反射+Aop)
-
第三方核心的框架
反射技术的使用
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
使用反射机制初始化对象 获取当前class的信息
Class aClass = Class.forName("com.mayikt.entity.UserEntity");
执行无参数构造函数
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity");
UserEntity userEntity = (UserEntity) aClass.newInstance();
userEntity.setName("mayikt");
userEntity.setUserId(1234);
System.out.println(userEntity);
执行有参数构造函数
Class\<?> aClass = Class.forName("com.mayikt.entity.UserEntity"); // 执行有参数构造函数
Constructor<?> constructor = aClass.getConstructor(Integer.class, String.class);
UserEntity userEntity = (UserEntity) constructor.newInstance(10, "mayikt");
System.out.println(userEntity);
使用反射机制给属性赋值
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity"); // 给私有属性赋值
UserEntity userEntity = (UserEntity) aClass.newInstance();
Field userId = aClass.getDeclaredField("userId");
userId.setAccessible(true); userId.set(userEntity,12);
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(userEntity,"mayikt");
System.out.println(userEntity);
- Exception in thread "main" java.lang.IllegalAccessException: Class com.mayikt.Test001 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)
如果使用反射给私有属性或者调用私有的方法 都需要设置权限
使用反射机制给调用方法
Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity"); // 给私有属性赋值
UserEntity userEntity = (UserEntity) aClass.newInstance();
Method meite = aClass.getDeclaredMethod("meite", Integer.class);
meite.setAccessible(true); //这一步 暴力反射
Object invoke = meite.invoke(userEntity, 10); S
ystem.out.println(invoke);