1. 程式人生 > >Java 反射---資料序列化成物件 總結

Java 反射---資料序列化成物件 總結

說起java的序列化,我們最初的理解就是形成一個檔案,儲存到本地,這是最為常用的一點,也算是較為基礎的一部分了。

而反射呢,不外乎就是跳過預編譯,生成一個物件,代替一個new 的過程。

常用基礎的應該就是Class.forName(),和Class.newInstance()這兩個方法了。

在這周的空閒時間重新回顧了下java反射的基礎,對其有了一個新的理解,其主要的工具包主要是依賴於 java.lang.reflect包中。

用一個情景來進行解釋好了,我們設擁有這樣的一個場景,

現在我們由一個Data的類(它擁有的屬性是任意型別的),然後我們得到了一串關於Data類屬性的值,我們通過反射來建立一個擁有實際值的Data物件。

先來總結一下,本次情景主要用到的方法,並且做一個總結:

獲取構造方法:

getConstructors():所有"公有的"構造方法 getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)

其中要注意的是使用getDeclaredConstructors()獲得私有時,需要用到setAccessible()來進行解除限定。

獲取類中每一條屬性的記錄:

  1. getFields():獲取所有的"公有欄位"

  2. getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有

其中要注意的一項是反射生成的是一個物件的資料,而不是一個類。因此對於獲取到的靜態變數,其實屬於整個類的,不加入反射。

獲取方法,呼叫方法:

1.批量的:

public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類)

public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的)

2.獲取單個的:

public Method getMethod(String name,Class<?>... parameterTypes):

*引數:

* name : 方法名;

* Class ... : 形參的Class型別物件

* public Method getDeclaredMethod(String name,Class<?>... parameterTypes)

* 呼叫方法:

* Method --> public Object invoke(Object obj,Object... args):

* 引數說明:

* obj : 要呼叫方法的物件;

* args:呼叫方式時所傳遞的實參;

為了區分概念免得混淆程式碼先來一個簡陋的識別:

Field:代表整一條的屬性。

Class:修飾詞(例如String類,Interge類這些)

Object:值(儲存的是值,例如String name = “11211”,其中Object指的是11211)

下面是程式碼實現部分:

主測試類:

public class ReflectData {
	
	private static  final ReflectModel<Data> reflectModel = new ReflectModel<>(Data.class);
	
	
	public static void main(String[] args){
		Data data = getData();
		System.out.println(data.toString());
		
	}
	
	//通過反射得到一個Data物件
	private static Data getData(){
		return  reflectModel.getData();
	}
	
	private static class Data{
		String name;
		int age;
		Boolean sex;
		
		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return "name : "+name+",age:" +age+"sex: "+sex;
		}
		
	}
}

其中Data類為本次的場景的測試物件

反射處理model類:


import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;

public class ReflectModel<Model> {
    
	
	private final compositionModel<Model> extractor;//儲存了modelclass、 構造方法、Map<String,Field>
	private final serialMap  serialmap; //對給定的物件的實際值,進行轉化賦值的類,
	private final Map<String,Class<?>> typeMap;
	
	ReflectModel(Class<Model> modelClass){
		this.extractor = new compositionModel<Model>(modelClass);
		this.serialmap = new serialMap();
		this.typeMap = getTypeMap();
	}
	
	private Map<String,Class<?>> getTypeMap(){
		Map<String, Field> sf = this.extractor.getFieldContain();
		Map<String,Class<?>> sc = new LinkedHashMap<String, Class<?>>();
		for(String s:sf.keySet()){
			sc.put(s, sf.get(s).getType());
		}
		return sc;
	}
	
	public Model getData(){
		String dataString ="sss,18,1";
		Model model = deserialize(dataString);
		return model;
	}
	
	public Model deserialize(String dt){
		Model model = extractor.newInstance();
		Map<String,Object> values = extractor.getValues(model);
		serialmap.deserialize(dt, values, typeMap);
		extractor.setValue(model, values);
		return model;
	}
}

model的反射解析類:


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.LinkedHashMap;
import java.util.Map;

public class compositionModel<Model> {
	 
	private final Class<Model> modelClass;
	private final Constructor<Model> modelConstructor;
	private final Map<String, Field>  fieldContain;
	
	compositionModel(Class<Model> cl){
		this.modelClass = cl;
		this.modelConstructor = getModelConstrutor(cl);
		this.fieldContain = getFieldContain(cl);
	}
	
	public Map<String, Field> getFieldContain(){
		return fieldContain;
	}
	
