反射机制是干什么的:
反射在以后开发中的作用:
我们设计程序最终是要提高程序的执行效率,我们在开发一个模块的时候,要不停的去创建对象 User user = new User(); 使用new关键字,会使得程序之间产生耦合,以后new关键字使用多了,耦合就会变高,程序的执行效率就会很差
这个时候我们能不能换一种方式去创建实例,尽量避免使用new关键字,反射机制就可以在不使用new的情况下去创建实例
反射是各大java框架的底层:框架就是帮助程序解耦,提高程序的执行效率,提高开发人员的开发效率
spring 框架:容器
java.lang.reflect
什么是反射:
反射是java中比较偏底层的一种机制,通过反射可以在类加载时去获取类相关的信息
对象.getClass()
类.class属性
Class.forName("全类名")
java.lang.Class:
代表整个字节码,代表一个类型,代表整个类
java.lang.reflect.Method:
代表字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor:
代表字节码中的构造方法字节码,代表类中的构造方法
java.lang.reflect.Field:
代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)
getField()
xxxxxxxxxx71//获取字节码对象2 Class stuClass = Class.forName("com.os467.pojo.Student");3
4 //getField()这个方法只能去获取公共的属性5 Field address = stuClass.getField("address");6
7 System.out.println(address);
getDeclaredField()
xxxxxxxxxx41//getDeclaredField()这个方法可以去获取一个类中所有的属性2Field id = stuClass.getDeclaredField("id");3
4System.out.println(id);
getDeclaredFields()
xxxxxxxxxx21//获取一个类中所有属性,封装成字节码数组2Field[] declaredFields = stuClass.getDeclaredFields();
获取全类名
xxxxxxxxxx11String name = stuClass.getName();获取简类名
xxxxxxxxxx11String simpleName = stuClass.getSimpleName();
获取属性的类型
declaredField.getType()
获取属性的修饰符
xxxxxxxxxx71//获取属性的修饰符代号2int modifiers = declaredField.getModifiers();3
4//将代号转成修饰符字符串5String string = Modifier.toSring(modifiers);6
7System.out.println(string);
在学习反射时,获取类的信息都是通过get方法去获取的
由于java类中的方法支持重载,所以在调用getMethod(方法名称,参数类型)方法时需要将方法的参数类型传入,不传入则默认获取无参的方法
xxxxxxxxxx181public class ReflectDemo03 {2
3 public static void main(String[] args) throws Exception {4
5 //获取字节码对象6 Class stuClass = Student.class;7
8 //获取一个类中的方法9 Method setAge = stuClass.getMethod("setAge",Integer.class);10
11 System.out.println(setAge);12
13 Method study = stuClass.getMethod("study", int.class, double.class, String.class);14
15 System.out.println(study);16
17 }18}
xxxxxxxxxx181public class ReflectDemo03 {2
3 public static void main(String[] args) throws Exception {4
5 //获取字节码对象6 Class stuClass = Student.class;7
8 //获取一个类中所有的方法9 Method[] declaredMethods = stuClass.getDeclaredMethods();10
11 for (Method declaredMethod : declaredMethods) {12
13 System.out.println(declaredMethod);14
15 }16
17 }18}
其它的方法
xxxxxxxxxx251for (Method method : declaredMethods) {2
3 //获取方法名称4 System.out.println("方法名称"+method.getName());5
6 //获取方法返回值类型7 System.out.println("返回值类型"+method.getReturnType().getSimpleName());8
9 //获取方法的参数10 for (Class<?> parameterType : method.getParameterTypes()) {11
12 System.out.println("方法的参数类型"+parameterType);13
14
15 }16
17 //获取修饰符18 int modifiers = method.getModifiers();19
20 //将修饰符代号转成字符串21 String s = Modifier.toString(modifiers);22
23 System.out.println("修饰符"+s);24
25}
xxxxxxxxxx171public static void main(String[] args) throws Exception {2
3
4 //获取字节码对象5 Class aClass = Class.forName("com.os467.pojo.Student");6
7 //获取所有的构造8 Constructor[] declaredConstructors = aClass.getDeclaredConstructors();9
10 //遍历数组11 for (Constructor declaredConstructor : declaredConstructors) {12
13 System.out.println(declaredConstructor);14
15 }16
17}
写一个工具类,写一个静态方法,方法传入一个类的全类名,然后反编译(可以获取这个类中所有的信息)这个类工具类要适用于所有的类
根据反射获取类的信息
xxxxxxxxxx1691package com.os467.utils;2
3import java.io.FileNotFoundException;4import java.io.FileReader;5import java.lang.reflect.Constructor;6import java.lang.reflect.Field;7import java.lang.reflect.Method;8import java.lang.reflect.Modifier;9import java.util.Properties;10
11/**12 * 反编译工具类13 */14public class ReflectUtils {15
16 //构造私有化17 private ReflectUtils(){18
19 }20
21 /**22 * 根据反射获取类的信息23 * 1、根据流对象先读取配置文件中的全类名数据24 * 2、根据全类名创建字节码对象25 * 3、根据字节码对象去获取类的信息,完成类的反编译26 * @return27 */28 public static String getTypeMessageByReflect(){29
30 //用于字符串的追加,效率要比String高31 StringBuilder stringBuilder = new StringBuilder();32
33 try {34
35 //创建流对象36 FileReader fileReader = new FileReader("className.properties");37
38 //创建集合对象39 Properties properties = new Properties();40
41 //将配置文件中的数据装载到集合里面42 properties.load(fileReader);43
44 //根据全类名创建字节码对象45 Class aClass = Class.forName(properties.getProperty("className"));46
47 stringBuilder.append("public class ");48 stringBuilder.append(aClass.getSimpleName()+" { \n");49 //获取类中所有的属性50 Field[] declaredFields = aClass.getDeclaredFields();51
52 for (Field declaredField : declaredFields) {53
54 stringBuilder.append("\n\t");55
56 //获取属性的修饰符57 int modifiers = declaredField.getModifiers();58
59 //转成修饰符字符串60 String s = Modifier.toString(modifiers);61
62 //获取属性类型63 String simpleName = declaredField.getType().getSimpleName();64
65 //获取属性的名称66 String name = declaredField.getName();67
68 stringBuilder.append(s+" "+simpleName+" "+name+";");69 stringBuilder.append("\n");70
71 }72
73 //获取类的所有构造74 Constructor[] declaredConstructors = aClass.getDeclaredConstructors();75
76 //遍历数组77 for (Constructor declaredConstructor : declaredConstructors) {78
79 stringBuilder.append("\n\t");80
81 //获取构造的修饰符82 int modifiers = declaredConstructor.getModifiers();83
84 //转成修饰符字符串85 String s = Modifier.toString(modifiers);86
87 //获取构造名称88 String name = aClass.getSimpleName();89
90 stringBuilder.append(s + " " + name + "(");91
92 //获取参数列表93 Class[] parameterTypes = declaredConstructor.getParameterTypes();94
95 //遍历参数列表96 for (Class parameterType : parameterTypes) {97
98 //获取参数名99 stringBuilder.append(parameterType.getSimpleName()+",");100
101 }102
103 //判断有参的还是无参的104 if (parameterTypes.length > 0){105
106 //删除具体下标下面的字符107 stringBuilder.deleteCharAt(stringBuilder.length() - 1);108
109 }110
111 stringBuilder.append(") {}");112
113 stringBuilder.append("\n");114
115 //获取所有的普通方法116 Method[] declaredMethods = aClass.getDeclaredMethods();117
118 //遍历数组119 for (Method declaredMethod : declaredMethods) {120
121 stringBuilder.append("\n\t");122
123 //获取方法的修饰符124 int modifiers1 = declaredMethod.getModifiers();125
126 //转成修饰符字符串127 String s1 = Modifier.toString(modifiers1);128
129 //获取返回值类型130 String simpleName = declaredMethod.getReturnType().getSimpleName();131
132 stringBuilder.append(s1 + " " +simpleName + " " + declaredMethod.getName()+"(");133
134 //获取普通方法的参数列表135 Class[] parameterTypes1 = declaredMethod.getParameterTypes();136
137 //遍历参数138 for (Class parameterType : parameterTypes1) {139
140 stringBuilder.append(parameterType.getSimpleName()+",");141
142 if (parameterTypes.length > 0){143
144 //删除最后一个逗号145 stringBuilder.deleteCharAt(stringBuilder.length() - 1);146
147 }148
149 }150 stringBuilder.append("){}");151
152 stringBuilder.append("\n");153
154 }155
156 }157
158 stringBuilder.append("\n}");159
160 } catch (Exception e) {161 e.printStackTrace();162 }163
164
165 return stringBuilder.toString();166 }167
168
169}
反射
获取父类
xxxxxxxxxx11Class superclass = aClass.getSuperclass();获取实现的接口
xxxxxxxxxx11Class[] interfaces = aClass.getInterfaces();
无参构造实例
newInstance()
xxxxxxxxxx151 //获取字节码对象2Class aClass = Student.class;3
4//如何通过反射机制来创建一个类的实例5//默认情况下调用的是无参构造6Object o = aClass.newInstance();7
8if (o instanceof Student){9
10 Student student = (Student)o;11
12 System.out.println(student);13
14}15
有参构造实例
getDeclaredConstructor() 不传参数就是获取无参构造实例
xxxxxxxxxx131public static void main(String[] args) throws Exception {2
3 //创建字节码对象4 Class aClass = User.class;5
6 //获取构造字节码对象7 Constructor constructor = aClass.getDeclaredConstructor(String.class,String.class);8
9 Object obj02 = constructor.newInstance("root", "123456");10
11 System.out.println(obj02);12 13}
xxxxxxxxxx121//获取属性,返回属性字节码对象2Field addressFiled = aClass.getDeclaredField("address");3
4//给属性进行一个赋值操作5//Object obj 属性所在类的实例6//Object value 具体要赋的值7addressFiled.set(o,"南京市");8
9//通过反射获取属性具体的值10System.out.println(addressFiled.get(o));11
12System.out.println(o);
方法一:
先打破封装,再通过set方法给属性赋值
xxxxxxxxxx141//获取属性字节码对象2Field declaredFieldName = aClass.getDeclaredField("name");3
4//打破封装5declaredFieldName.setAccessible(true);6
7//通过反射机制来创建一个类的实例8//采用的无参构造创建的实例9Object o = aClass.newInstance();10
11//调用set方法给属性赋值12declaredFieldName.set(o,"张三");13
14System.out.println(o);方法二:
通过反射调用这个属性所对应的set方法给属性赋值
xxxxxxxxxx231public static void main(String[] args) throws Exception {2
3 //获取字节码对象4 Class userClass = User.class;5
6 //获取方法字节码对象7 Method declaredMethod = userClass.getDeclaredMethod("login",String.class,String.class);8
9 //通过反射创建实例10 Object o = userClass.newInstance();11
12 //调用方法13 //通过反射调用方法的方法14 //Object var1 当前方法所在类的实例15 //Object... var2 你需要传的参数16 //如果需要传入数组,先将数组转成Object类型 (Object)String[]17 //否则此方法会从数组中取值18 Object invoke = declaredMethod.invoke(o, "zs001", "123456");19
20 System.out.println(invoke);21
22
23}注意:操作私有的方法需要打破封装
xxxxxxxxxx11declaredMethod.setAccessible(true);
反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类,还有在struts2的struts.xml中配置action,也是通过反射调用的action
Json格式属性值获取(工具类)xxxxxxxxxx621package com.os467.utils;2
3import java.lang.reflect.Field;4
5public class ToJsonUtils {6
7 private ToJsonUtils(){8
9 }10
11 /**12 * 将实体的属性和属性值拼接成一个字符串13 * @return14 */15 public static String toJson(Object obj){16
17 //获取字节码对象18 Class aClass = obj.getClass();19
20 //获取属性字节码对象21 Field[] declaredFields = aClass.getDeclaredFields();22
23 //创建字符串对象24 StringBuilder stringBuilder = new StringBuilder();25
26 stringBuilder.append("{");27
28 for (Field declaredField : declaredFields) {29
30 //打破封装31 declaredField.setAccessible(true);32
33 //获取属性名34 String name = declaredField.getName();35
36 stringBuilder.append(name+":\"");37
38 Object o = null;39
40 //获取属性值41 try {42
43 o = declaredField.get(obj);44
45 stringBuilder.append(o+"\",");46
47 } catch (IllegalAccessException e) {48 e.printStackTrace();49 }50
51 }52
53 stringBuilder.deleteCharAt(stringBuilder.length()-1);54
55 StringBuilder s = stringBuilder.append("}");56
57 System.out.println(s);58
59 return null;60 }61
62}