將之前學的Java知識進行匯總和整理,本篇主要講述Java反射和使用用例。
項目開發中,經常遇到需要給實例化對象設置屬性值,並且當屬性特別多時,setter屬性占用很大篇幅,在此用反射實現實例化對象,並自動設置屬性值。可以作為以后項目的小工具,方便開發。
大致思路:(1)對需要實例化的Class對象,通過反射進行實例化;(2)將固定格式的參數注入到對象中。
篇外話:該思路與Spring的IOC類似,(1)程序啟動時,Spring會解析提前配置好的Bean信息(如通過XML配置或注解配置),將Bean抽象為BeanDefinition結構,其中包含類的全限定名和依賴的類信息,並注冊到容器中(說白了就是key-value的map中)。(2)在程序第一次執行getBean()時,會注入依賴的對象,這個會設計級聯注入,直到屬性為基本類型。
開始正文,下邊代碼是實現了類的實例化和屬性設置功能,主要包括 簡單數據類型設置 和 級聯對象引用設置。
(1)創建類實例化工廠類:包含實例化和設置屬性值兩個步驟;
(2)StringUtils類用於處理setter和getter方法名
(3)BeanUtils類用於設置屬性,其中包含級聯屬性實例化
具體過程已記錄在代碼注釋中。
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date;
public class ClassInstanceFactory{ private ClassInstanceFactory(){} /** * 1.首先進行實例化;2.再對實例化對象設置屬性值,格式“屬性:值|屬性:值” * @param clazz Class反射實例化 * @param value 為實例化對象設置屬性值 * @param <T> * @return */ public static <T> T createInstane(Class<T> clazz, String value){ try { Object obj = clazz.getDeclaredConstructor().newInstance(); BeanUtils.setValue(obj, value); return (T)obj; } catch (Exception e){ return null; } } } class StringUtils{ /** * 首字母大寫,以獲取setter和getter方法 * @param str * @return */ public static String initCap(String str){ if(null == str || "".equals(str)){ return str; } if(str.length() == 1){ return str.toUpperCase(); } else{ return str.substring(0,1).toUpperCase()+str.substring(1); } } } //為實例化對象設置屬性值 class BeanUtils{ public static void setValue(Object obj, String value){ String[] attrs = value.split("\\|"); for(int i = 0; i < attrs.length; i++){ String[] attr = attrs[i].split("\\:"); //判斷是否是處理級聯引用 if(attr[0].contains(".")) { String[] str = attr[0].split("\\."); try { //1.獲取級聯屬性是否為null Method getMethod = obj.getClass().getDeclaredMethod("get" + StringUtils.initCap(str[0])); Object tmp = getMethod.invoke(obj); if(tmp == null){ //2.為null時,需要初始化后,再設置屬性值 //2.1 首先實例化 Field field = obj.getClass().getDeclaredField(str[0]); tmp = field.getType().getDeclaredConstructor().newInstance(); //2.2 設置級聯引用的屬性 setValue(tmp, attrs[i].substring(attrs[i].indexOf(".")+1)); //2.3 將實例化完成的級聯屬性設置到對象中 Method method = obj.getClass().getDeclaredMethod("set" + StringUtils.initCap(str[0]), field.getType()); method.invoke(obj, tmp); } else { //3.不為空時,直接設置級聯引用的屬性 setValue(tmp, attrs[i].substring(attrs[i].indexOf(".")+1)); } } catch (Exception e){ } } else { //非級聯引用 try { //getField返回所有public的屬性; getDeclaredField 返回類所有聲明的屬性 Field field = obj.getClass().getDeclaredField(attr[0]); //getMethod 返回所有public的方法,包含父類 getDeclaredMethod返回所有聲明的方法,不包含父類 Method method = obj.getClass().getDeclaredMethod("set" + StringUtils.initCap(attr[0]), field.getType()); //獲取屬性實際值 Object val = convertType(field.getType().getName(), attr[1]); method.invoke(obj, val); } catch (Exception e) { } } } } private static Object convertType(String type, String value){ if(Integer.class.getName().equals(type) || "int".equals(type)) { return Integer.valueOf(value); } else if(Double.class.getName().equals(type) || "double".equals(type)){ return Double.valueOf(value); } else if(Long.class.getName().equals(type) || "long".equals(type)){ return Long.valueOf(value); } else if(Date.class.getName().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 (Exception e){ return new Date(); } } else{ return value; } } }
測試:
/** * 對簡單對象進行實例化,並給各屬性賦值 * 為避免大量setter代碼出現,使用反射機制簡化初始化過程 */ public class ReflectAndSimplObject { public static void main(String[] args){ String value = "name:bob|age:80|birth:1990-10-10|dept.name:ssc|dept.company.name:td|dept.company1.name:ry"; Person p = ClassInstanceFactory.createInstane(Person.class, value); System.out.println(p); } } class Company{ String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Company{" + "name='" + name + '\'' + '}'; } } class Company1 { String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Company1{" + "name='" + name + '\'' + '}'; } } class Dept{ String name; long id; Company company; Company1 company1; public String getName() { return name; } public void setName(String name) { this.name = name; } public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } public long getId() { return id; } public void setId(long id) { this.id = id; } public Company1 getCompany1() { return company1; } public void setCompany1(Company1 company1) { this.company1 = company1; } @Override public String toString() { return "Dept{" + "name='" + name + '\'' + ", id=" + id + ", company=" + company + ", company1=" + company1 + '}'; } } class Person{ String name; int age; Date birth; Dept dept; 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 Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", birth=" + birth + ", dept=" + dept + '}'; } }
輸出:
Person{name='bob', age=80, birth=Wed Oct 10 00:00:00 CST 1990, dept=Dept{name='ssc', id=0, company=Company{name='td'}, company1=Company1{name='ry'}}}
總結
反射的使用,將增加代碼的靈活性,並使代碼編寫更簡潔。可以將這個作為以后項目的工具,簡化diamagnetic編寫。