使用JAVA反射的利与弊

news/2024/5/19 4:21:16 标签: 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代码   收藏代码
  1. package com.qin.model;  
  2.   
  3. public class Dog {  
  4.       
  5.     private int id;  
  6.     private String name;  
  7.     private String type;  
  8.     private String color;  
  9.     private int weight;  
  10.     public int getId() {  
  11.         return id;  
  12.     }  
  13.     public void setId(int id) {  
  14.         this.id = id;  
  15.     }  
  16.     public String getName() {  
  17.         return name;  
  18.     }  
  19.     public void setName(String name) {  
  20.         this.name = name;  
  21.     }  
  22.     public String getType() {  
  23.         return type;  
  24.     }  
  25.     public void setType(String type) {  
  26.         this.type = type;  
  27.     }  
  28.     public String getColor() {  
  29.         return color;  
  30.     }  
  31.     public void setColor(String color) {  
  32.         this.color = color;  
  33.     }  
  34.     public int getWeight() {  
  35.         return weight;  
  36.     }  
  37.     public void setWeight(int weight) {  
  38.         this.weight = weight;  
  39.     }  
  40.  public Dog() {  
  41.     // TODO Auto-generated constructor stub  
  42. }  
  43. public Dog(int id, String name, String type, String color, int weight) {  
  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 String toString() {  
  53.     return "Dog [id=" + id + ", name=" + name + ", type=" + type + ", color="  
  54.             + color + ", weight=" + weight + "]";  
  55. }  
  56.   
  57.   
  58.    
  59.       
  60. }  


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




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



Java代码   收藏代码
  1. package com.qin.commons;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.Method;  
  5. import java.sql.Connection;  
  6. import java.sql.PreparedStatement;  
  7. import java.sql.ResultSet;  
  8. import java.util.ArrayList;  
  9. import java.util.List;  
  10.   
  11. import com.qin.db.ConnectionFactory;  
  12. import com.qin.model.Dog;  
  13. import com.qin.model.Person;  
  14. /*** 
  15.  * 反射自动查询和封装的类 
  16.  *@author qindongliang  
  17.  *  
  18.  * */  
  19. public class CommonSupport {  
  20.       
  21.       
  22.     /** 
  23.      * @param obj需要保存的对象 
  24.      * @param string 保存对象的sql语句 
  25.      * */  
  26.     public static String createSqlByObject(Object obj){  
  27.           
  28.          StringBuffer sb=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.         System.out.println("类名字: "+cname);  
  40.         //表名字  
  41.         String tableName=cname.split("\\.")[cname.split("\\.").length-1];  
  42.         System.out.println("表名字: "+tableName);  
  43.         //追加表名和(左边的符号  
  44.         sb.append(tableName).append(" (");  
  45.         //存放列名的集合  
  46.         List<String> columns=new ArrayList<String>();  
  47.         //存放值的集合  
  48.         List values=new ArrayList();  
  49.         //遍历方法  
  50.         for(Method m:ms){  
  51.              String methodName=m.getName();//获取每一个方法名  
  52.              //只得到具有get方法的属性,getClass除外  
  53.              if(methodName.startsWith("get")&&!methodName.startsWith("getClass")){  
  54.                  //System.out.println("属性名:"+methodName);  
  55.                  String fieldName = methodName.substring(3, methodName.length());  
  56. //               System.out.println("字段名:"+fieldName);  
  57.                  columns.add(fieldName);//将列名添加到列名的集合里  
  58.                  try{  
  59.                      Object value=m.invoke(obj, null);  
  60.                      //System.out.println("执行方法返回的值:"+value);  
  61.                      if(value instanceof String){  
  62. //                       System.out.println("字符串类型字段值:"+value);  
  63.                          values.add("'"+value+"'");//加上两个单引号,代表是字符串类型的  
  64.                      }else{  
  65. //                       System.out.println("数值类型字段值:"+value);  
  66.                          values.add(value);//数值类型的则直接添加  
  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.             System.out.println("列名:"+column+" 值:  "+value);  
  82.         }  
  83.           
  84.         //拼接列名  
  85.         for(int i=0;i<columns.size();i++){  
  86.              if(i==columns.size()-1){  
  87.                  sb.append(columns.get(i)).append(" ) ");  
  88.              }else{  
  89.                  sb.append(columns.get(i)).append(" , ");  
  90.              }  
  91.         }  
  92.         System.out.println(" 拼接列名后的sql:"+sb.toString());  
  93.         sb.append(" values ( ");  
  94.         //拼接值  
  95.         for(int i=0;i<values.size();i++){  
  96.              if(i==values.size()-1){  
  97.                  sb.append(values.get(i)).append(" ) ");  
  98.              }else{  
  99.                  sb.append(values.get(i)).append(" , ");  
  100.              }  
  101.         }  
  102.       
  103.         System.out.println(" 拼接值后的sql:"+sb.toString());  
  104.     
  105.         //返回组装的sql语句  
  106.         return sb.toString();  
  107.     }  
  108.       
  109.     /** 
  110.      * 将对象保存在数据库中 
  111.      * @param obj 保存的对象 
  112.      * **/  
  113.     public static void addOne(Object obj){  
  114.         try {  
  115.             Connection con=ConnectionFactory.getCon();  
  116.             String sql=createSqlByObject(obj);  
  117.             PreparedStatement ps=con.prepareStatement(sql);  
  118.             int result=ps.executeUpdate();  
  119.             if(result==1){  
  120.                 System.out.println("保存成功!");  
  121.             }else{  
  122.                 System.out.println("保存失败!");  
  123.             }  
  124.             ps.close();  
  125.             con.close();  
  126.         } catch (Exception e) {  
  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 Object getOneObject(String className,String columnName,String value){  
  142.           
  143.         String tableName=className.split("\\.")[className.split("\\.").length-1];  
  144.         System.out.println("表名字: "+tableName);  
  145.           
  146.         //根据类名来创建对象  
  147.         Class c=null;  
  148.         try{  
  149.             c=Class.forName(className);//反射生成一个类实例  
  150.         }catch(Exception e){  
  151.             e.printStackTrace();  
  152.         }  
  153.         //拼接sql语句  
  154.         StringBuffer sb=new StringBuffer();  
  155.         sb.append("select * from ")  
  156.         .append(tableName)  
  157.         .append(" where ")  
  158.         .append(columnName).append(" = ").append("'").append(value).append("'");  
  159.           
  160.         String querySql=sb.toString();  
  161.         System.out.println("查询的sql语句为:"+querySql);  
  162.           
  163.         Object obj=null;  
  164.         try{  
  165.         Connection con=ConnectionFactory.getCon();//得到一个数据库连接  
  166.         PreparedStatement ps=con.prepareStatement(querySql);//预编译语句  
  167.         ResultSet rs=ps.executeQuery();//执行查询  
  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.                       String cname = mName.substring(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.             System.out.println("请注意:"+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 obj;  
  213.     }  
  214.       
  215.       
  216.       
  217.       
  218.     public static void main(String[] args) throws Exception{  
  219.         //====================添加======================  
  220.         Dog d=new Dog(21"小不点""藏獒""灰色"25);  
  221.         Person p=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.         Person d1=(Person)getOneObject("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 ,我爱你 ! 

http://www.niftyadmin.cn/n/789098.html

相关文章

Flash cross-domain policy

QQ 1285575001 Wechat M010527 技术交流 QQ群599020441 纪年科技aming crossdomain.xml文件 flash在跨域时唯一的限制策略 限制了flash是否可以跨域读写数据以及允许从什么地方跨域读写数据 配置方法及不同配置对flash跨域的影响 域中的SWF文件 检查服务器目录下是否有cros…

leetcode_25 Merge k sorted linked lists

题目&#xff1a; Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. Example: Input: [1->4->5,1->3->4,2->6 ] Output: 1->1->2->3->4->4->5->6方法一&#xff1a;逐个比较&…

《JavaScript权威指南》学习笔记 第五天 window对象的方法。

前天和昨天大致浏览了犀牛书的函数、类与模块、正则表达式、JavaScript扩展、以及服务端的js。这些方面对于我目前的水平来说比较难&#xff0c;一些最基本的概念都不能领会。不过最复杂的知识占用平时使用的20%&#xff0c;而最简单的知识却占平时使用的80%。本着先学会使用&a…

java基础——Tomcat安装

QQ 1285575001 Wechat M010527 技术交流 QQ群599020441 纪年科技aming WEB服务器 ----> 应用逻辑 底层网络处理 ----- HTTP协议报文格式编码解码 管理具体web请求处理线程 web 应用服务器 软件—— Tomcat 依赖JAVA 虚拟机 JVM 类unix FreeBSD下载 编译好的 二进制包 环…

linux的vim按了ctrl+s之后假死的解决办法

习惯了很多软件的保存的快捷键,经常在vim中按下ctrls,然后就发现vim不响应了,之间一直采用kill的方式解决,近来搜了一下,是这样子的: 这时的vim并没有死掉,只是vim不再向终端输出东西了,按 ctrlq 即可恢复正常,试了一下,果然有效. 其实 ctrls 作用的不是 vim , 而是终端 , 也就…

Nginx解析安全实战

QQ 1285575001 Wechat M010527 技术交流 QQ群599020441 纪年科技aming 预备知识 NginxPHP/FastCGI构建的WEB服务器工作原理 Nginx|FastCGI简介 Nginx (“engine x”) 是一个高性能的 HTTP和反向代理服务器&#xff0c; Nginx作为WEB服务器可以处理静态文件&#xff0c; 索引…

leetcode_26 Ugly Number II

题目&#xff1a;丑数2 Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. Example: Input: n 10 Output: 12 Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10…

C++——QQ登录群发实现

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技aming 网络安全 ,深度学习,嵌入式,机器强化,生物智能,生命科学。 叮叮叮&#xff1a;产品已上线 —>关注 …