反射 将类的各个组成部分封装为其他对象,这就是反射机制
- 可以在程序运行过程中,操作这些对象
- 可以解耦,提高程序的可扩展性
反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,
- 对于任意一个类,都能够知道这个类的所以属性和方法;
- 对于任意一个对象,都能调用它的任意一个方法和属性
这种动态获取信息及动态调用对象方法的功能叫Java的反射机制
之前写到了设计模式的代理模式,因为下一篇动态代理等内容需要用到反射的知识,所以在之前Java篇的基础上再写一篇有关反射的内容,还是以实际的程序为主,了解反射是做什么的、应该怎么用。
框架设计的灵魂

反射机制的功能
Java反射机制主要提供了以下功能:
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
- 生成动态代理
实现反射机制的类
Java中主要由以下的类来实现Java反射机制(这些类都位于java.lang.reflect包中):
- Class类:代表一个类。 Field类:代表类的成员变量(成员变量也称为类的属性)。
- Method类:代表类的方法。
- Constructor类:代表类的构造方法。
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
setAccessible(true):暴力反射
设置后,可以把类中的所有私有属性获取出来
- Class对象
- Class对象中的功能
- Class对象功能中的方法
获取全类名
String getName()Person.class.getName()
获取Class对象的方式
⚠️ 注意: 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
Class.forName(“全类名”)
将字节码文件加载进内存,返回Class对象,多用于配置文件,将类名定义在配置文件中。读取文件,加载类
Class.forName("cn.itcast.domain.Person");
类名.class
通过类名的属性class获取,多用于参数的传递
对象.getClass()
getClass()方法在Object类中定义着,多用于对象的获取字节码的方式
// 获得对象的类Class classType=object.getClass();
Class对象功能
获取成员变量
| 方法 | 说明 |
|---|---|
| Field[] getFields() | 获取所有public修饰的成员变量 |
| Field getField(String name) | 获取指定名称的 public修饰的成员变量 |
| Field[] getDeclaredFields() | 获取所有的成员变量,不考虑修饰符 |
| Field getDeclaredField(String name) | 获取指定名称的成员变量,不考虑修饰符 |
| Field:成员变量 - [x] 设置值 void set(Object obj, Object value) - [x] 获取值 get(Object obj) 忽略访问权限修饰符的安全检查 setAccessible(true):暴力反射 |
Class<Person> personClass = Person.class;
//Field[] getFields()获取所有public修饰的成员变量
Field[] field = personClass.getFields();
Arrays.stream(field).forEach(System.out::println);
Person person = new Person();
personClass.getField("b").set(person, "张三");
System.out.println(person);
Object o = personClass.getField("b").get(person);
System.out.println(o);
//获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
Arrays.stream(declaredFields).forEach(System.out::println);
Field name = personClass.getDeclaredField("name");
name.setAccessible(true); //暴力反射 忽略访问权限修饰符的安全检查
Object o1 = name.get(person);
System.out.println(o1);
System.out.println(name);
获取构造方法
| 方法 | 说明 |
|---|---|
| Constructor<?>[] getConstructors() | |
| Constructor |
|
| Constructor |
|
| Constructor<?>[] getDeclaredConstructors() | |
| Constructor:构造方法 - 创建对象 T newInstance(Object… initargs) - 如果使用空参数构造方法创建对象,操作可以简化: - Class对象.newInstance方法 |
Class<Person> personClass = Person.class;
Constructor<?>[] constructors = personClass.getConstructors();
Arrays.stream(constructors).forEach(System.out::println);
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
Person name = constructor.newInstance("张三", 18); //创建对象,传值
Person nullname =personClass.getConstructor().newInstance();
Person nullname1 = personClass.newInstance();
System.out.println(name);
System.out.println(nullname);
获取成员方法
| 方法 | 说明 |
|---|---|
| Method[] getMethods() | |
| Method getMethod(String name, 类<?>… parameterTypes) | |
| Method[] getDeclaredMethods() | |
| Method getDeclaredMethod(String name, 类<?>… parameterTypes) | |
| Method:方法对象 - 执行方法: Object invoke(Object obj, Object… args) |
案例
需求:写一个”框架”,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
settings.properties
classname = domain.Teacher
methodName = speack

