目录
一、基本概念
1.1 反射的含义
加载类,并允许以编程的方式获取类中的各种成分(方法、成员变量、构造器等等)
1.2 反射的过程
①
加载类,获得类的字节码(Class对象)
②
获取类的构造器(Constructor对象)
获取类的成员变量(Field对象)
获取类的成员方法(Method对象)
③
对得到的类的属性进行操作(成员变量赋值、new对象、执行私有方法)
二、获取成分
2.1 获取Class对象
①直接获取对象(建议优先使用)
Class myClass = 类名.Class
②调用Class提供方法
forName方法
③Object提供方法
getClass
2.2 获取构造器对象
关键方法:
--获取定义的构造器方法 getDeclaredConstructor
--利用获取的构造器方法new一个对象(可使用强制类型转换) yourGetConstructor.newInstance
package com.study;
import java.lang.reflect.Constructor;
import org.junit.Test;
public class myCatTest {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void test() throws Exception {
Class c = myCat.class;
// 获取无参构造器
Constructor constructor1 = c.getDeclaredConstructor();
constructor1.setAccessible(true);//强制不检查访问权限
myCat cat1 = (myCat) constructor1.newInstance();
System.out.println(cat1);
// 获取有参构造器
Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
constructor2.setAccessible(true);
myCat cat2 = (myCat) constructor2.newInstance("加菲猫", 2);
System.out.println(cat2);
}
}
2.3 获取成员变量
关键方法:
--获取定义的成员变量(所有权限均可) getDeclaredField,getDeclaredFields
--设置访问权限 yourGetField.setAccessible
--对获取的成员变量进行赋值 yourGetConstructor.set
// myCat类
package com.study;
public class myCat {
private String name;
private int age;
public myCat(){
System.out.println("这是一个无参数的构造器");
}
public myCat(String name,int age){
System.out.println("这是一个有参数的构造器");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "myCat [name=" + name + ", age=" + age + "]";
}
}
// myCat测试类,使用反射获取成员变量
package com.study;
import java.lang.reflect.Field;
import org.junit.Test;
public class myCatTest {
@SuppressWarnings({ "rawtypes" })
@Test
public void test() throws Exception {
Class c = myCat.class;
// 获取成员变量
Field[] myField = c.getDeclaredFields();
for (Field field : myField) {
System.out.println(field);
}
myCat newCat = new myCat("中华田园猫", 10);
// 获取单个成员变量并赋值
Field myField2 = c.getDeclaredField("name");
myField2.setAccessible(true);
myField2.set(newCat, "加菲猫");
}
}
2.4 获取成员方法
关键方法:
--获取定义的成员方法(所有权限均可) getDeclaredMethod
--设置访问权限 yourGetMethod.setAccessible
--运行获取的成员方法 yourGetMethod.invoke
// myCat类
package com.study;
public class myCat {
private String name;
private int age;
public myCat(){
System.out.println("这是一个无参数的构造器");
}
public myCat(String name,int age){
System.out.println("这是一个有参数的构造器");
this.name = name;
this.age = age;
}
// 两个私有同名方法
@SuppressWarnings("unused")
private void eat(){
System.out.println(this.name+"正在吃猫粮");
}
@SuppressWarnings("unused")
private String eat(String food){
return this.name+"正在吃"+food;
}
@Override
public String toString() {
return "myCat [name=" + name + ", age=" + age + "]";
}
}
// myCat测试类,获取成员方法
package com.study;
import java.lang.reflect.Method;
import org.junit.Test;
public class myCatTest {
@SuppressWarnings({ "rawtypes" })
@Test
public void test() throws Exception {
Class c = myCat.class;
// 获取成员方法并打印
Method[] myMethod = c.getDeclaredMethods();
for (Method method : myMethod) {
System.out.println(method);
}
// 获取成员方法并单独执行
myCat newCat = new myCat("中华田园猫", 10);
@SuppressWarnings("unchecked")
Method hasMethod = c.getDeclaredMethod("eat", String.class);
// 禁止检查访问权限
hasMethod.setAccessible(true);
// 直接执行
Object rs = hasMethod.invoke(newCat);
System.out.println((String) rs);
@SuppressWarnings("unchecked")
Method noMethod = c.getDeclaredMethod("eat");
hasMethod.setAccessible(true);
noMethod.invoke(newCat);
}
}
三、使用场景
获取类的所有成分并操作
破坏类的封装性,实现直接使用
配合制作Java框架
配合单元测试的使用(有时候需要达到固定的单元测试覆盖率,但某些私有方法无法在外部执行,可以使用反射直接执行私有方法)