本文主要介绍如何通过Java反射机制设计通用Dao,针对中间使用到的方法进行介绍,不对反射做全面的介绍。
测试方法大家可以直接拷贝去试一下,特地写成比较通用的,注意参数就好了,当然最后还是会附上完整的测试代码。

为什么写这个?其实没任何意义,因为Hibernate、Mybatis全部帮我们做了,这是一个“重复造轮子”的过程。

先写一个普通类:

  1. //请将get、set方法补齐
  2. class Person {
  3. private String name;
  4. private int age;

通过Java成员变量拼接SQL语句

获取类名和全部字段所需的方法

getSimpleName()和getDeclaredFields()方法,获取类名和全部字段,先测试一下这两个方法:

  1. /**
  2. * 获取一个类所有字段的名称、类型、值
  3. *
  4. * @param object
  5. * @throws IllegalArgumentException
  6. * @throws IllegalAccessException
  7. */
  8. public static void testFields(Object object) throws IllegalArgumentException, IllegalAccessException {
  9. Class<?> clazz = object.getClass();
  10. // 获取类名
  11. System.out.println(clazz.getSimpleName());
  12. // 获取所有字段
  13. Field[] fields = clazz.getDeclaredFields();
  14. // 获取字段的信息
  15. for (Field field : fields) {
  16. System.out.println("++++++++++++++++++++++++");
  17. System.out.println("name:" + field.getName());
  18. System.out.println("type:" + field.getType());
  19. field.setAccessible(true);
  20. System.out.println("value:" + field.get(object).toString());
  21. }
  22. }

控制台打印结果:

Person
++++++++++++++++++++++++
name:name
type:class java.lang.String
value:小明
++++++++++++++++++++++++
name:age
type:int
value:30

结果分析:
由上面结果,我们可以想象,假设有一张Person表,然后Person表有name和age字段,然后有一条记录,name=”小明”,age=”30”,这样就基本跟Java类对应了。
也就是说:我们有这样一个Person类,然后我们的数据库有一个Person表,我们想把Person类中的属性存储到数据库中的时候,想要获取表名,只要只要getSimpleName()就好了;要获取字段值通过getDeclaredFields()也能做到,然后只要想办法把这些东西拼成SQL语句就好了。

SQL语句拼接思路

我们写Sql语句应该是这样:
INSERT INTO PERSON (name,age) VALUES (小明,30);
通过Java反射就可以这样拼出一条Sql语句:

  1. "INSERT INTO "+
  2. clazz.getSimpleName()+
  3. " (`name`,`age`) VALUES (`"+
  4. fields[0].getName()+
  5. "`,`"+
  6. fields[1].getName()+
  7. "`)";

从Javabean拼接出Insert语句

  1. //代码具体实现
  2. public static void createSql(Object object) throws Exception {
  3. Class<?> clazz = object.getClass();
  4. StringBuilder sb=new StringBuilder(120);
  5. sb.append("INSERT INTO ");
  6. // 获取类名
  7. sb.append(clazz.getSimpleName());
  8. // 获取全部字段
  9. Field[] fields = clazz.getDeclaredFields();
  10. sb.append(" (");
  11. for (Field field : fields) {
  12. sb.append("`");
  13. //获取字段名
  14. sb.append(field.getName());
  15. sb.append("`,");
  16. }
  17. sb.replace(sb.length()-1, sb.length(),") VALUES (");
  18. for (Field field : fields) {
  19. field.setAccessible(true);
  20. sb.append("`");
  21. //获取字段值
  22. sb.append(field.get(object).toString());
  23. sb.append("`,");
  24. }
  25. sb.replace(sb.length()-1, sb.length(), ")");
  26. System.out.println(sb.toString());
  27. }

控制台打印结果

  1. INSERT INTO Person (`name`,`age`) VALUES (`小明`,`30`)

看着似乎很不错,基本可以满足我们的需求了,把增删改查都写一下基本能满足需求了。

Select查询结果封装Javabean

可能还有个疑问,那查找数据怎么存到Java属性中?只要调用:field.set(object, value)就好了,第一个参数Object类型,你要把数据存储到哪一个Java对象,就传那一个对象,第二个是就是查找到的具体数值了。
假设数据库查询结果是:new Object[] { “小东”, 50 },然后把它转成对象。

  1. Object[] objects = new Object[] { "小东", 50 };
  2. Person per = (Person) usingFields(person.getClass(), objects);
  3. System.out.println(per.getAge());
  4. System.out.println(per.getName());
  1. /**
  2. * 字段值注入的方式
  3. *
  4. * @param clazz
  5. * @param params
  6. * @return
  7. * @throws Exception
  8. */
  9. public static Object usingFields(Class<?> clazz, Object params[]) throws Exception {
  10. Object object = clazz.newInstance();
  11. Field[] fields = clazz.getDeclaredFields();
  12. for (int i = 0; i < fields.length; i++) {
  13. fields[i].setAccessible(true);
  14. fields[i].set(object, params[i]);
  15. }
  16. return object;
  17. }

控制台打印结果

50
小东

通过Set、Get方法获取、注入属性值

通过Java字段拼接SQL语句,这是一个很好的思路,但是难免会有一些奇奇怪怪的需求,比如说我们的Javabean有个序列化ID,这时候getDeclaredFields()也会获取到序列化ID,而数据库肯定不会有这些字段的。

这时候可以考虑通过Set()和Get()方法,因为有这两个方法,肯定是希望其他人去调用这些方法,就比如JSP用到的EL表达式,他就是通过Get()方法查找的。

获取Javabean全部方法

getDeclaredMethods()和getMethods()
getDeclaredMethods()获取的是类自身声明的所有方法,包含public、protected和private方法;
getMethods()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。

  1. /**
  2. * 获取全部方法
  3. *
  4. * @param clazz
  5. */
  6. public static void testMethod(Class<?> clazz) {
  7. // 获取参数
  8. Method[] fields = clazz.getMethods();
  9. for (Method method : fields) {
  10. System.out.println("===================================");
  11. // 方法名
  12. System.out.println(method.getName());
  13. // 返回值类型
  14. System.out.println(method.getReturnType());
  15. // 获取方法所在类的
  16. System.out.println(method.getDeclaringClass());
  17. System.out.println("===================================");
  18. }
  19. }

控制台打印结果

getName
class java.lang.String
class com.Person

setName
void
class com.Person

getAge
int
class com.Person

setAge
void
class com.Person

………………

由于编辑器不支持使用“====”这里就删除掉了,类的方法即使一个不写也是非常多的,这里仅作局部展示,只知道我们确实可以通过这种方式找到我们需要的方法,剩下的就是再明确定位到我们所需的就好了。

准确超找Get和Set方法

  1. Field[] fields=person.getClass().getDeclaredFields();
  2. for (Field field : fields) {
  3. findGetMethodByField(field, person.getClass());
  4. findSetMethodByField(field, person.getClass());
  5. }
  1. /**
  2. * 查找所有Get方法
  3. *
  4. * @param field
  5. * @param clazz
  6. * @return
  7. * @throws Exception
  8. */
  9. public static Method findGetMethodByField(Field field, Class<?> clazz) throws Exception {
  10. String fieldName = field.getName();
  11. // get方法名
  12. String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
  13. System.out.println(methodName);
  14. Method[] methods = clazz.getDeclaredMethods();
  15. for (Method method : methods) {
  16. if (methodName.equals(method.getName())) {
  17. return method;
  18. }
  19. }
  20. return null;
  21. }
  22. /**
  23. * 查找所有Set方法
  24. *
  25. * @param field
  26. * @param clazz
  27. * @return
  28. * @throws Exception
  29. */
  30. public static Method findSetMethodByField(Field field, Class<?> clazz) throws Exception {
  31. String fieldName = field.getName();
  32. // get方法名
  33. String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
  34. System.out.println(methodName);
  35. Method[] methods = clazz.getDeclaredMethods();
  36. for (Method method : methods) {
  37. if (methodName.equals(method.getName())) {
  38. return method;
  39. }
  40. }
  41. return null;
  42. }

结果如下:
getName
setName
getAge
setAge

很好,这样基本就能找到了,找不到会返回null,判断一下就好。

通过Get方法获取返回值

先假设我们方法的返回值类型是”java.lang.String”,我们就可以使用Class.forName()创建一个这样的对象,然后直接调用Get方法即可,这里假设调用Get结果是str。

  1. /**
  2. * 获取返回值
  3. *
  4. * @throws ClassNotFoundException
  5. */
  6. public static void testReturnType() throws ClassNotFoundException {
  7. // method.getReturnType()
  8. String str = "假设某个方法返回这个字符串";
  9. Object object = Class.forName("java.lang.String");
  10. object = str;
  11. System.out.println(object);
  12. }

结果控制台就输出:

  1. 假设某个方法返回这个字符串

使用method.getReturnType()获取返回值,这个实际上返回的是:class java.lang.String,所以要SubString一下,删除不必要的字符串,然后使用method.invoke(obj)调用方法,这个方法的参数为Object,指明要调用的是哪一类的这个方法。

  1. Field[] fields = person.getClass().getDeclaredFields();
  2. for (Field field : fields) {
  3. System.out.println(usingReturnType(field, person).toString());
  4. }
  1. /**
  2. * 获取返回值
  3. *
  4. * @param field
  5. * 属性
  6. * @param obj
  7. * 对象
  8. * @return
  9. * @throws Exception
  10. */
  11. public static Object usingReturnType(Field field, Object obj) throws Exception {
  12. Method method = findGetMethodByField(field, obj.getClass());
  13. String returntype = method.getReturnType().getClass().toString();
  14. Object object = Class.forName(returntype.substring(6));
  15. object = method.invoke(obj);
  16. return object;
  17. }

控制台打印结果:
·
getName
小明
getAge
30

通过Set方法为Javabean设值

method.invoke(object, params[i])
第一个参数使我们要设值的对象,第二个参数是Object类型的集合,封装了method方法的参数值。

下面的简单地调用method.invoke(object, params[i])方法,param是我们要传的参数,假设数据库查询结果是:new Object[] { “小东”, 50 },然后把它转成对象。

  1. Object[] objects = new Object[] { "小东", 50 };
  2. Person per = (Person) usingMethods(person.getClass(), objects);
  3. System.out.println(per.getAge());
  4. System.out.println(per.getName());
  1. /**
  2. * Set方式注入
  3. *
  4. * @param clazz
  5. * @param params
  6. * @return
  7. * @throws Exception
  8. */
  9. public static Object usingMethods(Class<?> clazz, Object params[]) throws Exception {
  10. Object object = clazz.newInstance();
  11. Field[] fields = clazz.getDeclaredFields();
  12. for (int i = 0; i < fields.length; i++) {
  13. Method method = findSetMethodByField(fields[i], clazz);
  14. method.invoke(object, params[i]);
  15. }

控制台打印结果:

setName
setAge
50
小东

到这里,我们已经讲了Sql语句的拼接,还有数据库返回结果的处理,基本可以应付一些简单的增删改查,至于复杂的查询,还要做进一步的研究。

扩展:

其实还可以通过注解来设计Dao,为Javabean设置类注解,注解指明数据库对应的表名,然后为每个属性设置字段注解,注解指明数据库中对应的字段名,然后通过注解拼接Sql语句

源码:

  1. import java.lang.reflect.Field;
  2. import java.lang.reflect.Method;
  3. class Person {
  4. private String name;
  5. private int age;
  6. public Person() {
  7. }
  8. public Person(String name, int age) {
  9. super();
  10. this.name = name;
  11. this.age = age;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public int getAge() {
  20. return age;
  21. }
  22. public void setAge(int age) {
  23. this.age = age;
  24. }
  25. }
  26. public class Test {
  27. public static void main(String[] args) throws Exception {
  28. Person person = new Person("小明", 30);
  29. //获取字段
  30. // testFields(person);
  31. //Sql语句拼接
  32. // createSql(person);
  33. //获取方法
  34. // testMethod(Person.class);
  35. //获取Get和Set方法
  36. // Field[] fields=person.getClass().getDeclaredFields();
  37. // for (Field field : fields) {
  38. // findGetMethodByField(field, person.getClass());
  39. // findSetMethodByField(field, person.getClass());
  40. // }
  41. //测试返回值
  42. // testReturnType();
  43. //使用返回值
  44. // Field[] fields = person.getClass().getDeclaredFields();
  45. // for (Field field : fields) {
  46. // System.out.println(usingReturnType(field, person).toString());
  47. // }
  48. //Set方式注入
  49. Object[] objects = new Object[] { "小东", 50 };
  50. Person per = (Person) usingMethods(person.getClass(), objects);
  51. System.out.println(per.getAge());
  52. System.out.println(per.getName());
  53. //参数入住
  54. // Object[] objects = new Object[] { "小东", 50 };
  55. // Person per = (Person) usingFields(person.getClass(), objects);
  56. // System.out.println(per.getAge());
  57. // System.out.println(per.getName());
  58. }
  59. /**
  60. * 获取一个类所有属性的名称、类型、值
  61. *
  62. * @param object
  63. * @throws IllegalArgumentException
  64. * @throws IllegalAccessException
  65. */
  66. public static void testFields(Object object) throws IllegalArgumentException, IllegalAccessException {
  67. Class<?> clazz = object.getClass();
  68. // 获取类名
  69. System.out.println(clazz.getSimpleName());
  70. // 获取参数
  71. Field[] fields = clazz.getDeclaredFields();
  72. // 获取参数内容和类型
  73. for (Field field : fields) {
  74. System.out.println("++++++++++++++++++++++++");
  75. System.out.println("name:" + field.getName());
  76. System.out.println("type:" + field.getType());
  77. field.setAccessible(true);
  78. System.out.println("value:" + field.get(object).toString());
  79. }
  80. }
  81. public static void createSql(Object object) throws Exception {
  82. Class<?> clazz = object.getClass();
  83. StringBuilder sb = new StringBuilder(120);
  84. sb.append("INSERT INTO ");
  85. // 获取类名
  86. sb.append(clazz.getSimpleName());
  87. // 获取全部属性
  88. Field[] fields = clazz.getDeclaredFields();
  89. sb.append(" (");
  90. for (Field field : fields) {
  91. sb.append("`");
  92. // 获取属性名
  93. sb.append(field.getName());
  94. sb.append("`,");
  95. }
  96. sb.replace(sb.length() - 1, sb.length(), ") VALUES (");
  97. for (Field field : fields) {
  98. field.setAccessible(true);
  99. sb.append("`");
  100. // 获取属性值
  101. sb.append(field.get(object).toString());
  102. sb.append("`,");
  103. }
  104. sb.replace(sb.length() - 1, sb.length(), ")");
  105. System.out.println(sb.toString());
  106. }
  107. /**
  108. * 获取全部方法
  109. *
  110. * @param clazz
  111. */
  112. public static void testMethod(Class<?> clazz) {
  113. // 获取参数
  114. Method[] fields = clazz.getMethods();
  115. for (Method method : fields) {
  116. System.out.println("===================================");
  117. // 方法名
  118. System.out.println(method.getName());
  119. // 返回值类型
  120. System.out.println(method.getReturnType());
  121. // 获取方法所在类的
  122. System.out.println(method.getDeclaringClass());
  123. System.out.println("===================================");
  124. }
  125. }
  126. /**
  127. * 获取返回值
  128. *
  129. * @throws ClassNotFoundException
  130. */
  131. public static void testReturnType() throws ClassNotFoundException {
  132. // method.getReturnType()
  133. String str = "假设某个方法返回这个字符串";
  134. Object object = Class.forName("java.lang.String");
  135. object = str;
  136. System.out.println(object);
  137. }
  138. /**
  139. * 查找所有Get方法
  140. *
  141. * @param field
  142. * @param clazz
  143. * @return
  144. * @throws Exception
  145. */
  146. public static Method findGetMethodByField(Field field, Class<?> clazz) throws Exception {
  147. String fieldName = field.getName();
  148. // get方法名
  149. String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
  150. System.out.println(methodName);
  151. Method[] methods = clazz.getDeclaredMethods();
  152. for (Method method : methods) {
  153. if (methodName.equals(method.getName())) {
  154. return method;
  155. }
  156. }
  157. return null;
  158. }
  159. /**
  160. * 查找所有Set方法
  161. *
  162. * @param field
  163. * @param clazz
  164. * @return
  165. * @throws Exception
  166. */
  167. public static Method findSetMethodByField(Field field, Class<?> clazz) throws Exception {
  168. String fieldName = field.getName();
  169. // get方法名
  170. String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
  171. System.out.println(methodName);
  172. Method[] methods = clazz.getDeclaredMethods();
  173. for (Method method : methods) {
  174. if (methodName.equals(method.getName())) {
  175. return method;
  176. }
  177. }
  178. return null;
  179. }
  180. /**
  181. * 获取返回值
  182. *
  183. * @param field
  184. * 属性
  185. * @param obj
  186. * 对象
  187. * @return
  188. * @throws Exception
  189. */
  190. public static Object usingReturnType(Field field, Object obj) throws Exception {
  191. Method method = findGetMethodByField(field, obj.getClass());
  192. String returntype = method.getReturnType().getClass().toString();
  193. Object object = Class.forName(returntype.substring(6));
  194. object = method.invoke(obj);
  195. return object;
  196. }
  197. /**
  198. * Set方式注入
  199. *
  200. * @param clazz
  201. * @param params
  202. * @return
  203. * @throws Exception
  204. */
  205. public static Object usingMethods(Class<?> clazz, Object params[]) throws Exception {
  206. Object object = clazz.newInstance();
  207. Field[] fields = clazz.getDeclaredFields();
  208. for (int i = 0; i < fields.length; i++) {
  209. Method method = findSetMethodByField(fields[i], clazz);
  210. method.invoke(object, params[i]);
  211. }
  212. return object;
  213. }
  214. /**
  215. * 字段值注入的方式
  216. *
  217. * @param clazz
  218. * @param params
  219. * @return
  220. * @throws Exception
  221. */
  222. public static Object usingFields(Class<?> clazz, Object params[]) throws Exception {
  223. Object object = clazz.newInstance();
  224. Field[] fields = clazz.getDeclaredFields();
  225. for (int i = 0; i < fields.length; i++) {
  226. fields[i].setAccessible(true);
  227. fields[i].set(object, params[i]);
  228. }
  229. return object;
  230. }
  231. }

利用反射机制设计Dao的更多相关文章

  1. 利用JAVA反射机制设计通用的DAO

    利用JAVA反射机制设计一个通用的DAO 反射机制 反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,    那么就可以通过反射机制来获得类的所有信息. 反射机制创建类对象 ...

  2. android 利用反射机制获取drawable中所有的图片资源

    public List<Map<String,Object>> getGridData() { list=new ArrayList<Map<String,Obje ...

  3. 【转】Java利用反射机制访问私有化构造器

    Java利用反射机制访问私有化构造器 博客分类: java   我们都知道,当一个类的构造方法被设为私有的时候(private),在其他类中是无法用new来实例化一个对象的. 但是有一种方法可以把带有 ...

  4. Android利用反射机制为实体类属性赋值

    在做android项目时,有时会遇到从网络上获取json类型数据,赋值给实体类,实体类属性少可以一个一个的赋值,如果实体类有很多属性,赋值可能就要耗很长的功夫了,幸好Java给我们提供了反射机制.下面 ...

  5. java利用反射机制判断对象的属性是否为空以及获取和设置该属性的值

    1.java利用反射机制判断对象的属性是否为空: Map<String,String> validateMap = new LinkedHashMap<String, String& ...

  6. C# 中利用反射机制拷贝类的字段和属性(拷贝一个类对象的所有东西付给另一个类对象,而不是付给引用地址)

    from:https://blog.csdn.net/poxiaohai2011/article/details/27555951 //C# 中利用反射机制拷贝类的字段和属性(拷贝一个类对象的所有东西 ...

  7. java 中利用反射机制获取和设置实体类的属性值

    摘要: 在java编程中,我们经常不知道传入自己方法中的实体类中到底有哪些方法,或者,我们需要根据用户传入的不同的属性来给对象设置不同的属性值,那么,java自带的反射机制可以很方便的达到这种目的,同 ...

  8. Java——利用反射机制将表单数据自动填充到JavaBean中

    以一个案例介绍反射机制的一种常见的使用场景,以及具体实现. 1.本文案例 在编写Java Web应用程序时,使用表单提交数据是一个必不可少的环节,后台对于前台使用表单提交的数据需要能够从请求中解析,并 ...

  9. JAVA中利用反射机制进行对象和Map相互转换的方法

    JAVA的反射机制主要作用是用来访问对象的属性.方法等等.所以,JAVA中对象和Map相互转换可以利用JAVA的反射机制来实现.例子如下: 一.对象转Map的方法 public static Map& ...

随机推荐

  1. JavaWeb之Maven配置

    Maven和C#的nuget类似,可以通过设置就能引入框架等第三方,方便又省事.Java中使用Maven来管理第三方.今天尝试着配置了一下. 一.JDK的安装 关于JDK的安装可以查看百度经验,设置P ...

  2. layim+signalr2.0在线轻聊版解决方案

    本内容有版权限制,仅提供学习交流参考等等,请勿随便转载或者代码商用.     /** layui-v2.1.5 MIT License By http://www.layui.com */; layu ...

  3. UVa11882,Biggest Number

    搜索+剪枝 如此水的一个题,居然搞了一上午 出错在bfs与dfs时共用了一个vis数组,导致bfs完后返回dfs应该能访问到的点访问不到 自己想怎么剪枝,想了几个剪枝方法,又证明,又推翻,再想,再证明 ...

  4. AVL 树

    一棵AVL树是每个节点的左子树和右子树的高度最多差1的二叉查找树 SearchTree Insert(ElementType X, SearchTree T) { if (T == NULL) { T ...

  5. RabbitMQ 笔记-Exchanges

    Procuder Publish的Message进入了Exchange.接着通过"routing keys", RabbitMQ会找到应该把这个Message放到哪个queue里. ...

  6. CentOS 7 校对时间 修改时区

    在 CentOS 7 中, 引入了一个叫 timedatectl 的设置设置程序. 用法很简单: timedatectl # 查看系统时间方面的各种状态 Local time: 四 2014-12-2 ...

  7. ubuntu 常用软件安装

    安装ubuntu远程图形界面 sudo apt-get install xrdp (sudo apt-get install ..  用于安装软件的命令 ) sudo apt-get install ...

  8. HDU1166 敌兵布阵(线段树)

    C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于 ...

  9. Flexbox 布局教程

    Flex 布局是什么? Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为 Flex 布局. 使用 fle ...

  10. [C#]使用Costura.Fody将源DLL合并到目标EXE

    本文为原创文章,如转载,请在网页明显位置标明原文名称.作者及网址,谢谢! 一.本文主要是使用Costura.Fody工具将源DLL合并到目标EXE,因此,需要从以下任一链接下载: ①从Github地址 ...