反射机制是干什么的:
反射在以后开发中的作用:
我们设计程序最终是要提高程序的执行效率,我们在开发一个模块的时候,要不停的去创建对象 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()
xxxxxxxxxx
71//获取字节码对象
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()
xxxxxxxxxx
41//getDeclaredField()这个方法可以去获取一个类中所有的属性
2Field id = stuClass.getDeclaredField("id");
3
4System.out.println(id);
getDeclaredFields()
xxxxxxxxxx
21//获取一个类中所有属性,封装成字节码数组
2Field[] declaredFields = stuClass.getDeclaredFields();
获取全类名
xxxxxxxxxx
11String name = stuClass.getName();
获取简类名
xxxxxxxxxx
11String simpleName = stuClass.getSimpleName();
获取属性的类型
declaredField.getType()
获取属性的修饰符
xxxxxxxxxx
71//获取属性的修饰符代号
2int modifiers = declaredField.getModifiers();
3
4//将代号转成修饰符字符串
5String string = Modifier.toSring(modifiers);
6
7System.out.println(string);
在学习反射时,获取类的信息都是通过get方法去获取的
由于java类中的方法支持重载,所以在调用getMethod(方法名称,参数类型)
方法时需要将方法的参数类型传入,不传入则默认获取无参的方法
xxxxxxxxxx
181public 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}
xxxxxxxxxx
181public 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}
其它的方法
xxxxxxxxxx
251for (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}
xxxxxxxxxx
171public 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}
写一个工具类,写一个静态方法,方法传入一个类的全类名,然后反编译(可以获取这个类中所有的信息)这个类工具类要适用于所有的类
根据反射获取类的信息
xxxxxxxxxx
1691package 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 * @return
27 */
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}
反射
获取父类
xxxxxxxxxx
11Class superclass = aClass.getSuperclass();
获取实现的接口
xxxxxxxxxx
11Class[] interfaces = aClass.getInterfaces();
无参构造实例
newInstance()
xxxxxxxxxx
151 //获取字节码对象
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()
不传参数就是获取无参构造实例
xxxxxxxxxx
131public 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}
xxxxxxxxxx
121//获取属性,返回属性字节码对象
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方法给属性赋值
xxxxxxxxxx
141//获取属性字节码对象
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方法给属性赋值
xxxxxxxxxx
231public 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}
注意:操作私有的方法需要打破封装
xxxxxxxxxx
11declaredMethod.setAccessible(true);
反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类,还有在struts2的struts.xml中配置action,也是通过反射调用的action
Json
格式属性值获取(工具类)xxxxxxxxxx
621package com.os467.utils;
2
3import java.lang.reflect.Field;
4
5public class ToJsonUtils {
6
7 private ToJsonUtils(){
8
9 }
10
11 /**
12 * 将实体的属性和属性值拼接成一个字符串
13 * @return
14 */
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}