反射机制
反射(Reflect)是在运行时动态访问类与对象的技术
反射是JDK1.2版本后的高级特性,隶属于java.lang.reflect
大多数Java框架都基于反射实现参数配置、动态注入等特性
反射的核心类
Class类
Constructor构造方法类
Method方法类
Field成员变量类
Class类
Class是JVM中代表"类和接口"的类
Class对象具体包含了某个特定类的结构信息
通过Class对象可获取对应类的构造方法/方法/成员变量
Class类 主要用于获得指定类的信息,方法或成员变量
Class类的核心方法
/**
* 员工实体类
*/
public class Employee {
static {
System.out.println("Employee类已被加载到jvm,并已初始化");
}
private Integer eno;
private String ename; // public String ename;/
private Float salary;
private String dname;
public Employee(){
System.out.println("Employee默认构造方法已执行。");
}
public Employee(Integer eno, String ename, Float salary, String dname){
this.eno = eno;
this.ename = ename;
this.salary = salary;
this.dname = dname;
System.out.println("Employee带参构造方法已执行");
}
public Integer getEno() {
return eno;
}
public void setEno(Integer eno) {
this.eno = eno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Float getSalary() {
return salary;
}
public void setSalary(Float salary) {
this.salary = salary;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Employee{" +
"eno=" + eno +
", ename='" + ename + '\'' +
", salary=" + salary +
", dname='" + dname + '\'' +
'}';
}
public Employee updateSalary(Float val){
this.salary = this.salary + val;
System.out.println(this.ename + "调薪至" + this.salary + "元");
return this;
}
}
// 反射动态加载Employee类对象。
import com.imooc.reflect.entity.Employee;
import java.lang.reflect.InvocationTargetException;
public class ClassSample {
public static void main(String[] args) {
Class employeeClass = null;
try {
// Class.forName ()方法将指定的类加载到jvm,并返回对应class对象
employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee类已被加载到jvm中");
// class.getDeclaredConstructor().newInstance()通过默认构造方法创建新的对象, 返回Object对象所以需要强制转换为指定的类对象
Employee emp = (Employee) employeeClass.getDeclaredConstructor().newInstance();
System.out.println(emp);
// 对象无法被实例化,抛出"实例化异常", 如abstract类无法被实例化
} catch (InstantiationException e) {
throw new RuntimeException(e);
// 非法访问异常,当在作用域外访问对象方法或成员变量时抛出
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
// 类名与类路径书写错误是抛出"类无法找到"异常
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
Constructor构造方法类
Constructor类是对Java类中的构造方法的抽象
Contructor对象包含了具体类的某个具体构造方法的声明
通过Constructor对象调用带参构造方法创建对象
Constructor类核心方法
import com.imooc.reflect.entity.Employee;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ConstructorSample {
public static void main(String[] args) {
Class employeeClass = null;
try {
employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee类已被加载到jvm中");
Constructor constructor = employeeClass.getConstructor(new Class[]{Integer.class, String.class, Float.class, String.class});
Employee emp = (Employee) constructor.newInstance(new Object[]{100, "李雷", 3000f, "研发部"});
System.out.println(constructor);
System.out.println(emp);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
// 没有找到与之对应格式的方法
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
// 当被调用的方法的内部抛出了异常而没有被捕获时
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Method方法类
Method对象指代某个类中的方法的描述
Method对象使用classObj.getMethod()方法获取
通过Method对象调用指定对象的对应方法
Method核心类方法
import com.imooc.reflect.entity.Employee;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodSample {
public static void main(String[] args) {
Class employeeClass = null;
try {
employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee类已被加载到jvm中");
Constructor constructor = employeeClass.getConstructor(new Class[]{Integer.class, String.class, Float.class, String.class});
Employee emp = (Employee) constructor.newInstance(new Object[]{100, "李雷", 3000f, "研发部"});
Method updateSalaryMethod = employeeClass.getMethod("updateSalary", new Class[]{Float.class});
Employee employee1 = (Employee) updateSalaryMethod.invoke(emp, new Object[]{1000f});
System.out.println(constructor);
System.out.println(employee1);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Field成员变量类
Field对应某个具体类中的成员变量的声明
Field对象使用classObj.getField()方法获取
通过Field对象可为某对象成员变量赋值/取值
Field类核心方法
import com.imooc.reflect.entity.Employee;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class FieldSample {
public static void main(String[] args) {
try {
Class employeeClass = null;
employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee类已被加载到jvm中");
Constructor constructor = employeeClass.getConstructor(new Class[]{Integer.class, String.class, Float.class, String.class});
Employee emp = (Employee) constructor.newInstance(new Object[]{100, "李雷", 3000f, "研发部"});
Field enameField = employeeClass.getField("ename");
String ename = (String) enameField.get(emp);
System.out.println(emp);
System.out.println("ename:" + ename);
enameField.set(emp, "王五");
System.out.println(emp);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
}
getDeclared系列方法
getDeclaredConstructor(s)|Method(s)|Field(s)获取(单个/所有)对应对象
getConstructor(s)|Method(s)|Field(s)只能获取public对象, 访问非作用域内构造方法、方法、成员变量,会抛出异常
import com.imooc.reflect.entity.Employee;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class getDeclaredSample {
public static void main(String[] args) {
try {
Class employeeClass = null;
employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee类已被加载到jvm中");
Constructor constructor = employeeClass.getConstructor(new Class[]{Integer.class, String.class, Float.class, String.class});
Employee emp = (Employee) constructor.newInstance(new Object[]{100, "李雷", 3000f, "研发部"});
Field[] fields = employeeClass.getDeclaredFields();
for (Field field : fields){
System.out.println(field.getName());
if (field.getModifiers() == 1){// getModifiers获得变量的修饰符, 1为public
// 公有的变量可以直接用get方法来获取对应的值, 用Object对象来接收是因为不确定实体类变量的类型
Object val = field.get(emp);
System.out.println(field.getName() + ":" + val);
} else if (field.getModifiers() == 2) { // 2为private
// 私有的变量可以通过实体类自己的get/set方法来获取值,首先需要得到实体类get方法的字符串
String methodName = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
Method getMethod = employeeClass.getMethod(methodName);
// 调用实体类自己的get方法来获取变量的值
Object ret = getMethod.invoke(emp);
System.out.println(field.getName() + ":" + ret);
}
}
System.out.println(emp);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
反射机制应用例子
// 所有实体类实现的接口
public interface I18N {
public String say();
}
// 实体类1
public class Zhcn implements I18N{
@Override
public String say() {
return "生命不息奋斗不止";
}
}
// 实体类2
public class En implements I18N{
@Override
public String say() {
return "Cease to the struggle and cease to the life";
}
}
// 应用测试类
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URLDecoder;
import java.util.Properties;
public class Application {
public static void say(){
// 加载配置文件。
Properties properties = new Properties();
String configPath = Application.class.getResource("/config.properties").getPath();
try {
configPath = new URLDecoder().decode(configPath,"UTF-8");
properties.load(new FileInputStream(configPath));
String language = properties.getProperty("language");
// 因为所有的实体类都实现了I18N接口所以可以把返回值转换为I18N接口类型。
I18N i18n = (I18N) Class.forName(language).getDeclaredConstructor().newInstance();
System.out.println(i18n.say());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
Application.say();
}
}
// 配置文件
language = com.imooc.i18n.Zhcn
通过反射机制动态的加载实体类,之后再有新的实体类需要添加的时候只需要将新的实体类放到路径下并修改配置文件就可以了,不需要修改其他的代码,方便应用更新。