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

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

先写一个普通类:

    //请将get、set方法补齐
class Person {
private String name;
private int age;

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

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

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

    /**
* 获取一个类所有字段的名称、类型、值
*
* @param object
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static void testFields(Object object) throws IllegalArgumentException, IllegalAccessException {
Class<?> clazz = object.getClass();
// 获取类名
System.out.println(clazz.getSimpleName());
// 获取所有字段
Field[] fields = clazz.getDeclaredFields();
// 获取字段的信息
for (Field field : fields) {
System.out.println("++++++++++++++++++++++++");
System.out.println("name:" + field.getName());
System.out.println("type:" + field.getType());
field.setAccessible(true);
System.out.println("value:" + field.get(object).toString());
}
}

控制台打印结果:

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语句:

"INSERT INTO "+
clazz.getSimpleName()+
" (`name`,`age`) VALUES (`"+
fields[0].getName()+
"`,`"+
fields[1].getName()+
"`)";

从Javabean拼接出Insert语句

    //代码具体实现
public static void createSql(Object object) throws Exception {
Class<?> clazz = object.getClass();
StringBuilder sb=new StringBuilder(120);
sb.append("INSERT INTO ");
// 获取类名
sb.append(clazz.getSimpleName());
// 获取全部字段
Field[] fields = clazz.getDeclaredFields();
sb.append(" (");
for (Field field : fields) {
sb.append("`");
//获取字段名
sb.append(field.getName());
sb.append("`,");
}
sb.replace(sb.length()-1, sb.length(),") VALUES (");
for (Field field : fields) {
field.setAccessible(true);
sb.append("`");
//获取字段值
sb.append(field.get(object).toString());
sb.append("`,");
}
sb.replace(sb.length()-1, sb.length(), ")");
System.out.println(sb.toString());
}

控制台打印结果

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

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

Select查询结果封装Javabean

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

        Object[] objects = new Object[] { "小东", 50 };
Person per = (Person) usingFields(person.getClass(), objects);
System.out.println(per.getAge());
System.out.println(per.getName());
    /**
* 字段值注入的方式
*
* @param clazz
* @param params
* @return
* @throws Exception
*/
public static Object usingFields(Class<?> clazz, Object params[]) throws Exception {
Object object = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
fields[i].set(object, params[i]);
}
return object;
}

控制台打印结果

50
小东

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

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

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

获取Javabean全部方法

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

    /**
* 获取全部方法
*
* @param clazz
*/
public static void testMethod(Class<?> clazz) {
// 获取参数
Method[] fields = clazz.getMethods();
for (Method method : fields) {
System.out.println("===================================");
// 方法名
System.out.println(method.getName());
// 返回值类型
System.out.println(method.getReturnType());
// 获取方法所在类的
System.out.println(method.getDeclaringClass());
System.out.println("===================================");
}
}

控制台打印结果

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方法

        Field[] fields=person.getClass().getDeclaredFields();
for (Field field : fields) {
findGetMethodByField(field, person.getClass());
findSetMethodByField(field, person.getClass());
}
    /**
* 查找所有Get方法
*
* @param field
* @param clazz
* @return
* @throws Exception
*/
public static Method findGetMethodByField(Field field, Class<?> clazz) throws Exception {
String fieldName = field.getName();
// get方法名
String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
System.out.println(methodName);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
return method;
}
}
return null;
} /**
* 查找所有Set方法
*
* @param field
* @param clazz
* @return
* @throws Exception
*/
public static Method findSetMethodByField(Field field, Class<?> clazz) throws Exception {
String fieldName = field.getName();
// get方法名
String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
System.out.println(methodName);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
return method;
}
}
return null;
}

结果如下:
getName
setName
getAge
setAge

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

通过Get方法获取返回值

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

    /**
* 获取返回值
*
* @throws ClassNotFoundException
*/
public static void testReturnType() throws ClassNotFoundException {
// method.getReturnType()
String str = "假设某个方法返回这个字符串";
Object object = Class.forName("java.lang.String");
object = str;
System.out.println(object);
}

