反射的概念
简而言之,反射是可以通过每个.java文件生成的.class文件来对立进行一些数据访问和修改.
比如访问其私有化方法或私有化成员变量.
同时,能够无视方法的形参类型限制,比如可以通过更改ArrayList的’class’文件,能够在其泛型为’Integer’的情况下,通过’add’方法添加String字符串元素.
反射在日后JAVA开发中会经常用到,因此必须熟练掌握!
反射成员方法和成员变量是在反射构造方法的基础上实现的,而反射构造方法则是在’反射Class字节码类文件’的基础上实现的,这个关系一定要明白.
一.反射Class字节码类文件
反射Class字节码类文件是反射中最基本的要求,不先去类文件,就无法去反射构造方法,成员方法,成员变量.
反射类文件有三种格式,以下一一举例.
方式1
通过类的Class属性来获取其class对象
格式:Class<欲获取其class文件的类> 自定义Class类对象名 = 欲获取其class文件的类.class;
列如:
Class<Student> st = Student.class;
方式2
通过调用对象的’getClass’方法,来获得该对象其对应类的Class. 如此处通过’tudentObj’对象的’getClass’方法,来获取其对象类’Student’的Class文件.
格式:Class<? extends 欲获取其class文件的类> 自定义Class类对象名 = 自定义普通对象名.getClass();
列如:
Student studentObj = new Student();
Class<? extends Student> s =studentObj.getClass(); //设置泛型上线,即,泛型类只能为此处的'Student'及其子类.
方式3(推荐)
使用’Class’类中的静态方法’forName’,在括号参数内输入 包路径+类名 的格式来获取其Class. 此处需要处理异常.
格式:Class<?> 自定义Class类对象名 = Class.forName(其欲获取class文件类的包路径+其欲获取class文件类的类名);
Class<?> staticMethod = Class.forName("code.study.fanshetest.Student");
二.反射构造方法
之前在反射Class字节码类文件时讲过,反射构造方法,成员变量,成员方法都基于’反射Class字节码文件’之上.那么就需要先反射Class字节码文件,此处就不再叙述,仅叙述反射构造方法所需要的步骤.
1.创建反射构造方法的格式
格式1: 以数组形式,获取该自定义Class类对象所有公共构造方法
Constructor<?>[] 自定义公开构造数组对象名 = 自定义Class类对象名.getConstructors() ;
列如:
Constructor<?>[] getAllGouZao = staticMethod.getConstructors();
格式2: 以数组形式,获得该自定义Class类对象所有任何权限的构造方法
Constructor<?>[] 自定义任何权限构造数组对象名= 自定义Class类对象名.getDeclaredConstructors() ;
列如:
Constructor<?>[] getAllDeclaredGouzao = staticMethod.getDeclaredConstructors();
格式3: 获得该自定义Class类对象中某个公共构造方法
Constructor<?> 自定义单个公开构造对象名 = 自定义Class类对象名.getConstructor(参数类型.class) ;
列如:
Constructor<?> getOneGouZao = staticMethod.getConstructor(int.class);
格式4: 获得该自定义Class类对象中某个任何权限的构造方法
Constructor<?> 自定义单个任何权限构造对象名 = 自定义Class类对象名.getDeclaredConstructor(参数类型.class);
列如:
Constructor<?> siYouGouZaoMethod = staticMethod.getDeclaredConstructor(Integer.class);
2.解除私有化构造方法的访问限制
格式:
自定义'单个/所有'任何权限构造对象名.setAccessible(true);
列如:
siYouGouZaoMethod.setAccessible(true);
用’getDeclaredConstructor()
'或’getDclaredConstructors()'
获取构造方法的话,
那在获取之后就需要用上述格式的代码来解除这个私有化构造方法的权限,
之后才能够用自[定义’单个/所有’任何权限构造对象名.newInstance]的格式来创建实例.
3.实例化构造方法的对象
获取到构造方法后还不能使用,如果要使用其构造方法,那么就需要将构造方法实例化.
实例化对象时,有着类似于’new’对象时给小括号’()'内传递有参/无参构造一般的逻辑.
格式:
Object 自定义实例对象名 = 自定义'单个/数组''任何权限/公开权限'构造'对象名/数组对象名'.newInstance(无构造参数/有构造参数);
列如:
Object siYouGZ = siYouGouZaoMethod.newInstance(12);
System.out.println(siYouGZ);//调用该构造方法
三.反射成员变量
前面提到过,反射构造成员变量是基于反射构造方法的前提上实现的,而构造方法的实现则基于反射Class字节码文件的前提上,所以需要完成上述二个步骤.
注意: 不仅仅可以对反射出来的成员变量赋值,也可以获取其成员变量的值(前提是在此前已经通过其它方式为该成员变量传递过值).格式是: 此前的任意权限成员变量之对象名.get(普通对象名/构造方法的反射实例对象);
如:
//以普通形式创建对象
Student obj = new Student(1007);
// 获取字节码对象
Class c = obj.getClass();
// 获取属性对象
Field f = c.getDeclaredField(propertyName);
// 取消访问检查
f.setAccessible(true);
// 获取属性值
Object fValue = f.get(obj);
//以实例化反射构造方法的对象来演示.
Class<?> s = Class.forName("code.study.school0107getinfo.Student");
Constructor<?> sobj = s.getConstructor(Object.class);
Object sobjOfobj = sobj.newInstance("我爱中国");
Field fieodObj = s.getDeclaredField("objOfObject");
fieodObj.setAccessible(true);
Object result2 = fieodObj.get(sobjOfobj);
1.创建反射成员变量的格式
格式1: 以数组形式,获取该自定义Class类对象所有公共权限的变量.
Field[] 自定义公开权限的成员变量之数组对象名 = 自定义Class类对象名.getFields();
格式2: 以数组形式,获得该自定义Class类对象所有任意权限的成员变量
Field[] 自定义任意权限的成员变量之数组对象名 = 自定义Class类对象名.getFieldsgetDeclaredFields();
格式3: 获得该自定义Class类对象中某个公共权限的成员变量
Field 自定义公开权限的成员变量之对象名 = 自定义Class类对象名.getFieldsgetField(公共权限成员变量名);
格式4: 获得该自定义Class类对象中某个任意权限的成员变量
Field 自定义任意权限的成员变量之对象名 = 自定义Class类对象名.getFieldsgetDeclaredField(任意权限成员变量名);
列如:
Field getPrivateV = staticMethod.getDeclaredField("age");
2.解除私有化成员变量的访问检查
同样的,不仅仅是私有化的构造方法,私有化的成员变量也是需要解除访问限制的,不然就无法实例化.
格式:
自定义任意权限的成员变量对象名.setAccessible(true);
列如:
getPrivateV.setAccessible(true);
3.为成员变量赋值,并实例化
与构造方法的实例化一样,在实例化成员变量时,也是要赋值的.
括号内左侧的参数为构造方法的实例对象,右侧则是欲为成员变量所赋的值.
格式:
此前的任意权限成员变量之对象名.set(自定义构造方法实例对象名,数值);
列如:
getPrivateV.set(objObj,13434);
System.out.println(objObj);//调用
四.反射成员方法
同样的,成员方法的实现前提也是基于构造方法和其反射Class字节码文件的实现上.
1.创建反射成员方法的格式
格式1: 以数组形式,获取所有公开权限的成员方法,{{并且包含继承自父类和实现自接口的方法!!!}}
Method[] 自定义所有公开权限的成员方法之对象名 = 自定义Class类对象名.getMethods();
格式2:以数组形式,获取所有任意权限的成员方法,与之相反,仅仅是本类中的方法,不包括继承自类或实现自接口的.
Method[] 自定义所有任意权限的成员方法之对象名 = 自定义Class类对象名.getDeclaredMethods();
格式3: 获取单个公开权限的成员方法
Method 自定义单个公开权限的成员方法之对象名 = 自定义Class类对象名.getMethod(方法名,方法形参类型.class);
列如:
Method getOneMethod = studentClass.getDeclaredMethod("methodOfPublic",String.class);
格式4:获取单个任意权限的成员方法.
Method 自定义单个任意权限的成员方法之对象名 = 自定义Class类对象名.getDeclaredMethod(方法名,方法形参类型.class);
列如:
Method getOneDeclaredMethod = studentClass.getDeclaredMethod("methodOfPrivate", String.class);
2.解除私有化构成员方法的访问检查
反射成员方法也是如此,需要解除私有化成员方法的访问检查,才可以实例化成员方法的对象.
格式:
格式:自定义'单个/所有'任何任意成员方法对象名.setAccessible(true);
列如:
getOneDeclaredMethod.setAccessible(true);
3.为成员方法的形参赋值,并实例化
将其定义为’成员方法的实例对象’,为其传递参数,并接收.
格式:
Object 自定义成员方法实例对象名 = 此前的任意权限成员方法之对象名.invoke(此前的构造方法实例化对象,给其成员方法传递的参数);
列如:
Object stringParamPrivate = getOneDeclaredMethod.invoke(construcatorObj,"世界大同");
System.out.println(stringParamPrivate);//调用
反射成员变量演示类
请编写一个方法setProperty,该方法可以接收三个参数,
第一个为Object类型的obj对象,
第二个为String类型的propertyName,
第三个为Object类型的value,
方法的作用是能够为obj对象中名为propertyName的属性的值设置为value。
在主方法中调用方法进行测试。
简而言之:通过obj对象联系到propertynName所表示的变量,在给这个变量赋予’value’的值.
public class SetOfMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
Student studentObj = new Student("世界因你而改变~!");
setProperty(studentObj, "objOfObject",1232);
}
public static void setProperty(Object obj,String propertyName,Object value) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
//反射class字节码
Class reflection = obj.getClass();
//反射成员变量
Field fieldObj = reflection.getDeclaredField(propertyName);
//解除私有化成员变量的访问限制
fieldObj.setAccessible(true);
//先获取变量未被赋值时的值 此时为此前String类型的'世界因你而改变~!'
Object result = fieldObj.get(obj);
System.out.println(result);
//为其赋值
fieldObj.set(obj,value );
//再获取更改后的值,此时已经为'int'型的 1232
result = fieldObj.get(obj);
System.out.println(result);
Class<?> s = Class.forName("code.study.school0107getinfo.Student");
Constructor<?> sobj = s.getConstructor(Object.class);
Object sobjOfobj = sobj.newInstance("我爱中国");
Field fieodObj = s.getDeclaredField("objOfObject");
fieodObj.setAccessible(true);
Object result2 = fieodObj.get(sobjOfobj);
}
}
配合Properties反射成员方法
在当前模块目录下有properties格式的配置文件(直接准备好即可),内容如下:
className=com.itheima.Teacher
methodName=teach
同时,在com.itheima包下定义标准的JavaBean,名为Teacher,提供teach方法(无参无返回值,自定义即可)。
请读取该配置文件,使用反射技术,加载这个类,并运行配置的方法。
public class PropertiesLoad {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
BufferedReader br = new BufferedReader(new FileReader("D:\\IdeaProjects\\senior-code\\day15-Senior-FanShe\\src\\school0107Properties.txt"));
Properties prop = new Properties();
prop.load(br);
// System.out.println(prop.get("className"));
// System.out.println(prop.getProperty("className"));
//反射Class文件
Class<?> classLoad = Class.forName(prop.getProperty("className"));//com.itheima.Teacher
//反射构造方法
Constructor<?> constructionObj = classLoad.getConstructor();
//构造方法实例化
Object constructionInstance = constructionObj.newInstance();
//反射成员方法
Method methodObj = classLoad.getMethod(prop.getProperty("methodName"));//teacher
//成员方法实例化
Object methodInvoke = methodObj.invoke(constructionInstance);
}
}
反射成员方法到对象
有如下学生实体类:
package com.itheima;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 自行补充getters and setters
// 显示信息的方法
public void showInfo() {
System.out.println(name + " - " + age);
}
}
请使用反射技术,创建该类的对象,并为对象的属性赋值,然后反射调用显示信息的方法。
ReflectionClass.java
public class ReflectionClass {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//反射Class字节码
Class<?> reflectionObj = Class.forName("code.study.school0107studentofreflection.Student");
//反射构造方法
Constructor<?> constructorObj = reflectionObj.getConstructor(String.class,int.class);
//实例化构造方法
Object shiliConstructor = constructorObj.newInstance("你好!世界!",20200107);
//反射成员方法
Method refletionMethod = reflectionObj.getMethod("showInfo");
//将其实例化并调用.
Object loadObj = refletionMethod.invoke(shiliConstructor);
}
}
Student.java
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 显示信息的方法
public void showInfo() {
System.out.println(name + " - " + age);
}
}
反射成员变量到对象
现获取到一个Map集合,集合中以属性名称对应属性值的方式存放了一个学生对象的信息,如下:
HashMap<String, Object> map = new HashMap<>();
map.put(“id”, “heima001”);
map.put(“name”, “张三”);
map.put(“age”, 23);
map.put(“birthday”, “1999-09-09”);
这些信息与学生类(Student)中的属性一一对应
class Student {
private String id;
private String name;
private Integer age;
private String birthday;
// getters and setters...
// toString()...
}
请利用反射的知识,将集合中的属性值通过学生实体类的set方法,封装到一个学生对象中,并打印该对象展示。
MapOfReflection.java
public class MapOfReflection {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
HashMap<String, Object> map = new HashMap<>();
map.put("id", "heima001");
map.put("name", "张三");
map.put("age", 23);
map.put("birthday", "1999-09-09");
//反射Class文件
Class<?> studentOfClass = Class.forName("code.study.school0107studentandmap.StudentOfReflection");
//反射构造方法
Constructor<?> constructorObj = studentOfClass.getConstructor();
//实例化构造方法
Object constructorInstance = constructorObj.newInstance();
//反射所有'set'的成员方法
Method methodObjOfId = studentOfClass.getMethod("setId", String.class);
Method methodObjOfName = studentOfClass.getMethod("setName", String.class);
Method methodObjOfAge = studentOfClass.getMethod("setAge", Integer.class);
Method methodObjOfBirthday = studentOfClass.getMethod("setBirthday", String.class);
//实例化所有'set'成员方法
methodObjOfId.invoke(constructorInstance,"heima001");
methodObjOfName.invoke(constructorInstance,"张三");
methodObjOfAge.invoke(constructorInstance,23);
methodObjOfBirthday.invoke(constructorInstance,"1999-09-09");
//反射和实例化toString方法,完成打印来展示对象内容.
Method methodObjOfTostring = studentOfClass.getMethod("toString");
Object toString = methodObjOfTostring.invoke(constructorInstance);
System.out.println(toString);
}
}
StudentOfReflection.java
public class StudentOfReflection {
private String id;
private String name;
private Integer age;
private String birthday;
@Override
public String toString() {
return "StudentOfReflection{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", birthday='" + birthday + '\'' +
'}';
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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 getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}