内容概况
- 反射及作用
- 反射四个核心类
-
什么是反射Reflect
反射是在运行时动态访问类与对象的技术
- 反射是JDK1.2之后的高级特性,隶属于java.lang.reflect
大多数Java框架都基于反射实现参数配置、动态注入等特性 ```java public class ReflectSample { /**
传统的创建对象方式 */ public static void case1(){ Scanner scanner = new Scanner(System.in); System.out.print(“请输入计算类名:”); String op = scanner.next(); System.out.print(“请输入a:”); int a = scanner.nextInt(); System.out.print(“请输入b:”); int b = scanner.nextInt(); MathOperation mathOperation = null; if(op.equals(“Addition”)){
mathOperation = new Addition();
}else if(op.equals(“Subtraction”)) {
mathOperation = new Subtraction();
}else if(op.equals(“Multiplication”)){
mathOperation = new Multiplication();
}else{
System.out.println("无效的计算类");
return;
} float result = mathOperation.operate(a, b); System.out.println(result); }
/**
- 利用反射创建对象更加灵活
*/
public static void case2(){
Scanner scanner = new Scanner(System.in);
System.out.print(“请输入计算类名:”);
String op = scanner.next();
System.out.print(“请输入a:”);
int a = scanner.nextInt();
System.out.print(“请输入b:”);
int b = scanner.nextInt();
MathOperation mathOperation = null;
try {
}catch(Exception e){mathOperation = (MathOperation) Class.forName("com.imooc.reflect." + op).newInstance();
} float result = mathOperation.operate(a, b); System.out.println(result); }System.out.println("无效的计算类");
return;
public static void main(String[] args) {
ReflectSample.case2();
}
}
<a name="ZSVr7"></a>
## 反射的核心类
- Class类
- Constructor构造方法类
- Method方法类
- Field成员变量类
<a name="hzyLt"></a>
## Class类(描述其他类的一个类)
- Class是JVM中代表“类和接口”的类,和其他的标准的类没有任何区别,只是对其他的类和接口这一个特殊的类的抽象
- Class对象具体包含了某个特定类的结构信息
- 通过Class对象可获取对应类的构造方法、方法、成员变量
- Class核心方法
| 方法 | 用途 |
| --- | --- |
| Class.forName() | 静态方法,用于获取指定Class对象 |
| classObj.newInstance() | 通过默认构造方法创建新的对象 |
| classObj.getConstructor() | 获取指定public修饰构造方法Constructor对象 |
| classObj.getMethod() | 获取指定的public修饰方法Method对象 |
| classObj.getField() | 获取指定的public修饰成员变量Field对象 |
```java
public class ClassSimple {
public static void main(String[] args) {
try {
Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Employee employee = (Employee) employeeClass.newInstance();//通过默认的构造方法创建新的对象
System.out.println("employee = " + employee);
} catch (ClassNotFoundException e) {
//类名与类路径书写错误是抛出“类无法找到”异常
e.printStackTrace();
} catch (IllegalAccessException e) {
// 非法访问异常,当在作用域外访问对象方法或成员变量时抛出
e.printStackTrace();
} catch (InstantiationException e) {
// 实例化异常,当对象无法被实例化时抛出的异常,抽象类、接口等无法被实例化
e.printStackTrace();
}
}
}
Constructor构造方法类
- Constructor类是对Java中的构造方法的抽象。
- Constructor对象包含了具体的某个具体构造方法的声明。
- 通过Constructor对象调用带参构造方法创建对象
- Constructor类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getConstructor() | 获取指定public修饰的构造方法对象 | | constructorObj.newInstance() | 通过对应的构造方法创建对象 |
/**
* 利用带参构造方法创建对象
*/
public class ConstructorSimple {
public static void main(String[] args) {
try {
Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Constructor<?> employeeClassConstructor = employeeClass.getConstructor(new Class[]{
Integer.class, String.class, Float.class, String.class
});
Employee employee = (Employee) employeeClassConstructor.newInstance(1, "wkq", 12f, "某某部门");
System.out.println("employee = " + employee);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
//没有找到与之对应格式的方法
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
//实例化异常
e.printStackTrace();
} catch (InvocationTargetException e) {
// 目标调用异常,当被调用的方法内部跑出来异常而没有被捕获时
e.printStackTrace();
}
}
Method方法类
- Method对象指代某个类中的方法的描述
- Method对象使用classObj.getMethods()方法获取
- 通过Method对象调用指定对象的对应方法、
- Method类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getMethod() | 获取指定public修饰的方法对象 | | methodObj.invoke() | 调用指定对象的对应方法 |
public class MethodSimple {
public static void main(String[] args) {
try {
Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Constructor<?> constructor = employeeClass.getConstructor(new Class[]{
Integer.class, String.class, Float.class, String.class
});
Employee employee = (Employee) constructor.newInstance(12, "李磊", 12f, "研发部门");
Method updateSalaryMethod = employeeClass.getMethod("updateSalary", new Class[]{
Float.class
});
Employee newEmployee = (Employee) updateSalaryMethod.invoke(employee, new Object[]{1000f});
System.out.println("newEmployee = " + newEmployee);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Field成员变量类
- Field对应某个具体类中的成员变量的声明
- Field对象使用classObj.getField()方法获取
- 通过Field对象可为某对象成员变量赋值、取值
- 无论是下面的
getField()
还是后面的getMethod()
方法,这些get
方法开头的,默认都是获取public修饰的成员变量或者方法,如果尝试获取私有的成员方法或者成员变量,就会抛出NoSuchXXXException
- Field类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getField() | 获取指定public修饰的成员变量 | | fieldObj.set() | 为某对象指定成员变量赋值 | | fieldObj.get() | 获取某对象指定成员变量数值 |
public class FiledSimple {
public static void main(String[] args) {
try {
Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Constructor<?> employeeClassConstructor = employeeClass.getConstructor(new Class[]{
Integer.class, String.class, Float.class, String.class
});
Employee employee = (Employee) employeeClassConstructor.newInstance(new Object[]{
112, "李磊", 12f, "研发部"
});
Field employeeClassEnameField = employeeClass.getField("ename");
Object o = employeeClassEnameField.get(employee);
System.out.println("o = " + o);
employeeClassEnameField.set(employee,"王开琦");
System.out.println("employee = " + employee);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) { // 没有找到对应成员变量时抛出的异常
e.printStackTrace();
}
}
getDeclared系列方法
- getDeclaredConstructor(s)|Method(s)|Field(s)获取对应对象。带s的返回当前类中所有的。
- getConstructor(s)|Method(s)|Field(s)只能获取public对象,get是getDeclared的一个子集。
- 访问非作用域内构造方法、方法、成员变量,会抛出异常。
- 以下代码可以根据一个类对象解析这个对象,
```java
public class GetDeclaredSimpleSimple {
public static void main(String[] args) {
// declaredField.getModifiers() 获取访问修饰符,如果值为1,说明当前属性或方法是public修饰的try {
Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
Constructor<?> employeeClassConstructor = employeeClass.getConstructor(new Class[]{
Integer.class, String.class, Float.class, String.class
});
Employee employee = (Employee) employeeClassConstructor.newInstance(new Object[]{
12, "李磊", 12f, "研发部"
});
/* Field[] fields = employeeClass.getFields();
for (Field field : fields) {
System.out.println("field.getName() = " + field.getName());
}*/
/* Method[] declaredMethods = employeeClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("declaredMethod.getName() = " + declaredMethod.getName());
}*/
Field[] declaredFields = employeeClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("declaredField.getName() = " + declaredField.getName());
if (declaredField.getModifiers() == 1) {
Object val = declaredField.get(employee);
System.out.println("public \"+declaredField.getName()+\"= " + val);
} }} else if (declaredField.getModifiers() == 2) { //private修饰
// subString()代表字符串截取的意思 substring(0, 1)表示第一个字母 substring(1)表示第一个字母之后的字母
String methodName = "get" + declaredField.getName().substring(0, 1).toUpperCase() + declaredField.getName().substring(1);
Method method = employeeClass.getMethod(methodName);
Object val = method.invoke(employee);
System.out.println("private "+declaredField.getName()+" = " + val);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
<a name="ztq3O"></a>
## 反射在项目中的应用
反射提供了 `运行时` 对类的成员变量和方法提供了访问和调用的机制
```java
language=com.imooc.i18n.En // 配置文件内容
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) Class.forName(language).newInstance();
i18n.say();
System.out.println("i18n.say() = " + i18n.say());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Application.say();
}
}
总结
什么是反射
- 反射(Reflect)是在
运行时
动态访问类与对象的技术。 - 反射是JDK1.2版本后的高级特性,隶属于java.lang.reflect。
大多数Java框架都基于反射实现参数配置,动态注入、动态的创建类,创建对象等特性。
反射的核心类
Class
类Constructor
构造方法类Method
方法类-
Class类
Class是JVM中代表“类和接口” 的类
- Class对象具体包含了某个特定类的结构信息
- 通过Class对象可获取对应类的构造方法、方法、成员变量
- Class类核心方法 | 方法 | 用途 | | —- | —- | | Class.forName() | 静态方法,用于获取指定Class对象 | | classObj.newInstance() | 通过默认构造方法创建新的对象 | | classObj.getConstructor() | 获取指定public修饰构造方法Constructor对象 | | classObj.getMethod() | 获取指定的public修饰方法Method对象 | | classObj.getField() | 获取指定的public修饰成员变量Field对象 |
构造方法类
- Constructor类是对java类中构造方法的抽象
- Constructor对象包含了具体类的某个构造方法的声明
- 通过Constructor对象调用带参构造方法创建对象 | 方法 | 用途 | | —- | —- | | classObj.getMethod() | 获取指定public修饰的方法对象 | | methodObj.invoke() | 调用指定对象的对应方法 |
Method方法类
- Method对象指代某个类中的方法的描述
- Method对象使用
classObj.getMethod()
方法获取 - 通过对象调用指定对象的对应方法 | 方法 | 用途 | | —- | —- | | classObj.getMethod() | 获取指定public修饰的方法对象 | | methodObj.invoke() | 调用指定对象的对应方法 |
Field成员变量类
- Field对应某个具体类中的成员变量的声明
- Field对象使用classObj.getField()方法获取
- 通过Field对象可为某对象成员变量赋值、取值
- 无论是下面的
getField()
还是后面的getMethod()
方法,这些get
方法开头的,默认都是获取public修饰的成员变量或者方法,如果尝试获取私有的成员方法或者成员变量,就会抛出NoSuchXXXException
- Field类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getField() | 获取指定public修饰的成员变量 | | fieldObj.set() | 为某对象指定成员变量赋值 | | fieldObj.get() | 获取某对象指定成员变量数值 |