	//設定值
	public void setValue(Model model,Map<String,Object> values){
		for(String s:values.keySet()){
			Field f = fieldContain.get(s);
			try {
				f.set(model,values.get(s));//filed.set()方法對model中該f屬性賦值
			} catch (IllegalArgumentException | IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	//獲得構造方法
	private Constructor<Model> getModelConstrutor(Class<Model> cl){
		try {
			Constructor<Model> modelConstructor = cl.getDeclaredConstructor(new Class<?>[] {});
			modelConstructor.setAccessible(true);
			return modelConstructor;
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		///return modelConstructor;
		return null;
		
	}
	
	//通過構造器獲取model例項
	Model newInstance(){
		try {
			return modelConstructor.newInstance();
		} catch (InvocationTargetException e) {
			//建構函式本身丟擲異常,將盡量把異常以 unchecked 形式丟擲。
			Throwable targetException = e.getTargetException();
			if(targetException instanceof Error) {
				throw (Error) targetException;
			} else if(targetException instanceof RuntimeException) {
				throw (RuntimeException) targetException;
			} else {
				throw new RuntimeException(targetException);
			}
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
		
	}
	
	//獲取物件屬性,排除static和fianl的屬性
	private  Map<String, Field> getFieldContain(Class<Model> cl){
		Map<String, Field> fc = new LinkedHashMap<String, Field>();
		for(Field f:cl.getDeclaredFields()){
			int modifiers = f.getModifiers();
			//與序列化一致,靜態變數是屬於全域性的,不是屬於物件的,不加入反射
			if(!Modifier.isFinal(modifiers) && !Modifier.isStatic(modifiers)){
				f.setAccessible(true);
				fc.put(f.getName(), f);
			}
		}
		return fc;
	}
	
	//獲取每個類的預設值,此處還有拓展,如果實際值沒有的話,可以用設定一個map儲存每一種型別的預設值
	@SuppressWarnings("unchecked")
	public Map<String,Object> getValues(Model model){
		Map<String, Object> so = new LinkedHashMap<String, Object>(fieldContain.size());
		for(String s:fieldContain.keySet()){
			Field field = fieldContain.get(s);
			try {
				so.put(s, field.get(model));//field.get獲取該屬性在某個class中的值
			} catch (IllegalArgumentException | IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		}
		return so;
		
	}
	
}

傳入實際值的賦值處理類:


import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class serialMap {
	
		private static final Map<Class<?>, Class<?>> typeMap = new HashMap<Class<?>, Class<?>>() {{
				
				//Java 除了 char 的 7 種基本型別,外加它們的封包類,外加 String,一共15種類型。
				put(byte.class, Byte.class);
				put(short.class, Short.class);
				put(int.class, Integer.class);
				put(long.class, Long.class);
				put(float.class, Float.class);
				put(double.class, Double.class);
				put(boolean.class, Boolean.class);
				put(Byte.class, Byte.class);
				put(Short.class, Short.class);
				put(Integer.class, Integer.class);
				put(Long.class, Long.class);
				put(Float.class, Float.class);
				put(Double.class, Double.class);
				put(Boolean.class, Boolean.class);
				put(String.class, String.class);
			}};
		
			
		//獲取所有的對應類的賦值方法	
		private static final Map<Class<?>, Method> valueOfMethodMap = getValueOfMethodMap();
			
		//解析s資料,並且生成具體的物件,put進value中	
		void deserialize(String s,Map<String, Object> values,Map<String,Class<?>> typeList){
			String[] sList = s.split("\\,");
			int i=0;
			for(String fieldName:typeList.keySet()){
				Class<?> type = typeList.get(fieldName);
				Object value = getValueFromGetter(sList[i++],type);
				values.put(fieldName, value);
			}
		}
		
		//得到Method類(方法),然後下一步可以呼叫該方法
		private static Map<Class<?>, Method> getValueOfMethodMap() {
			HashMap<Class<?>, Method> map = new HashMap<Class<?>,Method>();
			for(Class<?> key:typeMap.keySet()){
				Class<?> type = typeMap.get(key);
				Method  method = map.get(type);
				if(method == null){
					Class<?>[] typeClasses;
					if(type.equals(String.class)) {
						typeClasses = new Class<?>[] {Object.class};
					} else {
						typeClasses = new Class<?>[] {String.class};
					}
					try {
						method =  type.getMethod("valueOf", typeClasses);//class.getMethod(“a”,b),class表示想要從中呼叫方法的類,a表示方法名字,b表示引數所屬的類
					} catch (NoSuchMethodException | SecurityException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					map.put(type, method);
				}
			}
			return map;
		}
		
		//獲得一個物件的值,例如int可以呼叫Interge的valueof的方法返回一個Interge物件
		Object getValueFromGetter(String s,Class<?>type){
			
			Object value = null;
			if(isBooleanType(type)){
				value = "1".equals(s);
			}else{
				Method method = getValueOfMethod(type);
				try {
					value = method.invoke(null, s); //呼叫方法
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return value;
		}
		Method getValueOfMethod(Class<?>type){
			type = typeMap.get(type);
			return valueOfMethodMap.get(type);
		}
		private static boolean isBooleanType(Class<?> type) {
			return boolean.class.equals(type) || Boolean.class.equals(type);
		}
		
}

測試結果

總結:reflect包類下有著許多有趣的類,上面的例子用的比較多的泛型,對於可變性有著很大的支援性,而反射也是對著適用性會有很大的變通,雖然看起來反射就是相當於new Data(“sss”,18,true),但是需求是一直都在變化的,而這種可拓展性相對來說要高的多。