Day42 Java反射(一)
前言
使用到一个类,JVM会将该类的class文件加载到方法区(类加载机制),同时会在堆内存中创建该类的class对象,class对象的作为class文件的访问入口。
在Java中,反射是指在运行时检查、获取和操作类、对象、方法等程序结构的能力。通过反射机制,可以在运行时动态获取类的信息、调用方法、访问字段等,而不需要在编译时确定这些信息。
基本概念
- Class类:在Java中,每个类都有一个对应的Class对象,可以通过类名.class或对象.getClass()方法获取。
- 获取Class对象:可以通过类的全限定名、对象的getClass()方法、Class类的静态方法forName()来获取Class对象。
- 反射API:Java提供了反射相关的API,如Class类、Constructor类、Method类、Field类等,用于操作类的结构。
理解:
反射实际上就是获取class对象,通过class对象访问class文件中的内容
访问内容: 属性,构造方法,普通方法(成员方法、静态方法、抽象方法…),方法上的参数,方法上的返回值,数组
应用场景
- 框架开发:许多框架(如Spring、Hibernate)利用反射实现依赖注入、ORM映射等功能。
- 工具类:编写通用工具类时,可以利用反射来实现动态调用、配置等功能。
- 测试框架:测试框架(如JUnit)利用反射来执行测试方法。
- 动态代理:通过反射可以实现动态代理,实现AOP等功能。
- 配置文件解析:可以通过反射读取配置文件中的类名、方法名等信息
利用反射获取class对象
Class对象的正确理解:每个类在内存中只有一份class文件
注意:
该类的class文件只在一次到方法区中,
该类的class对象在程序中是唯一的。
所以不管使用那种方式获取class对象都是同一个
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//获取class对象方式1
Class<? extends Student> clazz1 = Student.class;
//获取class对象方式2
Student stu = new Student();
Class<? extends Student> clazz2 = stu.getClass();
//获取class方式3
Class<?> clazz3 = Class.forName("com.qf.reflex01.Student");
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
}
}
public class Student extends Person{
private String classId;
private String id;
public static final String str = "用良心做教育";
public Student() {
}
private Student(String name, char sex, int age) {
super(name, sex, age);
}
public Student(String name, char sex, int age, String classId, String id) {
this(name, sex, age);
this.classId = classId;
this.id = id;
}
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "Student [classId=" + classId + ", id=" + id + ", toString()=" + super.toString() + "]";
}
}
利用反射操作属性
基本步骤:
- 获取Class对象:首先需要获取要操作的类的Class对象,可以通过类名.class或对象.getClass()方法获得。
- 获取字段对象:通过Class对象的getField()、getDeclaredField()等方法获取字段对象。
- 操作字段:通过Field对象的get()、set()方法可以获取和设置字段的值。
示例代码:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException;
import com.qf.utils.ReflexUtil;
public class Test03 {
/**
* 知识点:利用反射操作属性
*/
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
//通过反射工具类设置对象里的属性
Student stu = new Student();
ReflexUtil.setField(stu, "name", "小伟");
ReflexUtil.setField(stu, "sex", '男');
ReflexUtil.setField(stu, "age", 23);
ReflexUtil.setField(stu, "classId", "2401");
ReflexUtil.setField(stu, "id", "001");
System.out.println(stu);
}
}
public class Student extends Person{
private String classId;
private String id;
public static final String str = "用良心做教育";
public Student() {
}
private Student(String name, char sex, int age) {
super(name, sex, age);
}
public Student(String name, char sex, int age, String classId, String id) {
this(name, sex, age);
this.classId = classId;
this.id = id;
}
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "Student [classId=" + classId + ", id=" + id + ", toString()=" + super.toString() + "]";
}
}
public class ReflexUtil {
/**
* 获取当前类及其父类的属性对象
* @param clazz class对象
* @param name 属性名
* @return 属性对象
*/
public static Field getField(Class<?> clazz,String name){
for(Class<?> c = clazz;c != null;c = c.getSuperclass()){
try {
Field field = c.getDeclaredField(name);
return field;
} catch (NoSuchFieldException e) {
} catch (SecurityException e) {
}
}
return null;
}
/**
* 设置对象中的属性
* @param obj 对象
* @param name 属性名
* @param value 属性值
*/
public static void setField(Object obj,String name,Object value){
Field field = getField(obj.getClass(), name);
if(field != null){
field.setAccessible(true);
try {
field.set(obj, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 创建对象
* @param clazz class对象
* @param paremeterType 构造方法中的参数类型数组
* @param paremeters 构造方法中的参数数据
* @return 对象
*/
public static <T> T newInstance(Class<T> clazz,Class<?>[] parameterTypes,Object[] paremeters){
try {
Constructor<T> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
T obj = constructor.newInstance(paremeters);
return obj;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
利用反射操作构造方法
基本步骤:
- 获取Class对象:首先需要获取要操作的类的Class对象,可以通过类名.class或对象.getClass()方法获得。
- 获取构造方法对象:通过Class对象的getConstructor()、getDeclaredConstructor()等方法获取构造方法对象。
- 创建对象实例:通过构造方法对象的newInstance()方法创建类的对象实例。
示例代码:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import com.qf.utils.ReflexUtil;
public class Test04 {
/**
* 知识点:利用反射操作构造方法
*/
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//利用反射工具类去创建对象 -- 底层调用有参构造
Class<?>[] parameterTypes = {String.class,char.class,int.class,String.class,String.class};
Object[] paremeters = {"巴得伟",'男',23,"2401","001"};
Student stu = ReflexUtil.newInstance(Student.class, parameterTypes, paremeters);
System.out.println(stu);
}
}
public class Student extends Person{
private String classId;
private String id;
public static final String str = "用良心做教育";
public Student() {
}
private Student(String name, char sex, int age) {
super(name, sex, age);
}
public Student(String name, char sex, int age, String classId, String id) {
this(name, sex, age);
this.classId = classId;
this.id = id;
}
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "Student [classId=" + classId + ", id=" + id + ", toString()=" + super.toString() + "]";
}
}
public class ReflexUtil {
/**
* 获取当前类及其父类的属性对象
* @param clazz class对象
* @param name 属性名
* @return 属性对象
*/
public static Field getField(Class<?> clazz,String name){
for(Class<?> c = clazz;c != null;c = c.getSuperclass()){
try {
Field field = c.getDeclaredField(name);
return field;
} catch (NoSuchFieldException e) {
} catch (SecurityException e) {
}
}
return null;
}
/**
* 设置对象中的属性
* @param obj 对象
* @param name 属性名
* @param value 属性值
*/
public static void setField(Object obj,String name,Object value){
Field field = getField(obj.getClass(), name);
if(field != null){
field.setAccessible(true);
try {
field.set(obj, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 创建对象
* @param clazz class对象
* @param paremeterType 构造方法中的参数类型数组
* @param paremeters 构造方法中的参数数据
* @return 对象
*/
public static <T> T newInstance(Class<T> clazz,Class<?>[] parameterTypes,Object[] paremeters){
try {
Constructor<T> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
T obj = constructor.newInstance(paremeters);
return obj;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}