`

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

    博客分类:
  • 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 ,我爱你 !

分享到:
评论

相关推荐

    JAVA反射机制的入门代码

    Java反射机制是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法...

    Java反射性能测试分析

    ### Java反射性能测试分析 #### 引言 Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地访问、检测和修改类、接口、字段和方法等对象。然而,反射操作通常会引入额外的开销,这在性能敏感的...

    Java反射函数机制实现List转换Json

    Java反射机制是Java语言提供的一种强大功能,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括获取类的信息、创建对象、调用方法以及访问和...

    Java反射经典实例

    Java反射是Java编程语言中的一个强大特性,它允许运行时的程序访问并操作类、接口、字段和方法等信息,即使这些信息在编译时并未明确知晓。在Java中,反射通常通过`java.lang.Class`类和相关的API来实现。本实例将...

    java反射机制.zip

    java反射机制java反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制...

    反射实例-JAVA反射机制

    虽然Java反射提供了强大的功能,但在使用时也需要注意其潜在的问题: - **优点**: - **灵活性**:能够动态地加载和操作类。 - **扩展性**:方便扩展程序的功能。 - **可维护性**:降低了程序间的耦合度,提高了...

    java反射机制应用

    ### Java反射机制应用详解 #### 一、Java反射机制简介 Java反射机制是Java语言提供的一种能在运行时分析类信息并动态操作对象的功能。通过反射,我们可以在程序运行期间获取类的信息(如类名、方法名等),创建...

    java 反射机制例子

    下面通过一个具体的示例来展示如何使用Java反射来获取类的详细信息: ```java import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.for...

    Java反射机制的使用和学习方法

    综上所述,Java反射机制提供了强大的动态编程能力,但使用时需权衡其带来的性能损失和潜在的安全风险。通过深入学习和实践,开发者可以更好地掌握这一机制,为解决问题和开发复杂系统提供强有力的支持。

    java反射机制文档及代码

    Java反射机制是Java编程语言中一个强大的特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用方法以及...

    Java反射案例

    这个案例将深入探讨如何使用Java反射来实现一些实用的功能。 1. **获取类信息**: 反射机制首先从Class对象开始,它是所有Java类的元数据。通过`Class.forName()`方法或`类名.class`可以获取到Class对象。一旦有了...

    java反射机制源码

    java反射机制源码java反射机制源码java反射机制源码

    java反射调用实例代码

    - 实现序列化与反序列化:`ObjectInputStream`和`ObjectOutputStream`可以通过`readObject()`和`writeObject()`方法使用反射进行序列化操作。 反射在很多场景下都非常有用,比如在插件系统、框架开发、测试工具、...

    java反射与EJBjava反射与EJBjava反射与EJBjava反射与EJBjava反射与EJB

    总的来说,Java反射和EJB都是Java编程中的高级特性,它们为开发带来了便利,但同时也需要谨慎使用,因为不当的使用可能导致性能下降、安全性风险增加等问题。理解和熟练掌握这两个概念,对于提升Java开发水平和解决...

    java反射机制PPT

    在使用反射时,需要注意性能问题,因为反射操作比直接的Java代码执行要慢。此外,由于反射可以访问私有成员和调用非公开的方法,如果不加以控制,可能会破坏封装性,增加代码的复杂性和潜在的安全风险。 代理模式是...

    Java反射动态加载实例类

    ### Java反射机制与动态加载实例类 在Java中,反射是一种强大的工具,允许程序在运行时检查和修改其结构和行为。通过反射,我们可以动态地加载类、创建对象、访问和修改字段、调用方法等。本文将深入探讨Java反射...

    Java反射机制的详细讲解及实例,有助于java深度开发

    下面将详细阐述Java反射机制的基本概念、应用场景以及如何使用。 一、反射机制基本概念 1. 类加载:Java程序在运行时,JVM会将.class文件加载到内存中,形成类的Class对象,这个过程称为类加载。 2. 类的Class对象...

    Java反射技术的一般应用

    在向学生讲解Class.forName()方法的使用时,有时需要扩展讲解为什么这样书写的原理,于是,扩展讲解Java反射技术可以查看被监视类的方法(构造方法和普通方法)、公有属性的功能,以达到封闭功能的效果。该例子使用...

    Java 反射创建get set方法及反射方法的调用

    本文介绍了如何使用Java反射机制来创建get和set方法,并通过反射调用这些方法来访问对象的属性。这种方式虽然灵活,但在实际开发中应当谨慎使用,因为它可能会降低代码的性能和可维护性。了解反射机制的基本原理对于...

    java反射给指定字段赋值

    - 构造器信息获取与使用。 #### 代码解析 根据提供的部分代码片段: ```java A a = new A(); Field field = a.getClass().getDeclaredField("x"); field.setAccessible(true); field.set(a, 1); Field f = a....

Global site tag (gtag.js) - Google Analytics