反射
概念
Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。
反射需要使用的API
获取字节码对象
Class.forName(“类的全路径”);
类名.class
对象.getClass();
常用方法
package cn.tedu.reflection;
import org.junit.Test;
/**
* 测试反射技术
*/
public class TestReflect {
/*
单元测试:是java运行测试的最小单位,使用灵活
语法:@Test,返回值类型为空,无参数,必须被public所修饰
使用时需要导入Maven仓库中的包
import org.junit.Test;
*/
@Test
public void getClazz() throws ClassNotFoundException {
/*
参数为目标类的全路径名:包名+类名
获取本类的字节码对象
*/
Class<?> student1 = Class.forName("cn.tedu.reflection.Student");
Class<?> student2 = Student.class;
Class<?> student3 = new Student().getClass();
System.out.println(student1);//直接打印获取到的字节码兑象
System.out.println(student2.getName());//打印类的全路径名
System.out.println(student3.getName());//打印类的全路径名
System.out.println(student3.getSimpleName());//打印类的类名
System.out.println(student3.getPackage());//获取包对象
System.out.println(student3.getPackage().getName());//获取包名
}
}
- 获取构造方法
getConstructor(参数类型列表)
————获取公开的构造方法
getConstructors()
———获取所有的公开的构造方法
暴力反射getDeclaredConstructors()
——-获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
示例代码
//使用单元测试方法获取构造方法
@Test
public void getConstruct(){
Class<?> clazz = Student.class;
//获取所有公开构造方法,并存入数组
Constructor<?>[] cs = clazz.getConstructors();
//System.out.println(Arrays.toString(cs));
for (Constructor<?> i : cs){
System.out.println(i.getName());//获取当前构造函数的名称
Class<?>[] p = i.getParameterTypes();//获取当前构造方法的参数类型
System.out.println(Arrays.toString(p));
}
}
getMethods()
——获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
暴力反射:
getDeclaredMethods()
——-获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
示例代码
//通过单元测试获取普通方法
@Test
public void getFunction() throws ClassNotFoundException {
Class<?> clazz = Class.forName("cn.tedu.review.Student");
//获取所有公共普通方法
Method[] ms = clazz.getMethods();
//System.out.println(Arrays.toString(ms));
for (Method i : ms){
System.out.println(i.getName());//获取当前遍历到的方法名
Class<?>[] pt = i.getParameterTypes();//获取方法名的参数类型
System.out.println(Arrays.toString(pt));//查看当前遍历到的方法参数类型
}
- 获取成员变量
getFields()
——-获取所有公开的成员变量,包括继承变量
getDeclaredFields()
——-获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
示例代码
/*
通过单元测试获取成员变量
成员变量的修饰符必须为public才能被获取到
默认修饰符无法获取
*/
@Test
public void getFields(){
Class<Student> clazz = Student.class;
Field[] fs = clazz.getFields();
for (Field i : fs){
System.out.println(i.getName());//获取遍历到的属性名
System.out.println(i.getType().getName());//获取遍历到的属性名的类型名
}
}
反射创建新实例
clazz.newInstance();
——执行无参构造创建对象
clazz.newInstance(666,”海绵宝宝”);
——执行含参构造创建对象
clazz.getConstructor(int.class,String.class)
——获取构造方法反射调用成员变量
clazz.getDeclaredField(变量名);
//获取变量
clazz.setAccessible(true);
//使私有成员允许访问
f.set(实例,值);
//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);
//访问指定实例变量的值,静态变量,第一参数给null反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);/
/使私有方法允许被调用
m.invoke(实例,参数数据);
//让指定实例来执行该方法
暴力反射
指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。
示例代码
暴力反射所需要的物料类
package cn.tedu.review;
/**
* 用于测试暴力反射
*/
public class Person {
private String name;
private int age;
private void find(String s,int n){
System.out.println(s + ":太热了,怎么破," + n + n + n + n);
}
private void update(){
System.out.println("不需 要升级");
}
}
使用暴力反射
package cn.tedu.review;
import com.sun.jmx.snmp.SnmpUnknownAccContrModelException;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试暴力反射
*/
public class TestReflect2 {
@Test
public void getFields() throws NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<?> clazz = Person.class;
//获取私有属性name属性的字节码对象
Field filed = clazz.getDeclaredField("name");
//使用获取到的私有属性对象获取对应信息
System.out.println(filed.getName());
System.out.println(filed.getType().getName());
/*
给指定属性设置值
暴力反射需要设置私有资源可见的权限
set(m,n)----m指要设置值的对象名,n指要设置的具体值
需要先使用字节码对象创建需要的目标对象
*/
filed.setAccessible(true);
Object obj = clazz.newInstance();
//使用属性对象设置obj的name值
filed.set(obj,"马钊");
System.out.println(filed.get(obj));
}
@Test
public void getFunction() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<Person> clazz = Person.class;
/*
使用暴力反射获取私有方法
getDeclaredMethod(m,x,y,z····)
m指需要获取的方法名
x,y,z···指方法参数,传入的为字节码对象。
*/
Method method = clazz.getDeclaredMethod("find", String.class,int.class);
method.setAccessible(true);
//需要确定对象来执行获取到的find()
Object obj = clazz.newInstance();
//使用invoke给对象obj执行方法
method.invoke(obj,"马钊",5);
}
}