反射Reflect
反射机制是干什么的:
- 可以在类加载的时候去获取类的相关信息(属性、方法、实现的接口、继承的类)
- 反射可以通过字节码的方式来创建实例
反射在以后开发中的作用:
我们设计程序最终是要提高程序的执行效率,我们在开发一个模块的时候,要不停的去创建对象 User user = new User();
使用new关键字,会使得程序之间产生耦合,以后new关键字使用多了,耦合就会变高,程序的执行效率就会很差
这个时候我们能不能换一种方式去创建实例,尽量避免使用new关键字,反射机制就可以在不使用new的情况下去创建实例
反射是各大java框架的底层:框架就是帮助程序解耦,提高程序的执行效率,提高开发人员的开发效率
spring 框架:容器
- 通过java语言中的反射机制可以操作字节码文件
- 通过反射机制可以操作代码片段
java.lang.reflect
什么是反射:
反射是java中比较偏底层的一种机制,通过反射可以在类加载时去获取类相关的信息
如何去获取一个类的字节码对象(Class)
对象.getClass()
类.class属性
Class.forName("全类名")
java.lang.Class:
代表整个字节码,代表一个类型,代表整个类
java.lang.reflect.Method
:代表字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor:
代表字节码中的构造方法字节码,代表类中的构造方法
java.lang.reflect.Field:
代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)
获取类中的属性
获取类中公共的属性
getField()
//获取字节码对象
Class stuClass = Class.forName("com.os467.pojo.Student");
//getField()这个方法只能去获取公共的属性
Field address = stuClass.getField("address");
System.out.println(address);
获取类中所有的属性
getDeclaredField()
//getDeclaredField()这个方法可以去获取一个类中所有的属性
Field id = stuClass.getDeclaredField("id");
System.out.println(id);
getDeclaredFields()
//获取一个类中所有属性,封装成字节码数组
Field[] declaredFields = stuClass.getDeclaredFields();
获取全类名
String name = stuClass.getName();
获取简类名
String simpleName = stuClass.getSimpleName();
获取属性的类型
declaredField.getType()
获取属性的修饰符
//获取属性的修饰符代号
int modifiers = declaredField.getModifiers();
//将代号转成修饰符字符串
String string = Modifier.toSring(modifiers);
System.out.println(string);
在学习反射时,获取类的信息都是通过get方法去获取的
获取类中的方法
由于java类中的方法支持重载,所以在调用getMethod(方法名称,参数类型)
方法时需要将方法的参数类型传入,不传入则默认获取无参的方法
获取类中公有的方法
public class ReflectDemo03 {
public static void main(String[] args) throws Exception {
//获取字节码对象
Class stuClass = Student.class;
//获取一个类中的方法
Method setAge = stuClass.getMethod("setAge",Integer.class);
System.out.println(setAge);
Method study = stuClass.getMethod("study", int.class, double.class, String.class);
System.out.println(study);
}
}
获取类中所有的方法
public class ReflectDemo03 {
public static void main(String[] args) throws Exception {
//获取字节码对象
Class stuClass = Student.class;
//获取一个类中所有的方法
Method[] declaredMethods = stuClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
}
}
其它的方法
for (Method method : declaredMethods) {
//获取方法名称
System.out.println("方法名称"+method.getName());
//获取方法返回值类型
System.out.println("返回值类型"+method.getReturnType().getSimpleName());
//获取方法的参数
for (Class<?> parameterType : method.getParameterTypes()) {
System.out.println("方法的参数类型"+parameterType);
}
//获取修饰符
int modifiers = method.getModifiers();
//将修饰符代号转成字符串
String s = Modifier.toString(modifiers);
System.out.println("修饰符"+s);
}
获取所有的构造
public static void main(String[] args) throws Exception {
//获取字节码对象
Class aClass = Class.forName("com.os467.pojo.Student");
//获取所有的构造
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
//遍历数组
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
反射工具类ReflectUtils
写一个工具类,写一个静态方法,方法传入一个类的全类名,然后反编译(可以获取这个类中所有的信息)这个类工具类要适用于所有的类
根据反射获取类的信息
- 1、根据流对象先读取配置文件中的全类名数据
- 2、根据全类名创建字节码对象
- 3、根据字节码对象去获取类的信息,完成类的反编译
package com.os467.utils;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Properties;
/**
* 反编译工具类
*/
public class ReflectUtils {
//构造私有化
private ReflectUtils(){
}
/**
* 根据反射获取类的信息
* 1、根据流对象先读取配置文件中的全类名数据
* 2、根据全类名创建字节码对象
* 3、根据字节码对象去获取类的信息,完成类的反编译
* @return
*/
public static String getTypeMessageByReflect(){
//用于字符串的追加,效率要比String高
StringBuilder stringBuilder = new StringBuilder();
try {
//创建流对象
FileReader fileReader = new FileReader("className.properties");
//创建集合对象
Properties properties = new Properties();
//将配置文件中的数据装载到集合里面
properties.load(fileReader);
//根据全类名创建字节码对象
Class aClass = Class.forName(properties.getProperty("className"));
stringBuilder.append("public class ");
stringBuilder.append(aClass.getSimpleName()+" { \n");
//获取类中所有的属性
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
stringBuilder.append("\n\t");
//获取属性的修饰符
int modifiers = declaredField.getModifiers();
//转成修饰符字符串
String s = Modifier.toString(modifiers);
//获取属性类型
String simpleName = declaredField.getType().getSimpleName();
//获取属性的名称
String name = declaredField.getName();
stringBuilder.append(s+" "+simpleName+" "+name+";");
stringBuilder.append("\n");
}
//获取类的所有构造
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
//遍历数组
for (Constructor declaredConstructor : declaredConstructors) {
stringBuilder.append("\n\t");
//获取构造的修饰符
int modifiers = declaredConstructor.getModifiers();
//转成修饰符字符串
String s = Modifier.toString(modifiers);
//获取构造名称
String name = aClass.getSimpleName();
stringBuilder.append(s + " " + name + "(");
//获取参数列表
Class[] parameterTypes = declaredConstructor.getParameterTypes();
//遍历参数列表
for (Class parameterType : parameterTypes) {
//获取参数名
stringBuilder.append(parameterType.getSimpleName()+",");
}
//判断有参的还是无参的
if (parameterTypes.length > 0){
//删除具体下标下面的字符
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
stringBuilder.append(") {}");
stringBuilder.append("\n");
//获取所有的普通方法
Method[] declaredMethods = aClass.getDeclaredMethods();
//遍历数组
for (Method declaredMethod : declaredMethods) {
stringBuilder.append("\n\t");
//获取方法的修饰符
int modifiers1 = declaredMethod.getModifiers();
//转成修饰符字符串
String s1 = Modifier.toString(modifiers1);
//获取返回值类型
String simpleName = declaredMethod.getReturnType().getSimpleName();
stringBuilder.append(s1 + " " +simpleName + " " + declaredMethod.getName()+"(");
//获取普通方法的参数列表
Class[] parameterTypes1 = declaredMethod.getParameterTypes();
//遍历参数
for (Class parameterType : parameterTypes1) {
stringBuilder.append(parameterType.getSimpleName()+",");
if (parameterTypes.length > 0){
//删除最后一个逗号
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
}
stringBuilder.append("){}");
stringBuilder.append("\n");
}
}
stringBuilder.append("\n}");
} catch (Exception e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
}
反射
- 通过反射机制访问对象的某个属性
- 通过反射机制调用对象的某个方法
- 通过反射机制调用某个构造方法实例化对象
- 通过反射机制获取父类及父类型接口
获取父类
Class superclass = aClass.getSuperclass();
获取实现的接口
Class[] interfaces = aClass.getInterfaces();
如何通过反射机制来创建一个类的实例
无参构造实例
newInstance()
//获取字节码对象
Class aClass = Student.class;
//如何通过反射机制来创建一个类的实例
//默认情况下调用的是无参构造
Object o = aClass.newInstance();
if (o instanceof Student){
Student student = (Student)o;
System.out.println(student);
}
有参构造实例
getDeclaredConstructor()
不传参数就是获取无参构造实例
public static void main(String[] args) throws Exception {
//创建字节码对象
Class aClass = User.class;
//获取构造字节码对象
Constructor constructor = aClass.getDeclaredConstructor(String.class,String.class);
Object obj02 = constructor.newInstance("root", "123456");
System.out.println(obj02);
}
如何通过反射来给属性赋值
//获取属性,返回属性字节码对象
Field addressFiled = aClass.getDeclaredField("address");
//给属性进行一个赋值操作
//Object obj 属性所在类的实例
//Object value 具体要赋的值
addressFiled.set(o,"南京市");
//通过反射获取属性具体的值
System.out.println(addressFiled.get(o));
System.out.println(o);
如何通过反射获取属性值
方法一:
先打破封装,再通过set方法给属性赋值
//获取属性字节码对象
Field declaredFieldName = aClass.getDeclaredField("name");
//打破封装
declaredFieldName.setAccessible(true);
//通过反射机制来创建一个类的实例
//采用的无参构造创建的实例
Object o = aClass.newInstance();
//调用set方法给属性赋值
declaredFieldName.set(o,"张三");
System.out.println(o);
方法二:
通过反射调用这个属性所对应的set方法给属性赋值
通过反射调用类中的方法
public static void main(String[] args) throws Exception {
//获取字节码对象
Class userClass = User.class;
//获取方法字节码对象
Method declaredMethod = userClass.getDeclaredMethod("login",String.class,String.class);
//通过反射创建实例
Object o = userClass.newInstance();
//调用方法
//通过反射调用方法的方法
//Object var1 当前方法所在类的实例
//Object... var2 你需要传的参数
Object invoke = declaredMethod.invoke(o, "zs001", "123456");
System.out.println(invoke);
}
注意:操作私有的方法需要打破封装
declaredMethod.setAccessible(true);
反射在以后的用途
反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类,还有在struts2的struts.xml中配置action,也是通过反射调用的action
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com