一、什么是反射
JAVA反射机制:
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
(1)Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
(2)加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
二、常用API
Class类:反射的核心类,反射所有的操作都是围绕该类来生成的,通过它,可以获取类的属性,方法等内容
Field类:表示类的属性,可以获取和设置类中属性的值
Method类:表示类的方法,它可以用来获取类中方法的信息,或者执行方法
Constructor类:表示类的构造方法
//获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"吴彦祖");//执行有参构造创建对象
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(实例,参数数据);//让指定实例来执行该方法
三、反射的应用
遍历某个类的所有的构造方法,属性,方法
案例:
StudentEntity类
public class StudentEntity {
private String name;
private Integer age;
private String hobby;
public StudentEntity(String name, Integer age) {
System.out.println("有参构造方法1");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public StudentEntity(String name, Integer age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
System.out.println("有参构造方法2");
}
public StudentEntity(){
System.out.println("无参构造方法");
}
public void study(){
System.out.println("正在学习。。。。。。");
}
public void sleep(){
System.out.println("正在睡觉。。。。。");
}
public int count(){
System.out.println("正在计算");
return 0;
}
public void showInfo(){
System.out.println("姓名:"+this.name +
" 年龄:"+this.age+
" 爱好:"+this.hobby);
}
}
测试类:
public class Test {
//遍历构造方法
public void m1(Class clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//通过类名直接获取
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor con : constructors) {
System.out.println(con);
}
System.out.println("---------------------------------");
}
//遍历属性
public void m2(Class clazz){
Field[] fields = clazz.getDeclaredFields();
for (Field fie : fields) {
System.out.println(fie.getName());
}
System.out.println("---------------------------------");
}
//遍历方法
public void m3(Class clazz){
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
Test01 test = new Test01();
test.m1(StudentEntity.class);
test.m2(StudentEntity.class);
test.m3(StudentEntity.class);
}
}
输出:
思路:
通过类的对象获取构造方法、定义的属性、定义的方法的集合,再通过集合去遍历
注意:对于私有属性遍历,首先要获取访问授权,使用以下语句
field.setAccessible(true);
通过文件名进行反射
案例:
写一个类ReflectUtil类, 类中写一个静态方法Object methodInvoker(String classMethd) 此classMethod为无参方法名如,
我们传入的实参字符串为:classMethod 为"java.lang.String.length()"就可以通过反射执行String类中的length方法、当传入的实参字符串为"com.atguigu.javase.reflect.Teacher.test()"就可以执行指定包下,指定类中的指定方法
public class ReflectUtil {
public static Object methodInvoker(String classMethd) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
int lastIndexOf = classMethd.lastIndexOf(".");
String calssName = classMethd.substring(0,lastIndexOf);//获取类名
//找到该类
Class clazz = Class.forName(calssName);
int index = classMethd.indexOf("(");
//获取方法名
String methodName = classMethd.substring(lastIndexOf+1,index);
//实例化对象
Object o = clazz.getDeclaredConstructor().newInstance();
//找到该方法
Method method = clazz.getMethod(methodName);
//调用该方法
return method.invoke(o);
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
methodInvoker("com.test.entity.StudentEntity.study()");
//methodInvoker("java.lang.String.length()");
}
}
输出
思路:
通过最后一个" . " 获取类名,再通过类名找到该类,
通过" ( " 找到方法名,再通过方法名找到该方法
最后实例化该类对象(通过调用改类的构造函数实例化),并调用该方法
总结:
反射决定了一个程序员的上限,也就是说,反射学的好,程序员的格局也跟着大,反射是一种逆向的思维,当正面碰到编译问题过不去时,不妨试一试反射,在运行时去解决。api就这么多,需要灵活的去用。