一、反射机制是什么
1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
2、Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
二、反射的作用
我先讲两个案例来说明反射的重要性
案例1、通过配置文件的全类名,调用该类方法
(1)、配置一个properties文件,也可以用xml来配置
class=com.zhao.reflectdemo.pojo.Cat
name=小白
(2)、写两个实体类
Cat类
@Data
public class Cat {
private String name;
private Integer age;
private Date brith;
private String character;
private String a;
private String b;
private String c;
private String d;
public void call(String name){
this.name = name;
System.out.println("猫儿:" + this.name + "在叫");
}
}
Dog类
@Data
public class Dog {
private String name;
private Integer age;
private Date brith;
private String character;
private String a;
private String b;
private String c;
private String d;
public void call(String name){
this.name = name;
System.out.println("狗儿:" + this.name + "在叫");
}
}
(3)、测试:
@Test
public void test() throws Exception{
Properties properties = new Properties();
properties.load(new InputStreamReader(
Files.newInputStream(Paths.get("src\\main\\resources\\application.properties")),
StandardCharsets.UTF_8));
String className = properties.getProperty("class");
String name = properties.getProperty("name");
properties.clone();
Cat cat = new com.zhao.reflectdemo.pojo.Cat();
cat.call(name);
common(className,name);
className = "com.zhao.reflectdemo.pojo.Dog";
common(className,name);
}
private void common(String className,String name) throws Exception{
Class<?> animalClass = Class.forName(className);
Object o = animalClass.newInstance();
Method call = animalClass.getMethod("call",String.class);
call.invoke(o,name);
}
(4)、结果:

案例2、通过反射更改现有对象的属性
(1)、使用Cat类,去掉@Data注解和任何方法
public class Cat {
private String name;
private Integer age;
private Date brith;
private String character;
private String a;
private String b;
private String c;
private String d;
}
(2)、测试类:
public void Test2() throws Exception {
Cat cat = new Cat();
common2(cat);
System.out.println(cat);
}
private <T> void common2(T t) throws Exception{
Class<?> tClass = t.getClass();
Field[] fields = tClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.getType() == String.class) {
String name = field.getName();
Object o = field.get(t);
if (Objects.isNull(o)){
if (name.equals("name")) {
field.set(t,"大白");
}else {
field.set(t,"");
}
}
}
}
}
(3)、结果:debug看一下,的确可以实现改熟悉的值

三、反射原理
1、编译
图解

Java文件与Class文件对比

2、类加载
图解

DeBug看一下

查看Class对象是否是唯一的

3、运行

四、使用反射
反射机制相关的重要的类
类 | 含义 |
---|
java.lang.Class | 代表整个字节码。代表一个类型,代表整个类。 |
java.lang.reflect.Method | 代表字节码中的方法字节码。代表类中的方法。 |
java.lang.reflect.Constructor | 代表字节码中的构造方法字节码。代表类中的构造方法。 |
java.lang.reflect.Field | 代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。 |
一、获取class对象的三种方法
方法 |
---|
Class.forName(“全类名”) |
对象.getClass() |
类.class |
Cat cat = new Cat();
Class<? extends Cat> class1 = cat.getClass();
Class<Cat> class2 = Cat.class;
Class<?> class3 = Class.forName("com.zhao.reflectdemo.pojo.Cat");
System.out.println(class1 == class2);
System.out.println(class1 == class3);
System.out.println(class2 == class3);
二、Class类
Class类常用的方法
方法名 | 备注 |
---|
public T newInstance() | 创建对象 |
public String getName() | 返回完整类名带包名 |
public String getSimpleName() | 返回类名 |
public Field[] getFields() | 返回类中public修饰的属性 |
public Field[] getDeclaredFields() | 返回类中所有的属性 |
public Field getDeclaredField(String name) | 根据属性名name获取指定的属性 |
public native int getModifiers() | 获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】 |
ublic Method[] getDeclaredMethods() | 返回类中所有的实例方法 |
public Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 根据方法名name和方法形参获取指定方法 |
public Constructor<?>[] getDeclaredConstructors() | 返回类中所有的构造方法 |
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 根据方法形参获取指定的构造方法 |
public native Class<? super T> getSuperclass() | 返回调用类的父类 |
public Class<?>[] getInterfaces() | 返回调用类实现的接口集合 |
三、反射获取方法(Method)
Method类
方法名 | 备注 |
---|
public String getName() | 返回方法名 |
public int getModifiers() | 获取方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】 |
public Class<?> getReturnType() | 以Class类型,返回方法类型【一般配合Class类的getSimpleName()方法使用】 |
public Class<?>[] getParameterTypes() | 返回方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】 |
public Object invoke(Object obj, Object… args) | 调用方法 |
案例:
1、有个Cat类:
public class Cat {
public void call(String name){
System.out.println("cat的有参方法,参数:" + name);
}
public String call(){
System.out.println("cat的无参方法");
return "无参方法";
}
private String privatization(){
System.out.println("cat的私有方法");
return "私有方法";
}
}
2、测试案例:
@Test
public void Test2() throws Exception {
Class<Cat> catClass = Cat.class;
Cat cat = catClass.newInstance();
System.out.println("============获取单个非私有方法==================");
Method method = catClass.getMethod("call");
Object o = method.invoke(cat);
System.out.println("method的返回值是" + o);
Method method2 = catClass.getMethod("call",String.class);
method2.invoke(cat, "随便");
Method[] declaredMethods = catClass.getDeclaredMethods();
System.out.println("============获取单个方法==================");
Method declaredMethod = catClass.getDeclaredMethod("privatization");
declaredMethod.setAccessible(true);
declaredMethod.invoke(cat);
}
3、结果

四、反射获取字段(Field)
Field类
方法名 | 备注 |
---|
public String getName() | 返回属性名 |
public int getModifiers() | 获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】 |
public Class<?> getType() | 以Class类型,返回属性类型【一般配合Class类的getSimpleName()方法使用】 |
public void set(Object obj, Object value) | 设置属性值 |
public Object get(Object obj) | 读取属性值 |
案例:
1、有个Cat类:
@Data
public class Cat {
private String name;
private Integer age;
private Date brith;
private String character;
private String a;
private String b;
private String c;
private String d;
}
2、测试案例:
@Test
public void Test3() throws Exception{
Cat cat = new Cat();
cat.setA("随便,随便拉");
Class<?> tClass = cat.getClass();
Field[] fields = tClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.getType() == String.class) {
String name = field.getName();
Object o = field.get(cat);
if (Objects.isNull(o)){
if (name.equals("name")) {
field.set(cat,"大白");
}else {
field.set(cat,"");
}
}
}
}
System.out.println(cat);
}
3、Debug

五、反射获取构造函数(Constructor)
Constructor类
方法名 | 备注 |
---|
public String getName() | 返回构造方法名 |
public int getModifiers() | 获取构造方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】 |
public Class<?>[] getParameterTypes() | 返回构造方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】 |
public T newInstance(Object … initargs) | 创建对象【参数为创建对象的数据】 |
案例:
1、有个Cat类:
public class Cat {
public String name;
private Cat(){
}
public Cat(String name){ this.name = name;}
}
2、测试案例:
@Test
public void Test4() throws Exception{
Class<Cat> catClass = Cat.class;
Constructor<Cat> constructor = catClass.getConstructor(String.class);
Cat cat1 = constructor.newInstance("名字是个啥");
System.out.println(cat1.name);
Constructor<Cat> declaredConstructor = catClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Cat cat2 = declaredConstructor.newInstance();
System.out.println(cat2.name);
}
3、结果
