反射的概念
Java反射机制允许程序在运行时通过Reflection API获得类的全部信息,并拥有访问权。
反射的触发时机
要想知道反射在什么时候起作用,就得先了解一下类加载过程,冯·诺依曼定义的计算机模型中,任何程序都需要加载到内存才能与CPU进行交流。字节码.class文件同样需要加载到内存中,才可以实例化。类加载就是一个将.class字节码文件实例化成java.lang.Class对象并进行相关初始化的过程。
根据上图便能够清楚的看到反射是在程序运行期间发挥作用的。
反射的应用场景
1 框架设计的底层,如Spring框架 IOC控制反转
2 数据库驱动的加载,Class.forName(“com.mysql.jdbc.Driver”);
3 繁琐重复代码的优化,很多代码生成工具都是借助反射技术实现的
反射机制的应用场景十分广泛,此处仅列举以上3种作为参考
案例演示
业务需求:开发一个工具类,在不修改工具类代码的情况下,用户只需要简单的配置就能够完成对象的创建以及方法的调用。
程序设计:
为了方便大家理解,我们给业务需求引入一个特定的场景
游戏中有两名英雄角色供玩家选择
角色1:
姓名:安琪拉
职业:中单
一技能:程序中会使用public修饰,代表角色行为的方法
被动:程序中会使用private修饰,代表角色行为的方法
角色2
姓名:凯
职业:上单
一技能:程序中会使用public修饰,代表角色行为的方法
被动:程序中会使用private修饰,代表角色行为的方法
此时我们需要一个配置文件供玩家配置想要选择的英雄角色以及要释放的技能
people.properties
接着我们只需要创建一个普通的maven工程,借助java反射机制就可以实现以上业务场景,工程目录结构如下
代码示例
定义角色1 AnQiLa
package com.demo.roles;
public class AnQiLa {
private String name="安琪拉";
private String job="中单";
//私有化角色触发被动技能的方法
private String getPassiveSkill(){
return name+": [触发了被动技能!]";
}
//角色一技能
public String getFirstSkill(){
return name+": [在中路使用了一技能]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
定义角色2 Kai
package com.demo.roles;
public class Kai {
private String name="凯";
private String job="上单";
//私有化角色触发被动技能的方法
private String getPassiveSkill(){
return name+": [触发了被动技能!]";
}
//角色一技能
public String getFirstSkill(){
return name+": [在上路使用了一技能]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
开发业务场景工具类
package com.demo.controller;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectUtil {
public static void main(String[] args) throws Exception {
//加载玩家配置信息
Properties properties = new Properties();
ClassLoader classLoader = ReflectUtil.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("people.properties");
properties.load(resourceAsStream);
//从配置文件中读取玩家选择的英雄角色
String role = properties.getProperty("object.role");
//从配置文件中读取玩家使用的技能
String actions = properties.getProperty("method.skills");
String[] skills = actions.split(",");
//通过反射实例化玩家选择的角色对象
Class aClass = Class.forName(role);
Object instance = aClass.newInstance();
//遍历玩家选择使用的技能
for (String skill : skills) {
//获取玩家使用角色的所有技能
Method declaredSkill = aClass.getDeclaredMethod(skill);
//判断获得的技能是否私有
if (declaredSkill.toString().contains("private")) {
//如果是私有的被动技能,则需设置私有技能可使用
declaredSkill.setAccessible(true);
//使用被动
Object invoke = declaredSkill.invoke(instance, null);
System.out.println(invoke.toString());
} else {
//如果是普通技能 则可以直接访问
Object invoke = declaredSkill.invoke(instance, null);
System.out.println(invoke.toString());
}
}
}
}
接下来玩家只需要通过更改people.properties配置文件选择需要使用的角色和需要使用的技能,工具类就可以帮我们完成角色的创建以及技能的释放
#玩家配置需要选择的英雄角色
#选择AnQiLa[安琪拉]
object.role=com.demo.roles.AnQiLa
#玩家配置需要使用的技能,多个技能之间用英文逗号隔开
#选择使用一技能并触发私有的被动技能
method.skills=getPassiveSkill,getFirstSkill
运行结果1
F:\software\Java\jdk1.8.0_121\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2019.1.4\lib\idea_rt.jar=63738:D:\IntelliJ IDEA 2019.1.4\bin" -Dfile.encoding=UTF-8 -classpath F:\software\Java\jdk1.8.0_121\jre\lib\charsets.jar;F:\software\Java\jdk1.8.0_121\jre\lib\deploy.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\access-bridge-64.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\cldrdata.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\dnsns.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\jaccess.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\jfxrt.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\localedata.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\nashorn.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunec.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunjce_provider.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunmscapi.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunpkcs11.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\zipfs.jar;F:\software\Java\jdk1.8.0_121\jre\lib\javaws.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jce.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jfr.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jfxswt.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jsse.jar;F:\software\Java\jdk1.8.0_121\jre\lib\management-agent.jar;F:\software\Java\jdk1.8.0_121\jre\lib\plugin.jar;F:\software\Java\jdk1.8.0_121\jre\lib\resources.jar;F:\software\Java\jdk1.8.0_121\jre\lib\rt.jar;D:\ideastudyspace\spring_study\reflect-demo\target\classes com.demo.controller.ReflectUtil
安琪拉: [触发了被动技能!]
安琪拉: [在中路使用了一技能]
Process finished with exit code 0
假如玩家此时想玩上单使用凯,直接在people.properties配置文件里选择即可
#玩家配置需要选择的英雄角色
#选择Kai[凯]
object.role=com.demo.roles.Kai
#玩家配置需要使用的技能,多个技能之间用英文逗号隔开
#选择使用一技能并触发私有的被动技能
method.skills=getPassiveSkill,getFirstSkill
运行结果2
F:\software\Java\jdk1.8.0_121\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2019.1.4\lib\idea_rt.jar=63947:D:\IntelliJ IDEA 2019.1.4\bin" -Dfile.encoding=UTF-8 -classpath F:\software\Java\jdk1.8.0_121\jre\lib\charsets.jar;F:\software\Java\jdk1.8.0_121\jre\lib\deploy.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\access-bridge-64.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\cldrdata.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\dnsns.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\jaccess.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\jfxrt.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\localedata.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\nashorn.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunec.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunjce_provider.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunmscapi.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\sunpkcs11.jar;F:\software\Java\jdk1.8.0_121\jre\lib\ext\zipfs.jar;F:\software\Java\jdk1.8.0_121\jre\lib\javaws.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jce.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jfr.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jfxswt.jar;F:\software\Java\jdk1.8.0_121\jre\lib\jsse.jar;F:\software\Java\jdk1.8.0_121\jre\lib\management-agent.jar;F:\software\Java\jdk1.8.0_121\jre\lib\plugin.jar;F:\software\Java\jdk1.8.0_121\jre\lib\resources.jar;F:\software\Java\jdk1.8.0_121\jre\lib\rt.jar;D:\ideastudyspace\spring_study\reflect-demo\target\classes com.demo.controller.ReflectUtil
凯: [触发了被动技能!]
凯: [在上路使用了一技能]
Process finished with exit code 0