Java 反射---資料序列化成物件 總結
說起java的序列化,我們最初的理解就是形成一個檔案,儲存到本地,這是最為常用的一點,也算是較為基礎的一部分了。
而反射呢,不外乎就是跳過預編譯,生成一個物件,代替一個new 的過程。
常用基礎的應該就是Class.forName(),和Class.newInstance()這兩個方法了。
在這周的空閒時間重新回顧了下java反射的基礎,對其有了一個新的理解,其主要的工具包主要是依賴於 java.lang.reflect包中。
用一個情景來進行解釋好了,我們設擁有這樣的一個場景,
現在我們由一個Data的類(它擁有的屬性是任意型別的),然後我們得到了一串關於Data類屬性的值,我們通過反射來建立一個擁有實際值的Data物件。
先來總結一下,本次情景主要用到的方法,並且做一個總結:
獲取構造方法:
getConstructors():所有"公有的"構造方法 getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
其中要注意的是使用getDeclaredConstructors()獲得私有時,需要用到setAccessible()來進行解除限定。
獲取類中每一條屬性的記錄:
-
getFields():獲取所有的"公有欄位"
-
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),但是需求是一直都在變化的,而這種可拓展性相對來說要高的多。