共计 4255 个字符,预计需要花费 11 分钟才能阅读完成。
## 什么是反射?
反射允许对封装类的字段,方法和构造函数的信息进行编程访问。(就是从类中拿东西)
例子:IDEA中的代码提示就是通过反射将类中的方法、形参获取出来。
需要从class字节码文件中获取class对象再解剖信息。

获取class对象的三种方式
-
Class.forName("全类名");(全类名:包名+类名)。最为常用Class aClass = Class.forName("com.ouyu.Student"); -
类名.class。往往当作参数传递ClassbClass = Student.class ; -
对象.getClass();。有了这个类对对象时,才可以调用。Student s1 = new Student() ; Class aClass1 = s1.getClass(); System.out.println(aClass1);
利用反射获取构造方法
Class类中用于获取构造方法的方法(Declared代表一种权限,表示能够访问到所有的对象)
Constructor<?>[]getConstructors():返回所有的公共构造方法对象的数组Constructor[] cons = aClass.getConstructors();
Constructor<?>[]getDeclaredConstructors():返回所有构造方法对象的数组Constructor[] cons = aClass.getDeclaredConstructors();
Constructor<T>getConstructor(Class<?>...parameterTypes):返回单个公共构造方法对象Constructor con = aClass.getConstructor(String.class);//参数与构造方法一致
Constructor<T>getDeclaredConstructor(Class<?>...parameterTypes):返回单个构造方法对象Constructor con = aClass.geDeclaredtConstructor(String.class);//参数与构造方法一致
获取权限修饰符(getModifiers())
Constructor cons = aClass.getDeclaredConstructor();
int modifiers = cons.getModifiers();//public是1,private是2,具体其他参考文档
获取方法的参数(getParameters())
Parameter[] parameters = cons.getParameters();
for(Parameter e : parameters){
System.out.println(e);
}
Constructor类中用于创建对象的方法(newInstance(Object...initargs))
con.setAccessible(true);//如果构造方法是私有的添加如下代码临时取消访问权限,暴力获取
Constructor con = aClass.getDeclaredConstructor(String.class,int.class);
Student ouyu = (Student)con.newInstance("ouyu", 16);
利用反射获取成员变量
Class类中用于获取成员变量的方法
Field[] getFields:返回所有公共成员变量对象的数组Field[] fs = aClass.getFields();
Field[] getDeclaredFields:返回所有成员变量对象的数组Field[] fs = aClass.getDeclaredFields();
Field[] getField:返回单个公共成员变量对象Field[] f = aClass.getField();
Field[] getDeclaredField:返回单个成 员变量对象Field[] f = aClass.getDeclaredField();
获取权限修饰符(getModifiers())
Field f = aClass.getDeclaredField("name");
int modifiers = f.getModifiers();
System.out.println(modifiers);
获取成员变量的名字(getName())
Field f = aClass.getDeclaredField("name");
String s = f.getName() ;
获取成员变量的数据类型(getType())
Field f = aClass.getDeclaredField("name");
Class type = f.getType();
Field类中用于创建对象的方法
获取成员变量记录的值(get())
Student s1 = new Student("ouyu",12) ;
Field f = aClass.getDeclaredField("name");
f.setAccessible(true);////如果成员变量是私有的添加如下代码临时取消访问权限,暴力获取
String s = (String) f.get(s1);
修改对象里记录的值(set())
f.set(s1,"luolei");
利用反射获取成员方法
Class中用于获取成员方法的方法
Method[] getMethods:返回所有公共成员方法对象的数组(包含父类中所有的公共方法)Method[] ms = aClass.getMethods();
Method[] getDeclaredMethods:返回所有成员方法对象的数组(不能并获取父类的,但是可以获取本类中私有的)Method[] ms = aClass.getDeclaredMethods();
Method[] getMethod:返回单个公共成员方法对象(包含父类中所有的公共方法)Method[] m = aClass.getMethod("name",String.class,int.class);//获取指定名字和参数的成员方法
Method[] getDeclaredMethod:返回单个成员方法对象(不能并获取父类的,但是可以获取本类中私有的)Method[] m = aClass.getDeclaredMethod("name",String.class,int.class);//获取指定名字和参数的成员方法
获取成员方法的修饰符(getModifiers())
Method m = aClass.getDeclaredMethod("eat",String.class,int.class);
int modifiers = m.getModifiers();
获取方法抛出的异常
Method m = aClass.getDeclaredMethod("eat",String.class,int.class);
Class[] exceptionTypes = m.getExceptionTypes();
Method类中用于创建对象的方法
Object invoke(Object obj,Object...args):运行方法
参数1:用obj对象调用该方法
参数2:调用方法传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
Method m = aClass.getDeclaredMethod("eat",String.class,int.class);
Student s = new Student() ;
m.setAccessible(true);//方法为私有是临时取消访问权限
System.out.println(m.invoke(s,"薯条",12)); ;//第一个参数调用方法的对象,后面的是传给方法的参数,此时我的这个方法的返回值是字符串,
反射的作用
- 获取一个类的所有信息,获取到了之后,再执行其他业务逻辑
- 结合配置文件,动态地创建对象并调用方法
练习
将对象的成员变量写入txt文件当中
public static void saveObject(Object obj) throws IllegalAccessException, IOException {
//获取字节码文件
Class classz = obj.getClass() ;
//创建IO流
BufferedWriter bw = new BufferedWriter(new FileWriter("src\\a.txt")) ;
//获取成员变量
Field[] fields = classz.getDeclaredFields() ;
for(Field field : fields){
field.setAccessible(true);
String name = field.getName() ;
Object value = field.get(obj) ;
bw.write(name + " = " + value);
bw.newLine();
}
bw.close();
}
利用反射动态创建对象
//读取配置文件
Properties prop = new Properties() ;
FileInputStream fis = new FileInputStream("prop.properties") ;
prop.load(fis);
fis.close();
String classname = (String) prop.get("classname");
String methodname = (String) prop.get("method");
//读取类的字节码文件
Class clazz = Class.forName(classname) ;
//获取构造方法
Constructor con = clazz.getDeclaredConstructor(String.class,int.class);
//用构造方法创建对象
Student s = (Student) con.newInstance("ouyu",12);
System.out.println(s);
//获取成员方法
Method method = clazz.getDeclaredMethod(methodname,String.class,int.class);
method.setAccessible(true);
//调用成员方法
method.invoke(s,"薯条",12) ;
classname = com.ouyu.Student
method = eat
通过配置文件动态的创建对象。
总结
