0
点赞
收藏
分享

微信扫一扫

(转)使用JAVA反射的利与弊


在Java的20周年的纪念日的日子里,让我们来重新温习下Java里面的高级知识,Java肯定希望大家了解她,要不然你跟她天天相濡以沫了这么长时间,让她知道你竟然不了解她,不在乎她,那么她该有多伤心呢,所以我们不应该做一个负心汉,更不应该做一个忘恩负义的人,她教会了你生存的技能,所以我们也应该将她发扬光大! 

Java的核心技能有如下几项: 
(1)JVM的调优 
(2)类加载器 
(3)反射 
(4)动态编译 
(5)动态代理 
(6)注解 
(7)多线程 
(8)IO,NIO,Socket,Channel等网络编程 
除了JAVA的基础,面向对象的思想外,这些既是java里面核心技术,也是面试时候,面试官经常爱问的几个知识,了解,熟悉和掌握他们的重要性不言而喻,今天就先来谈谈反射。 

反射给java提供了,运行时获取一个类实例的可能,这一点非常灵活,你仅仅传一个类的全包名路径,就能通过反射,来获取对应的类实例,我们一般会用Class类,来调用这个被反射的Objcet类下的,构造方法,属性,或方法等,反射在一些开源框架里用的非常之多,Spring,Struts,Hibnerate,MyBatics都有它的影子,反射虽然很灵活,能够使得写的代码,变的大幅精简,所以在用的时候,一定要注意具体的应用场景,反射的优缺点如下: 

优点: 

(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。 
(2)与Java动态编译相结合,可以实现无比强大的功能 

缺点: 
(1)使用反射的性能较低 
(2)使用反射相对来说不安全 
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性 

任何事物,都有两面性,反射的优点,也同是就是它的缺点,所以,没有好与坏,只有最合适的场景,一阴一阳,才是天道平衡的条件。 

下面来看个,使用java反射,来自动封装数据库对应的表的例子,初学java的人都会给每个实体类建立一个Dao对象,来专门操作这个对象对应的表,这样做没错,很好,是分层,分工明确的一个表现,但是如果有几十个实体类,那么这种重复增删改查的工作,就会大大增加,散仙初入门的时候也有如此的感受,虽然我们可以通过,抽象类和接口,使用适配器的设计模式来简化重复的代码,但是不可避免的就是类的臃肿了,下面看看如何使用反射来搞定这么多实体类的重复的增删改查的代码: 
使用前提: 
(1)每一个实体类都会对应一个数据库表 
(2)每个表的列,与对应的实体类的属性名是一样的 
(3)实体类要提供基本的get或set方法 



​​​

(转)使用JAVA反射的利与弊_java

​​​ 

实体类如下:  



Java代码    ​​


​​

1. package
2.
3. public class
4.
5. private int
6. private
7. private
8. private
9. private int
10. public int
11. return
12. }
13. public void setId(int
14. this.id = id;
15. }
16. public
17. return
18. }
19. public void
20. this.name = name;
21. }
22. public
23. return
24. }
25. public void
26. this.type = type;
27. }
28. public
29. return
30. }
31. public void
32. this.color = color;
33. }
34. public int
35. return
36. }
37. public void setWeight(int
38. this.weight = weight;
39. }
40. public
41. // TODO Auto-generated constructor stub
42. }
43. public Dog(int id, String name, String type, String color, int
44. super();
45. this.id = id;
46. this.name = name;
47. this.type = type;
48. this.color = color;
49. this.weight = weight;
50. }
51. @Override
52. public
53. return "Dog [id=" + id + ", name=" + name + ", type=" + type + ", color="
54. ", weight=" + weight + "]";
55. }
56.
57.
58.
59.
60. }

Java代码    ​​​​


1. package
2.
3. public class
4.
5. private int
6. private
7. private int
8. private
9. public int
10. return
11. }
12. public void setId(int
13. this.id = id;
14. }
15. public
16. return
17. }
18. public void
19. this.name = name;
20. }
21. public int
22. return
23. }
24. public void setAge(int
25. this.age = age;
26. }
27. public
28. return
29. }
30. public void
31. this.address = address;
32. }
33.
34. public
35. // TODO Auto-generated constructor stub
36. }
37. public Person(int id, String name, int
38. super();
39. this.id = id;
40. this.name = name;
41. this.age = age;
42. this.address = address;
43. }
44. @Override
45. public
46. return "Person [id=" + id + ", name=" + name + ", age="
47. ", address=" + address + "]";
48. }
49.
50.
51.
52. }