结果控制台就输出:

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

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

        Field[] fields = person.getClass().getDeclaredFields();
for (Field field : fields) {
System.out.println(usingReturnType(field, person).toString());
}
    /**
* 获取返回值
*
* @param field
* 属性
* @param obj
* 对象
* @return
* @throws Exception
*/
public static Object usingReturnType(Field field, Object obj) throws Exception {
Method method = findGetMethodByField(field, obj.getClass());
String returntype = method.getReturnType().getClass().toString();
Object object = Class.forName(returntype.substring(6));
object = method.invoke(obj);
return object;
}

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

通过Set方法为Javabean设值

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

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

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

控制台打印结果:

setName
setAge
50
小东

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

扩展:

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

源码:

import java.lang.reflect.Field;
import java.lang.reflect.Method; class Person {
private String name;
private int age; public Person() {
} public Person(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
} public class Test {
public static void main(String[] args) throws Exception {
Person person = new Person("小明", 30); //获取字段
// testFields(person); //Sql语句拼接
// createSql(person); //获取方法
// testMethod(Person.class); //获取Get和Set方法
// Field[] fields=person.getClass().getDeclaredFields();
// for (Field field : fields) {
// findGetMethodByField(field, person.getClass());
// findSetMethodByField(field, person.getClass());
// } //测试返回值
// testReturnType(); //使用返回值
// Field[] fields = person.getClass().getDeclaredFields();
// for (Field field : fields) {
// System.out.println(usingReturnType(field, person).toString());
// } //Set方式注入
Object[] objects = new Object[] { "小东", 50 };
Person per = (Person) usingMethods(person.getClass(), objects);
System.out.println(per.getAge());
System.out.println(per.getName()); //参数入住
// Object[] objects = new Object[] { "小东", 50 };
// Person per = (Person) usingFields(person.getClass(), objects);
// System.out.println(per.getAge());
// System.out.println(per.getName());
} /**
* 获取一个类所有属性的名称、类型、值
*
* @param object
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static void testFields(Object object) throws IllegalArgumentException, IllegalAccessException {
Class<?> clazz = object.getClass();
// 获取类名
System.out.println(clazz.getSimpleName());
// 获取参数
Field[] fields = clazz.getDeclaredFields();
// 获取参数内容和类型
for (Field field : fields) {
System.out.println("++++++++++++++++++++++++");
System.out.println("name:" + field.getName());
System.out.println("type:" + field.getType());
field.setAccessible(true);
System.out.println("value:" + field.get(object).toString());
}
} public static void createSql(Object object) throws Exception {
Class<?> clazz = object.getClass();
StringBuilder sb = new StringBuilder(120);
sb.append("INSERT INTO ");
// 获取类名
sb.append(clazz.getSimpleName());
// 获取全部属性
Field[] fields = clazz.getDeclaredFields();
sb.append(" (");
for (Field field : fields) {
sb.append("`");
// 获取属性名
sb.append(field.getName());
sb.append("`,");
}
sb.replace(sb.length() - 1, sb.length(), ") VALUES (");
for (Field field : fields) {
field.setAccessible(true);
sb.append("`");
// 获取属性值
sb.append(field.get(object).toString());
sb.append("`,");
}
sb.replace(sb.length() - 1, sb.length(), ")");
System.out.println(sb.toString());
} /**
* 获取全部方法
*
* @param clazz
*/
public static void testMethod(Class<?> clazz) {
// 获取参数
Method[] fields = clazz.getMethods();
for (Method method : fields) {
System.out.println("===================================");
// 方法名
System.out.println(method.getName());
// 返回值类型
System.out.println(method.getReturnType());
// 获取方法所在类的
System.out.println(method.getDeclaringClass());
System.out.println("===================================");
}
} /**
* 获取返回值
*
* @throws ClassNotFoundException
*/
public static void testReturnType() throws ClassNotFoundException {
// method.getReturnType()
String str = "假设某个方法返回这个字符串";
Object object = Class.forName("java.lang.String");
object = str;
System.out.println(object);
} /**
* 查找所有Get方法
*
* @param field
* @param clazz
* @return
* @throws Exception
*/
public static Method findGetMethodByField(Field field, Class<?> clazz) throws Exception {
String fieldName = field.getName();
// get方法名
String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
System.out.println(methodName);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
return method;
}
}
return null;
} /**
* 查找所有Set方法
*
* @param field
* @param clazz
* @return
* @throws Exception
*/
public static Method findSetMethodByField(Field field, Class<?> clazz) throws Exception {
String fieldName = field.getName();
// get方法名
String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
System.out.println(methodName);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
return method;
}
}
return null;
} /**
* 获取返回值
*
* @param field
* 属性
* @param obj
* 对象
* @return
* @throws Exception
*/
public static Object usingReturnType(Field field, Object obj) throws Exception {
Method method = findGetMethodByField(field, obj.getClass());
String returntype = method.getReturnType().getClass().toString();
Object object = Class.forName(returntype.substring(6));
object = method.invoke(obj);
return object;
} /**
* Set方式注入
*
* @param clazz
* @param params
* @return
* @throws Exception
*/
public static Object usingMethods(Class<?> clazz, Object params[]) throws Exception {
Object object = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Method method = findSetMethodByField(fields[i], clazz);
method.invoke(object, params[i]);
}
return object;
} /**
* 字段值注入的方式
*
* @param clazz
* @param params
* @return
* @throws Exception
*/
public static Object usingFields(Class<?> clazz, Object params[]) throws Exception {
Object object = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
fields[i].set(object, params[i]);
}
return object;
}
}