设计代理模式
Customer.java
public class Customer {
private Long id;
private String name;
private int age;
public Customer() {}
public Customer(String name,int age) {
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id=id;
}
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;
}
}
WriteFile.java
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
/**
* @ClassName: WriteFile
* @Description: 写文件操作
* @author 一缕清风
* @date 2021年12月01日
*
*/
public class WriteFile {
private static String pathname = "./out.txt";
public static void write(StringBuffer sBuffer) throws Exception {
File file = new File(pathname);
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
bw.write(sBuffer.toString());
bw.close();
}
}
ReflectTester.java
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTester {
public Object copy(Object object) throws Exception{
//获得对象的类型
Class classType=object.getClass();
System.out.println("Class:"+classType.getName());
//通过默认构造方法创建一个新的对象
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
//获得对象的所有属性
Field fields[]=classType.getDeclaredFields();
for(int i=0; i<fields.length;i++){
Field field=fields[i];
String fieldName=field.getName();
String firstLetter=fieldName.substring(0,1).toUpperCase();
//获得和属性对应的getXXX()方法的名字
String getMethodName="get"+firstLetter+fieldName.substring(1);
//获得和属性对应的setXXX()方法的名字
String setMethodName="set"+firstLetter+fieldName.substring(1);
//获得和属性对应的getXXX()方法
Method getMethod=classType.getMethod(getMethodName,new Class[]{});
//获得和属性对应的setXXX()方法
Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()});
//调用原对象的getXXX()方法
Object value=getMethod.invoke(object,new Object[]{});
System.out.println(fieldName+":"+value);
//调用拷贝对象的setXXX()方法
setMethod.invoke(objectCopy,new Object[]{value});
}
return objectCopy;
}
}
ReflexDemo.java
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @ClassName: ReflexDemo
* @Description: 通过反射获取类、属性及方法
* @author 一缕清风
* @date 2021年12月01日
*
*/
public class ReflexDemo {
private static StringBuffer sBuffer;
public static void getJar(String jar) throws Exception {
try {
File file = new File(jar);
URL url = file.toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[] { url },
Thread.currentThread().getContextClassLoader());
JarFile jarFile = new JarFile(jar);
Enumeration<JarEntry> enumeration = jarFile.entries();
JarEntry jarEntry;
sBuffer = new StringBuffer(); //存数据
while (enumeration.hasMoreElements()) {
jarEntry = enumeration.nextElement();
if (jarEntry.getName().indexOf("META-INF") < 0) {
String classFullName = jarEntry.getName();
if (classFullName.indexOf(".class") < 0) {
classFullName = classFullName.substring(0, classFullName.length() - 1);
} else {
// 去除后缀.class,获得类名
String className = classFullName.substring(0, classFullName.length() - 6).replace("/", ".");
Class<?> myClass = classLoader.loadClass(className);
sBuffer.append("类名\t:" + className);
System.out.println("类名\t:" + className);
// 获得属性名
Class<?> clazz = Class.forName(className);
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
sBuffer.append("属性名\t:" + field.getName() + "\n");
System.out.println("属性名\t:" + field.getName());
sBuffer.append("-属性类型\t:" + field.getType() + "\n");
System.out.println("-属性类型\t:" + field.getType());
}
// 获得方法名
Method[] methods = myClass.getMethods();
for (Method method : methods) {
if (method.toString().indexOf(className) > 0) {
sBuffer.append("方法名\t:" + method.toString().substring(method.toString().indexOf(className)) + "\n");
System.out.println("方法名\t:" + method.toString().substring(method.toString().indexOf(className)));
}
}
sBuffer.append("--------------------------------------------------------------------------------" + "\n");
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sBuffer.append("End");
WriteFile.write(sBuffer); //写文件
}
}
}
Main.java
/**Main.java
* @ClassName: Main
* @Description:
* @author 一缕清风
* @date 2021年12月01日
*
*/
public class Main {
private static String jar = "lib/dt.jar";
public static void main(String[] args) throws Exception {
ReflexDemo.getJar(jar);
}
}
