本文实例讲述了java高级特性之反射机制。分享给大家供大家参考,具体如下:
老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值
- 一、 什么是反射?
- 二、反射能做什么?
一、 什么是反射?
用在java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
如果你是一个android developer,前辈们都会教导你尽量少用反射,效率太低,太慢。“射”嘛,射的太快就不好了,所以反射虽然慢点,但是偶尔射一下还是很”爽”的。
二、反射能做什么?
1、新建类的实例
我们知道所有的类都继承子顶级父类object,而object中有hashcode()
、equals()
、clone()
、tostring()
、getclass()
等。其中getclass()
返回一个class 对象。我们这里就需要使用的class对象,注意c是大写,我们可以通过一下方式来获取class对象
- 1.class.forname("类名字符串") (注意:类名字符串必须是全称,包名+类名)
- 2.类名.class
- 3.实例对象.getclass()
在class类中有一个非常重要的方法
1
2
3
4
|
public t newinstance() throws instantiationexception, illegalaccessexception { return newinstanceimpl(); } private native t newinstanceimpl() throws illegalaccessexception, instantiationexception; |
查看api可以看到调用newinstace
方法可以返回当前class对应的实例对象。接下来看一个小的demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class reflection { public static void main(string[] args) { // 普通创建类的实例 people p1 = new people(); system.out.println(p1.getname()); // 利用反射获取类的实例 class clazz = people. class ; // 常用方式,注意括号中需要放类的全路径名 // class clazz = class.forname("reflection.people"); // class clazz = p1.getclass(); try { people p2 = (people) clazz.newinstance(); system.out.println(p2.getname()); } catch (exception e) { e.printstacktrace(); } } } class people { private string name = "张三" ; private int 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; } } |
输入结果:
张三
张三
2、获取成员变量和方法
在讲之前我们先来看这样一个小按理,json数据转javabaen对象,在不用解析库的情况下,一般我们会这样做
- private void analysisdate(jsonobject response) throws jsonexception {
- int announceid = response.getint("announceid");
- string title = response.getstring("title");
- string hits = response.getstring("hits");
- string addtime = response.getstring("addtime");
- newsnotifyitem newsnotifyitem = new newsnotifyitem(announceid,
- title, hits, addtime);
- }
- }
每当我们需要解析额时候,都需要根据不同javabean来进行相应的解析,我们每次进行的操作都是一样的,只是解析的数据不同而已,结合上篇帖子讲到的泛型,这里我们就可以再利用反射来自己做一个json解析工具
下面 是我写的一个jsonobject对象转javabean的一个工具类,需要注意的是,json的key需要和字段名保持一致,先说下思路
①首先通过反射获取javabean中的所有字段值的名称
②拼接出set方法
③由于字段名和json的key值相同,利用自动名获取json中的值并填充的实例对象中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
public class json2beanutils { public static <t> t jsontobean(jsonobject response, class <t> clazz) { try { // 创建类的实例 object object = class .forname(clazz.getname()).newinstance(); // 获取类中的所有成员变量 field[] fields = object.getclass().getdeclaredfields(); for ( int i = 0 ; i < fields.length; i++) { //设置权限 fields[i].setaccessible( true ); // 获取字段的名称 string fieldname = fields[i].getname(); // 过滤掉uid if (fieldname.endswith( "serialversionuid" )) { continue ; } // 获取字段的类型 string fieldtype = fields[i].getgenerictype().tostring(); // 拼接出javabean中的set方法 这里有一个坑 后面讲解 string methodname = "set" + fieldname.substring( 0 , 1 ).touppercase() + fieldname.substring( 1 ); try { // 判断变量类型 if (fieldtype.endswith( "class java.lang.string" )) { // 获取到set方法 method m = object.getclass().getmethod(methodname, string. class ); string value = null ; try { // 从jsonobj中取出相应的值 value = response.getstring(fieldname); } catch (exception e) { e.printstacktrace(); value = "" ; } if (textutils.isempty(value)) { value = "" ; } else if (value.endswith( "null" )) { value = "" ; } // 赋值 m.invoke(object, value); } else if (fieldtype.endswith( "int" ) || fieldtype.endswith( "class java.lang.integer" )) { // int 类型 system.out.println(); method m = object.getclass().getmethod(methodname, int . class ); int value = - 1 ; try { value = response.getint(fieldname); } catch (exception e) { e.printstacktrace(); value = - 1 ; } m.invoke(object, value); } else if (fieldtype.endswith( "boolean" ) || fieldtype .endswith( "fieldtype:class java.lang.boolean" )) { // boolean 类型 method m = object.getclass().getmethod(methodname, boolean . class ); boolean value = false ; try { value = response.getboolean(fieldname); } catch (exception e) { e.printstacktrace(); value = false ; } m.invoke(object, value); } else if (fieldtype.endswith( "double" ) || fieldtype .endswith( "fieldtype:class java.lang.double" )) { // double 类型 method m = object.getclass().getmethod(methodname, double . class ); double value = -1d; try { value = response.getdouble(fieldname); } catch (exception e) { e.printstacktrace(); value = -1d; } m.invoke(object, value); } else if (fieldtype.endswith( "char" )) { // char类型 jsonobject 没有char method m = object.getclass().getmethod(methodname, string. class ); string value = "" ; try { value = response.getstring(fieldname); } catch (exception e) { e.printstacktrace(); value = "" ; } m.invoke(object, value); } else if (fieldtype.endswith( "float" ) || fieldtype .endswith( "fieldtype:class java.lang.float" )) { // float类型 method m = object.getclass().getmethod(methodname, double . class ); double value = -1d; try { value = response.getdouble(fieldname); } catch (exception e) { e.printstacktrace(); value = -1d; } m.invoke(object, value); } else if (fieldtype.endswith( "short" ) || fieldtype .endswith( "fieldtype:class java.lang.short" )) { // short method m = object.getclass().getmethod(methodname, short . class ); int value = - 1 ; try { value = response.getint(fieldname); } catch (exception e) { e.printstacktrace(); value = - 1 ; } m.invoke(object, value); } else if (fieldtype.endswith( "byte" ) || fieldtype .endswith( "fieldtype:class java.lang.byte" )) { method m = object.getclass().getmethod(methodname, byte . class ); int value = - 1 ; try { value = response.getint(fieldname); } catch (exception e) { e.printstacktrace(); value = - 1 ; } m.invoke(object, value); } else if (fieldtype.endswith( "long" ) || fieldtype .endswith( "fieldtype:class java.lang.long" )) { method m = object.getclass().getmethod(methodname, long . class ); long value = -1l; try { value = response.getlong(fieldname); } catch (exception e) { e.printstacktrace(); value = -1l; } m.invoke(object, value); } } catch (exception e) { // todo: handle exception } } return (t) object; } catch (exception e) { e.printstacktrace(); } return null ; } } |
这里需要注意一个坑,先来看一段代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class people { private string name; private int age; private string msex; 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 string getmsex() { return msex; } // 这里就出了问题 public void setmsex(string msex) { this .msex = msex; } } |
当我们自动生成get set方法时,会将字段的首字母大写,我们在上面拼接set 方法时,也是基于这样的规则来拼装的。但是 当我们的字段名为 aabbb 时,则生成的get set 方法则不会大写。解决方案也很简单,注意字段命名或者在拼接时对第二个自动进行大小写判断。这样我们自己写的json解析工具就搞定, 以后每次解析只需一行代码即可ok。
今天反射就暂时讲到这里。其实反射的作用远不于此,这里只是使用了反射的冰山一角,结合注解和泛型,反射可以做的事更多,但是还是和开头讲的一样,反射用起来虽然很爽,但是不能乱射,和频繁的射,“射”的太多。“性”能会出问题!(o(∩_∩)o )。
希望本文所述对大家java程序设计有所帮助。
原文链接:https://blog.csdn.net/soul_code/article/details/50466935