• Java读书笔记(7)-深入学习Java Reflection


    转自:http://my.oschina.net/u/1027043/blog/402458

    参考链接:

    1. 官方API解释以及实例:http://docs.oracle.com/javase/tutorial/reflect/index.html
    2. 使用Java的利弊:http://my.oschina.net/u/1027043/blog/402458

    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提供了更多的特性,也这只是一个简单的例子,具体的应用场景中,我们也需要因地制宜,否则,则为适 得其反!

  • 相关阅读:
    windows服务安装命令
    vue开发
    Quorum(NRW)算法机制简介
    SideCar模式
    Python抓取数据的几种方式
    Ms SqlServer索引的选择
    cmd添加环境变量
    好用工具网站
    Aufofac生命周期
    EF初次加载优化
  • 原文地址:https://www.cnblogs.com/hust_wsh/p/5121537.html
Copyright © 2020-2023  润新知