说明:本文是针对大量的对于反射讲解不够细致,且比较晦涩难懂,故总结做了此篇文档.本文最大特点是加入了对反射知识原理的讲解.本文学习时间为20分钟左右.
Java必学基础知识之反射原理和运用
在框架和组件中常使用,可以写出复用性高的通用程序,解耦使用.
原理理解
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性.这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.
总结一句话,就是能把java类中的各种成分映射成一个个的Java对象.
思路:想要操作类,就必须先获得该类的字节码对象Class.通过Class提供的方法对类进行进一步的解剖,从而实现各种操作.
解剖:就是调用Class类中的方法.
专业描述词汇
- Class:类
- Constructor:构造方法
- Method:方法
- Field:字段/属性
- instance:实例/对象
- invoke:执行
类加载过程与反射的使用
查看Class类在Java中的api详解总结
- Class类的实例表示正在运行的Java应用程序中的类和接口
- Class没有公共构造方法.Class对象是在加载类时,有java虚拟机以及通过调用类加载器中的defineClass方法自动构造的.也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了.
反射知识应用
创建一个Student类
package study.reflection.domain;
public class Student {
// 属性
private String name;
private int age;
public String description;
// 构造方法
public Student(){
System.out.println("调用Student无参数的构造方法... ...");
}
private Student(String name) {
System.out.println("调用name单参数:"+name);
this.name = name;
}
public Student(String name, int age) {
System.out.println("调用 String name, int age 两个参数的构造方法... ...");
this.name = name;
this.age = age;
}
protected Student(boolean n) {
System.out.println("受保护的方法:"+n);
}
private Student(String name, int age, String description){
System.out.println("调用私有的 三个参数的构造方法 ... ...");
this.name = name;
this.age = age;
this.description = description;
}
// get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
// 自定义方法
private int show(int num){
System.out.println("调用私有的show方法... ... num=" + num);
return num;
}
// toString方法
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", description=" + description + "]";
}
}
获取Class对象的三种方法
任何数据类型(包括基本数据类型)都有一个“静态”的class属性
一般在方法内部使用
通过Class类的静态方法:forName(String className)(常用)
从外部的配置文件中获取Class对象
package study.reflection.main;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import org.junit.Test;
import cn.itcast.reflection.domain.Student;
public class Reflection01 {
@Test
public void constructor() throws Exception {
//加载类的对象
Class clazz = Class.forName("cn.itcast.reflection.domain.Student");
System.out.println("======================公有构造方法================");
//获取所有共有构造方法
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("====================所有构造方法==================");
//获取所有构造方法(公有,私有,受保护的)
Constructor[] constructors2 = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors2) {
System.out.println(constructor);
}
/* System.out.println("===========获取Student类的单参构造函数=======");
Constructor constructor2 = clazz.getConstructor(String,int.class);
System.out.println(constructor2);*/
}
@Test
public void privateCons() throws Exception {
Class clazz = Class.forName("cn.itcast.reflection.domain.Student");
System.out.println("=====================获取Student类的单参构造方法,创建对象====");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
System.out.println(constructor);
//调用构造方法
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance("张");
System.out.println(student);
}
/**
* 空参构造直接调用
* @throws Exception
*/
@Test
public void nullConstructor() throws Exception {
Class clazz = Class.forName("cn.itcast.reflection.domain.Student");
Constructor constructor = clazz.getConstructor();
}
}
注意:在运行期间,一个类只产生一个Class对象
通过反射调用类中的方法
获取普通方法
@Test
public void getMethod() throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("cn.itcast.reflection.domain.Student");
Student student = (Student) clazz.newInstance();
// 获取普通的方法
Method setNameMethod = clazz.getMethod("setName",String.class);
setNameMethod.invoke(student,"小明同学");
System.out.println(student);
Method getNameMethod = clazz.getMethod("getName");
Object returnVal = getNameMethod.invoke(student);
System.out.println(returnVal);
}
获取私有方法
@Test
public void getMethod2() throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("cn.itcast.reflection.domain.Student");
Student student = (Student) clazz.newInstance();
// 获取私有的方法
Method showMethod = clazz.getDeclaredMethod("show",int.class);
showMethod.setAccessible(true);
Object returnVal = showMethod.invoke(student, 1500);
System.out.println(returnVal);
}
通过反射调用属性
@Test
public void getMethod3() throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("cn.itcast.reflection.domain.Student");
Student student = (Student) clazz.newInstance();
// 获取普通属性
Field descriptionField = clazz.getField("description");
descriptionField.set(student, "描述:初学者");
//获取私有属性
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(student, "石猴");
System.out.println(student);
}