使用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代碼 mysql

  1. package com.qin.model;
  2. public class Dog {  
  3.       
  4.     private int id;  
  5.     private String name;  
  6.     private String type;  
  7.     private String color;  
  8.     private int weight;  
  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 String getType() {  
  22.         return type;  
  23.     }  
  24.     public void setType(String type) {  
  25.         this.type = type;  
  26.     }  
  27.     public String getColor() {  
  28.         return color;  
  29.     }  
  30.     public void setColor(String color) {  
  31.         this.color = color;  
  32.     }  
  33.     public int getWeight() {  
  34.         return weight;  
  35.     }  
  36.     public void setWeight(int weight) {  
  37.         this.weight = weight;  
  38.     }  
  39.  public Dog() {  
  40.     // TODO Auto-generated constructor stub  
  41. }  
  42. public Dog(int id, String name, String type, String color, int weight) {  
  43.     super();  
  44.     this.id = id;  
  45.     this.name = name;  
  46.     this.type = type;  
  47.     this.color = color;  
  48.     this.weight = weight;  
  49. }  
  50. @Override  
  51. public String toString() {  
  52.     return "Dog [id=" + id + ", name=" + name + ", type=" + type + ", color="  
  53.             + color + ", weight=" + weight + "]";  
  54. }  
  55.   
  56.   
  57.    
  58.       
  59. }  

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代碼  sql

  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.     public static void main(String[] args) throws Exception{  
  216.         //====================添加======================  
  217.         Dog d=new Dog(21"小不點""藏獒""灰色"25);  
  218.         Person p=new Person(6"大象hadoop"10"家住Apache基金組織");  
  219.          //createSqlByObject(d);  
  220.         //addOne(d);給dog表添加一條數據  
  221.         //addOne(p);//給person表添加一條數據  
  222.           
  223.         //=======================查詢=======================  
  224.         //強制轉換爲原始類  
  225. //    Dog d1=(Dog)getOneObject("com.qin.model.Dog", "id", "1");  
  226. //    System.out.println(d1);  
  227.           
  228.         Person d1=(Person)getOneObject("com.qin.model.Person""id""1");  
  229.         //Person d1=(Person)getOneObject("com.qin.model.Person", "name", "王婷");  
  230.         System.out.println(d1);  
  231.              
  232.     }  
  233.         
  234. }  

代碼量是很是的少的,並且具備通用型,若是再有10個這個實體類,咱們代碼根本不用任何改動,只須要傳入不一樣的實體類名字便可,固然這一點和Hibernate的自動化ORM很是接近了,在Hibnerate裏,能夠自動經過表生成類,也能夠經過類生成數據庫的表,原理其實就是利用了反射的特性,幫咱們作了大量的重複工做,固然Hibnerate提供了更多的特性,也這只是一個簡單的例子,具體的應用場景中,咱們也須要因地制宜,不然,則爲拔苗助長! 編程

相關文章
相關標籤/搜索