熟悉JAVA反射后,来偷懒做些事情字符串处理的事情

举个简单的例子吧,假设我们想把一个对象的所有属性值存到数据库里,通常会用到

insert into XXX (field1,field2) values (v001,v002)

像这种语句,格式都一个样,唯一的区别就是XXX表和表的字段与值的不同。但是针对不同的表,总要重复写这条语句,然后一条一条复制粘贴表里的所有字段,再一条一条复制粘贴所有的字段值,要是表多而且字段多的话,是不是看着有点累还容易出错……

所以为什么不写个程序,让它通过传递参数来找到这个类名,以及相应属性和和值然后自动生成这条sql语句呢?如此一来,岂不美哉。

那么我来尝试偷懒一下,直接上代码:

(为了简单,我们在这里假设数据库的字段和我们javabean的字段值一样,数据库表名与我们的javabean类名一样,且没有Boolean类型的成员)

	public static String getSaveSQL(Object javaBean) {
		StringBuilder sb = new StringBuilder(); // 由于需要增加的内容较多,固采用StringBuilder代替String
		Class<?> targetClass = javaBean.getClass(); // 目标类的Class对象
		String className = targetClass.getSimpleName(); // 简单类名
		sb.append("insert into ");
		sb.append(className); // 类名即对应表名
		sb.append(" (");
		Field[] fields = targetClass.getDeclaredFields(); // 获得属性域
		List<String> fieldList = new ArrayList<>(); // 存储属性名的数组
		List<String> methodList = new ArrayList<>(); // 存储方法名的数组
		String fieldName = null;
		String methodName = null;
		for (Field field : fields) { // 遍历属性域,获得对应属性名和方法名
			fieldName = field.getName();
			methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
			fieldList.add(fieldName);
			methodList.add(methodName);
		}
		int i;
		for (i = 0; i < fieldList.size(); i++) { // 构建sql语句中的字段部分
			sb.append(fieldList.get(i));
			if (i != fieldList.size() - 1)
				sb.append(",");
		}
		sb.append(") values (");
		Object to = null;
		Method tm = null;
		try {
			for (i = 0; i < methodList.size(); i++) { // 构建sql语句中的值部分
				tm = targetClass.getMethod(methodList.get(i));
				to = tm.invoke(javaBean);
				if (to instanceof String || to instanceof Boolean) {
					sb.append("\'" + to + "\'");
				} else {
					sb.append(to);
				}
				if (i != methodList.size() - 1)
					sb.append(",");
			}
			sb.append(")");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return sb.toString();
	}

大功告成。这么一来的话,以后我们想获取这条存储的sql语句,只要调用这个方法传入相应的类名参数就行了?省力了不少吧。当然其他的类似语句都可以通过这个方式生成。

————————————————————————

再举个例子吧,比如说我们要把javabean的属性和属性值放到一个map里,如果用反射的话那就更简单了:

	public static Map addJavaBean(Map map, Object javaBean) {
		Class<?> classType = javaBean.getClass(); // 获得对象类型
		Field[] fields = classType.getDeclaredFields(); // 获得对象所有属性域
		for (Field field : fields) { // 遍历属性域,并获得其值
			String attributeName = field.getName(); // 获得属性名
			String methodGet = "get" + attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1); // javabean的get()方法
			try {
				Method get = classType.getMethod(methodGet);// 获得get方法的域
				Object attributeValue = get.invoke(javaBean);// 调用get方法,返回属性值
				map.put(attributeName, attributeValue); // 添加到map中
			} catch (NoSuchMethodException e) {
				e.printStackTrace(System.out);
			} catch (SecurityException e) {
				e.printStackTrace(System.out);
			} catch (IllegalAccessException e) {
				e.printStackTrace(System.out);
			} catch (IllegalArgumentException e) {
				e.printStackTrace(System.out);
			} catch (InvocationTargetException e) {
				e.printStackTrace(System.out);
			}
		}
		return map;
	}

当然你也可以写个方法,删除不必要的属性域。

————————————————————————————

以上都是对javabean的操作,用熟练的话舒服的一批。

要不再搞个复杂点的……比如说动态代理什么的?

public class DAOfactory {
	@SuppressWarnings("unchecked")
	protected static <T> T getProxyInstance(Class<?> daoClass, Class<? extends DAO> implClass)
			throws IllegalArgumentException, InstantiationException, IllegalAccessException {
		return (T) Proxy.newProxyInstance(daoClass.getClassLoader(), new Class[] { daoClass },
				new DynamicProxy(implClass.newInstance()));
		
	}

	public static StudentDAO getStudentDAOInstance() {
		try {
			return getProxyInstance(StudentDAO.class, StudentDAOimpl.class);
		} catch (IllegalArgumentException | InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static TeacherDAO getTeacherDAOInstance() {
		try {
			return getProxyInstance(TeacherDAO.class, TeacherDAOimpl.class);
		} catch (IllegalArgumentException | InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
			return null;
		}
	}
}

在这里面吧,我想让类在实例化的时候自动在工厂里生成它的实例,并且找到它的代理。

其中上面的Proxy.newProxyInstance是java里关于反射的一个方法,前两个参数大家都能看懂,至于第三个参数做了什么,还得我们自己实现。

public class DynamicProxy implements InvocationHandler {
	Object proxied; // 被代理的impl对象

	public DynamicProxy(Object proxied) { // 传入被代理的对象
		this.proxied = proxied;
	}

	/*
	 * 重载invoke方法 功能:实现对impl类的代理,同时实现数据的库的连接,以事务的方式发送
	 * 
	 * @method:接口类被调用的方法
	 * 
	 * @args:调用方法的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Connection conn = MyDBConnectionFactory.getMyDBConnection();
		Class<? extends DAO> clazz = (Class<? extends DAO>) proxied.getClass();
		Object retobj = null;
		try {
			Method setConnMethod = clazz.getMethod("setConnection", new Class[] { Connection.class });
			setConnMethod.invoke(proxied, conn);
			conn.setAutoCommit(false);
			retobj = method.invoke(proxied, args);
			conn.commit();
		} catch (SQLException e) {
			conn.rollback();
			e.printStackTrace();
			retobj = null;
		} finally {
			conn.close();
		}

		return retobj;
	}

}

比如说我们这么写,那么数据库的连接和事务回滚我们就把它写到代理里面了。

这样一来呢,以后我们要找dao的实例,只需要

this.teacherDAO = DAOfactory.getTeacherDAOInstance();

就可以啦。

(如果不用动态代理,得在每个impl后都写个proxy,代码将大量重复,看着都心烦)

——————————————————————

反正呢,熟悉反射之后,一般我看到有跟javabean有关字符串频繁出现,都会下意识的搞个小方法让它自动生成,然后对一些设计模式和框架底层实现也可以帮助理解啊,总之能用代码偷懒,就很舒服。


作者:寂地
链接:https://www.zhihu.com/question/66525147/answer/243139185
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值