【反射】用Java反射机制手写出JavaBean的单级与多级的属性封装:可能是mybaties的底层实现原理之一

认识反射

  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
  要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

那么Java反射有什么作用呢?

假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。

Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。

代码时间:多级联属性的封装(对反射相当熟悉的小伙伴请享用。)

首先是三个普通Java类

//普通Java类
public class Company {
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Company [name=" + name + "]";
	}
}

public class Dept {
	private int dno;
	private String name;
	private Company company;

	@Override
	public String toString() {
		return "Dept [dno=" + dno + ", name=" + name + ", company=" + company + "]";
	}

	public Company getCompany() {
		System.out.println("调用Company");
		return company;
	}

	public void setCompany(Company company) {
		this.company = company;
	}

	public int getDno() {
		return dno;
	}

	public void setDno(int dno) {
		this.dno = dno;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}
import java.util.Date;

public class Emp {
	private String ename;
	private String job;
	private Integer age;
	private double salary;
	private Date birthday;
	private Dept dept;

	public Dept getDept() {
		return dept;
	}

	public void setDept(Dept dept) {
		this.dept = dept;
	}

	public String getEname() {
		return ename;
	}

	public void setEname(String ename) {
		this.ename = ename;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	@Override
	public String toString() {
		return "Emp [ename=" + ename + ", job=" + job + ", age=" + age + ", salary=" + salary + ", birthday=" + birthday
				+ ", dept=" + dept + "]";
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

}

相信这三个类对于开发过web项目的小伙伴们都不陌生。那接下来重头戏来了。

/**
 * 字符串处理类
 * 
 * @author Administrator
 *
 */
public class StringUtils {
	// 构造方法私有化,不允许外部创建对象
	private StringUtils() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * 首字母转大写的工具方法
	 * 
	 * @param str
	 *            需要格式化的字符串
	 * @return 已经格式化过后的字符串
	 */
	public static String initCap(String str) {
		if (str == null) {
			return null;
		}
		if ("".equals(str)) {
			return str;
		}
		if (str.length() == 1) {
			return str.toUpperCase();
		} else {
			return str.substring(0, 1).toUpperCase() + str.substring(1);
		}
	}
}

接下来是bean工厂类

/**
 * 创建对象的工厂类,参考工厂设计模式
 * 
 * @author Administrator
 *
 */
public class ClassInstanceFactory {
	private ClassInstanceFactory() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * 
	 * @param clazz
	 *            要实例化的类
	 * @param value
	 *            实例化对象需要封装的值
	 * @return 返回实例化后的值
	 */
	public static <T> T create(Class<?> clazz, String value) {
		try {
			//直接通过无参构造创建对象
			Object obj = clazz.getDeclaredConstructor().newInstance();
			BeanUtils.setValue(obj, value);// 通过反射设置属性
			return (T) obj;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}
}

接下来核心代码

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 属性封装的工具类
 * 
 * @author Administrator
 *
 */
public class BeanUtils {
	private BeanUtils() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * 
	 * @param obj
	 *            需要设置 值得对象
	 * @param value
	 *            需要设置的值
	 */
	public static void setValue(Object obj, String value) {
		String[] split = value.split("\\|");
		for (int i = 0; i < split.length; i++) {// 循环设置属性内容
			// split[0]是属性名 split[1]是属性内容
			String[] spl = split[i].split(":");
			try {
				if (spl[0].contains(".")) {// 多级配置
					String[] temp = spl[0].split("\\.");
					Object currentObj = obj;
					// 最后一位肯定是属性名称,所以不再本次实例化考虑范围
					for (int j = 0; j < temp.length - 1; j++) {// 实例化
						// 调用getter方法。如果返回null则表示未实例化
						Method method = currentObj.getClass().getDeclaredMethod("get" + StringUtils.initCap(temp[j]));
						Object tempObj = method.invoke(currentObj);// 调用get方法获取返回值
						if (tempObj == null) {// 没有返回值则表示没有实例化
							// 获取字段对象
							Field field = currentObj.getClass().getDeclaredField(temp[j]);
							// 获取该字段的set方法
							Method met = currentObj.getClass().getDeclaredMethod("set" + StringUtils.initCap(temp[j]),
									field.getType());
							// 创建该字段的实例化对象
							Object newObject = field.getType().getDeclaredConstructor().newInstance();
							// 设置该对象
							met.invoke(currentObj, newObject);
							// 当前操作对象变成新创建的对象
							currentObj = newObject;
						} else {// 有实例化对象
							currentObj = tempObj;// 获取到的对象变成当前操作对象
						}
					}
					// 以下为属性设置
					Field field = currentObj.getClass().getDeclaredField(temp[temp.length - 1]);
					Method method = currentObj.getClass()
							.getDeclaredMethod("set" + StringUtils.initCap(temp[temp.length - 1]), field.getType());
					Object inverseAttributs = inverseAttributs(field.getType().getName(), spl[1]);
					method.invoke(currentObj, inverseAttributs);
				} else {// 只是简单字段赋值
					// 获取字段对象
					Field field = obj.getClass().getDeclaredField(spl[0]);
					// 获取set方法
					Method method = obj.getClass().getDeclaredMethod("set" + StringUtils.initCap(spl[0]),
							field.getType());
					// 数据类型转换
					Object inverseAttributs = inverseAttributs(field.getType().getName(), spl[1]);
					// 设置值
					method.invoke(obj, inverseAttributs);
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}

		}
	}

	/**
	 * 对常用类型进行格式化
	 * 
	 * @param type
	 * @param value
	 * @return
	 */
	public static Object inverseAttributs(String type, String value) {
		if ("long".equals(type) || "java.lang.Long".equals(type)) {
			return Long.parseLong(value);
		} else if ("int".equals(type) || "java.lang.Integer".equals(type)) {
			return Integer.parseInt(value);
		} else if ("double".equals(type) || "java.lang.Double".equals(type)) {
			return Double.parseDouble(value);
		} else if ("java.util.Date".equals(type)) {// 对时间类型进行格式化
			SimpleDateFormat sdf = null;
			if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
				sdf = new SimpleDateFormat("yyyy-MM-dd");
			} else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}.\\d{2}.\\d{2}")) {
				sdf = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
			} else {
				return new Date();
			}
			try {
				return sdf.parse(value);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return new Date();
			}
		} else {
			return value;
		}
	}
}

测试类

public class Demo {

	public static void main(String[] args) {
		// 某种格式的数据把他格式化为对象
		String value = "ename:开发|job:coder|age:20|salary:3400.00|birthday:1999-10-10 21.32.44"
				+ "|dept.name:开发部dadada|dept.dno:1000|dept.company.name:家里蹲";
		// 开始格式化
		Object create = ClassInstanceFactory.create(Emp.class, value);
		System.out.println(create);
	}

}
 /*
                           _ooOoo_
                          o8888888o
                          88" . "88
                          (| -_- |)
                          O\  =  /O
                       ____/`---'\____
                     .'  \\|     |//  `.
                    /  \\|||  :  |||//  \
                   /  _||||| -:- |||||-  \
                   |   | \\\  -  /// |   |
                   | \_|  ''\---/''  |   |
                   \  .-\__  `-`  ___/-. /
                 ___`. .'  /--.--\  `. . __
              ."" '<  `.___\_<|>_/___.'  >'"".
             | | :  `- \`.;`\ _ /`;.`/ - ` : | |
             \  \ `-.   \_ __\ /__ _/   .-` /  /
        ======`-.____`-.___\_____/___.-`____.-'======
                           `=---='
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                 佛祖保佑       永无BUG
        */
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值