Java代码    ​​​​


    1. package
    2.
    3. import
    4. import
    5. import
    6. import
    7. /**
    8. * 数据库连接的
    9. * 测试类
    10. * @author qindongliang
    11. *
    12. *
    13. * **/
    14. public class
    15.
    16. public static Connection getCon()throws
    17. "com.mysql.jdbc.Driver");
    18. //加上字符串编码指定,防止乱码
    19. "jdbc:mysql://localhost:3306/rate?characterEncoding=utf8", "root", "qin");
    20. return
    21. }
    22.
    23.
    24. public static void main(String[] args) throws
    25.
    26. "com.mysql.jdbc.Driver");
    27. "jdbc:mysql://localhost:3306/rate", "root", "qin");
    28. System.out.println(connection);
    29. connection.close();
    30.
    31.
    32. }
    33.
    34. }


    Java代码    ​​​​


    1. package
    2.
    3. import
    4. import
    5. import
    6. import
    7. import
    8. import
    9. import
    10.
    11. import
    12. import
    13. import
    14. /***
    15. * 反射自动查询和封装的类
    16. *@author qindongliang
    17. *
    18. * */
    19. public class
    20.
    21.
    22. /**
    23. * @param obj需要保存的对象
    24. * @param string 保存对象的sql语句
    25. * */
    26. public static
    27.
    28. new StringBuffer("insert into ");
    29.
    30. //得到对象的类
    31. Class c=obj.getClass();
    32. //得到对象中的所有方法
    33. Method[] ms=c.getMethods();
    34.
    35. //得到对象中所有的属性,虽然在这个里面就能获取所有的字段名,但不建议这么用,破坏类的封装性
    36. Field[] fs=c.getDeclaredFields();
    37. //得到对象类的名字
    38. String cname=c.getName();
    39. "类名字: "+cname);
    40. //表名字
    41. "\\.")[cname.split("\\.").length-1];
    42. "表名字: "+tableName);
    43. //追加表名和(左边的符号
    44. " (");
    45. //存放列名的集合
    46. new
    47. //存放值的集合
    48. new
    49. //遍历方法
    50. for(Method m:ms){
    51. //获取每一个方法名
    52. //只得到具有get方法的属性,getClass除外
    53. if(methodName.startsWith("get")&&!methodName.startsWith("getClass")){
    54. //System.out.println("属性名:"+methodName);
    55. 3, methodName.length());
    56. // System.out.println("字段名:"+fieldName);
    57. //将列名添加到列名的集合里
    58. try{
    59. null);
    60. //System.out.println("执行方法返回的值:"+value);
    61. if(value instanceof
    62. // System.out.println("字符串类型字段值:"+value);
    63. "'"+value+"'");//加上两个单引号,代表是字符串类型的
    64. else{
    65. // System.out.println("数值类型字段值:"+value);
    66. //数值类型的则直接添加
    67. }
    68.
    69. catch(Exception e){
    70. e.printStackTrace();
    71. }
    72.
    73. }
    74.
    75. }
    76.
    77.
    78. for(int i=0;i<columns.size();i++){
    79. String column=columns.get(i);
    80. Object value=values.get(i);
    81. "列名:"+column+" 值: "+value);
    82. }
    83.
    84. //拼接列名
    85. for(int i=0;i<columns.size();i++){
    86. if(i==columns.size()-1){
    87. " ) ");
    88. else{
    89. " , ");
    90. }
    91. }
    92. " 拼接列名后的sql:"+sb.toString());
    93. " values ( ");
    94. //拼接值
    95. for(int i=0;i<values.size();i++){
    96. if(i==values.size()-1){
    97. " ) ");
    98. else{
    99. " , ");
    100. }
    101. }
    102.
    103. " 拼接值后的sql:"+sb.toString());
    104.
    105. //返回组装的sql语句
    106. return
    107. }
    108.
    109. /**
    110. * 将对象保存在数据库中
    111. * @param obj 保存的对象
    112. * **/
    113. public static void
    114. try
    115. Connection con=ConnectionFactory.getCon();
    116. String sql=createSqlByObject(obj);
    117. PreparedStatement ps=con.prepareStatement(sql);
    118. int
    119. if(result==1){
    120. "保存成功!");
    121. else{
    122. "保存失败!");
    123. }
    124. ps.close();
    125. con.close();
    126. catch
    127. // TODO Auto-generated catch block
    128. e.printStackTrace();
    129. }
    130.
    131. }
    132.
    133. /**
    134. * 根据类名字和一个查询条件
    135. * 自动封装一个Bean对象
    136. * @param columnName 列名
    137. * @param value 列值
    138. * @return {@link Object}
    139. *
    140. * */
    141. public static
    142.
    143. "\\.")[className.split("\\.").length-1];
    144. "表名字: "+tableName);
    145.
    146. //根据类名来创建对象
    147. null;
    148. try{
    149. //反射生成一个类实例
    150. catch(Exception e){
    151. e.printStackTrace();
    152. }
    153. //拼接sql语句
    154. new
    155. "select * from ")
    156. .append(tableName)
    157. " where ")
    158. " = ").append("'").append(value).append("'");
    159.
    160. String querySql=sb.toString();
    161. "查询的sql语句为:"+querySql);
    162.
    163. null;
    164. try{
    165. //得到一个数据库连接
    166. //预编译语句
    167. //执行查询
    168. //得到对象的所有的方法
    169. Method ms[]=c.getMethods();
    170.
    171. if(rs.next()){
    172. //生成一个实例
    173. obj=c.newInstance();
    174.
    175. for(Method m:ms){
    176. String mName=m.getName();
    177. if(mName.startsWith("set")){
    178. //根据方法名字自动提取表中对应的列名
    179. 3, mName.length());
    180. //打印set的方法名
    181. // System.out.println(cname);
    182. //得到方法的参数类型
    183. Class[] params=m.getParameterTypes();
    184. // for(Class cp : params){
    185. // System.out.println(cp.toString());
    186. // }
    187. //如果参数是String类型,则从结果集中,按照列名取到的值,进行set
    188. //从params[0]的第一个值,能得到该数的参数类型
    189. if(params[0]==String.class){//
    190. m.invoke(obj, rs.getString(cname));
    191. //如果判断出来是int形,则使用int
    192. else if(params[0]==int.class){
    193. m.invoke(obj, rs.getInt(cname));
    194. }
    195. }
    196. }
    197.
    198.
    199.
    200. else{
    201. "请注意:"+columnName+"="+value+"的条件,没有查询到数据!!");
    202. }
    203. rs.close();
    204. ps.close();
    205. con.close();
    206. catch(Exception e){
    207. e.printStackTrace();
    208. }
    209.
    210.
    211.
    212. return
    213. }
    214.
    215.
    216.
    217.
    218. public static void main(String[] args) throws
    219. //====================添加======================
    220. new Dog(21, "小不点", "藏獒", "灰色", 25);
    221. new Person(6, "大象hadoop", 10, "家住Apache基金组织");
    222. //createSqlByObject(d);
    223. //addOne(d);给dog表添加一条数据
    224. //addOne(p);//给person表添加一条数据
    225.
    226. //=======================查询=======================
    227. //强制转换为原始类
    228. // Dog d1=(Dog)getOneObject("com.qin.model.Dog", "id", "1");
    229. // System.out.println(d1);
    230.
    231. "com.qin.model.Person", "id", "1");
    232. //Person d1=(Person)getOneObject("com.qin.model.Person", "name", "王婷");
    233. System.out.println(d1);
    234.
    235.
    236. }
    237.
    238.
    239.
    240. }



    代码量是非常的少的,而且具有通用型,如果再有10个这个实体类,我们代码根本不用任何改动,只需要传入不同的实体类名字即可,当然这一点和Hibernate的自动化ORM非常接近了,在Hibnerate里,可以自动通过表生成类,也可以通过类生成数据库的表,原理其实就是利用了反射的特性,帮我们做了大量的重复工作,当然Hibnerate提供了更多的特性,也这只是一个简单的例子,具体的应用场景中,我们也需要因地制宜,否则,则为适得其反! 

    最后,大家来一起喊一句: 
    JAVA ,我爱你 !

    举报

    相关推荐

    0 条评论