利用反射机制设计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. 利用Dropbox同步Arch下一些软件的配置文件

    一些软件后要好好的配置一番才能好好为自己所用,比如vim,比如conky等等,但是万一系统真出了问题,或者硬盘跪了,要重新安装系统重新配置的时候真是一种折磨,前阵子想到如果用dropbox同步那些配置 ...

  2. IO 调优

    磁盘优化 1.增加缓存 2.优化磁盘的管理系统 3.设计合理的磁盘存储数据块 4.应用合理的RAID策略 TCP网络参数调优 网络IO优化 1.减少网络交互次数 2.减少网络传输数据量的大小 3.尽量 ...

  3. React UI 组件库uiw v1.2.8 发布

    uiw 高品质的UI工具包,基于React 16+的组件库.

  4. 正则和grep——再做正则就去死

    grep 文本过滤工具 基本正则表达式 grep 语法 基本正则表达式的元字符 次数匹配 位置锚定 分组 扩展正则表达式 基本正则表达式的元字符 次数匹配 位置锚定 分组 或者 grep的介绍 lin ...

  5. 算法改进 | java语言中判断素数

    参考文章:http://blog.csdn.net/kp_liu/article/details/37569507 http://blog.csdn.net/huang_miao_xin/articl ...

  6. iOS布局

    1.Masonry 创建constraint来定义布局的方式: 1.1. mas_makeConstraints : 你可以使用局部变量后者属性来保存以便下次应用它 1.2. mas_updateCo ...

  7. 数据分析与展示——NumPy库入门

    这是我学习北京理工大学嵩天老师的<Python数据分析与展示>课程的笔记.嵩老师的课程重点突出.层次分明,在这里特别感谢嵩老师的精彩讲解. NumPy库入门 数据的维度 维度是一组数据的组 ...

  8. 压缩感知重构算法之子空间追踪(SP)

    SP的提出时间比CoSaMP提出时间稍晚一些,但和压缩采样匹配追踪(CoSaMP)的方法几乎是一样的.SP与CoSaMP主要区别在于“In each iteration, in the SP algo ...

  9. Android Studio 中修改Apk名称

    修改生成的apk名称,并且使调试时也可以使用. 在app->build.gradle 中增加以下内容: android.applicationVariants.all { variant-> ...

  10. java 随记

    后台开发的过程中积累的关于java的杂记 架构 SSH框架 为什么要分层? 因为分层使代码变得清晰,容易写也容易阅读,更重要的是让代码扩展性更好,层与层之间的改动不会互相影响 各层的分工 dao--与 ...