`

(转)使用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反射使用及相关知识点的详细阐述: 1. **获取Class对象** - `Class.forName(String className)`: 通过全限定类名获取Class对象。 - `object.getClass()`: 对象的`getClass()`方法返回该对象的Class...

    利用java反射将json字符串转成对象.zip

    在给定的“利用java反射将json字符串转成对象”的主题中,我们将深入探讨如何借助反射机制将JSON字符串转换为Java对象。 首先,我们需要了解JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人...

    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反射函数机制实现List转换Json

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

    java反射机制.zip

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

    java反射实现Object转json

    对于"java反射实现Object转json"这个主题,我们将深入探讨如何使用反射机制将Java对象转换为JSON格式的数据。 首先,理解JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也...

    Java反射 JavaBean对象自动生成插入,更新,删除,查询sql语句操作.docx

    在Java反射JavaBean对象自动生成插入、更新、删除、查询sql语句操作中,主要使用了Java反射机制来获取JavaBean对象的信息,然后根据这些信息生成对应的sql语句。例如,通过Java反射机制可以获取JavaBean对象的成员...

    北大青鸟java反射机制

    Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。在"北大青鸟java反射机制"的学习资料中,我们将会深入探讨这一核心特性。 首先,我们要理解反射的核心概念...

    Java反射简单例子

    下面我们将详细探讨Java反射的基本概念、使用场景以及如何通过`ReflectTest.java`这个简单的例子来理解反射。 ### 1. 反射的基本概念 反射机制允许我们在运行时检查类的信息,包括类名、方法名、参数类型等,并且...

    java反射机制源码

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

    实战java反射机制-让你迅速认识java强大的反射机制

    Java反射机制是Java编程语言中的一个强大特性...在"ReflectTest.java"这个文件中,可能包含的是一个实际的Java程序,演示了上述反射机制的一些使用案例。通过阅读和理解这个程序,你可以更好地掌握Java反射的实战应用。

    java反射技术ppt

    `dyn_proxy--AOP动态代理实现方式.ppt`很可能包含关于如何使用Java反射来创建动态代理的详细步骤和示例。而`TestProxy`可能是一个测试类,用于演示如何使用这些动态代理进行实际编程。 总的来说,Java反射技术提供...

    Java反射机制笔记(简单易懂)

    在Java中,我们可以使用反射机制来获取类的属性信息。我们可以使用getDeclaredField()方法来获取类的所有公共属性,或者使用getDeclaredFields()方法来获取类的所有属性,包括公共和私有属性。 例如: ```java ...

    Java 反射调用设置值

    Java 反射调用设置值

    java反射效率

    Java反射在编程中是一种强大的工具,它...开发者应权衡灵活性与性能,根据具体应用场景谨慎使用反射。在大多数情况下,优先考虑非反射设计,只有在必要的时候才引入反射技术,同时采取优化措施,以保持程序的高效运行。

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

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

    通过java反射实现map与bean之间互转

    在给定的标题“通过java反射实现map与bean之间互转”中,我们要探讨的是如何利用Java反射机制将Map对象转换为Java Bean对象,以及反过来,将Java Bean对象转换为Map对象。这个过程在数据处理和序列化中非常常见。 ...

Global site tag (gtag.js) - Google Analytics