对象的序列化就是把对象的状态用字符串或者byte数组表示,以方便在网络上传输或者将数据写入文件。而反序列化即根据字符串或者byte数组欢迎对象的状态。一般常用的序列化方法是xml序列化,将对象的各个属性写入xml,然后用网络发送到远方,远方收到xml后创建一个空对象,最后根据xml的信息欢迎对象的状态。
当然用json来序列化要比xml要高效很多。但是,经过实验研究发现json还有优化空间,于是本人设计了一套CommaString用于优化序列化过程。CommaString,顾名思义,即逗号字符串,比如一个对象A,其中有两个属性:整数10,字符串“hello”。对象A序列化后为:10,“hello"。这样比json要少一些字符,当然,逗号字符串中各个数据的顺序必须严格一致,即序列化时写入的顺序和反序列化时读取的顺序必须一样。在很多情况下,序列化和反序列化的实现是同一个人,即RMI的双方知道序列化的顺序,所以逗号字符串还是有可用的地方的。
序列化
下面以添加字符串举例说明序列化过程。
public void putString(String src)
{
if(src==null)
{
putString("null");
return;
}
if(stringBuffer.length()>0)
stringBuffer.append(",");
stringBuffer.append(src);
}
其中stringBuffer是一个StringBuffer,用这个也是出于效率的考虑。序列化接口很简单,如果是string类型,只需要把string放入buffer中即可,如果是int或者double等基础类型,则转为string类型再放入buffer中。
至于数组类型、list、set等二维数据类型,则先将其大小放入buffer,然后再将各个元素一一放入buffer。如下:
public void putIntArray(int[] data)
{
int i;
int[] objIntArray=data;
putInt(objIntArray.length);
for(i=0;i<objIntArray.length;i++)
{
putInt(objIntArray[i]);
}
}
至于hashMap,则首先先将map的大小放入buffer,然后对于每个元素,先放key,后放value。
public void putHashMap(HashMap<String,CommaSerialize> hashMap)
{
putInt(hashMap.size());
for(String key:hashMap.keySet())
{
putString(key);
putComma(hashMap.get(key));
}
}
最后是object的支持:借用instanceof来判断对象的类型,然后进一步序列化。
public void putObject(Object obj)
{
if(obj==null)
{
putString("null");
return;
}
if(obj instanceof Integer)
{
putInt(Integer.parseInt(obj.toString()));
}
else if((obj instanceof Float) ||(obj instanceof Double))
{
putDouble(Double.parseDouble(obj.toString()));
}
else if( obj instanceof String)
{
putString(obj.toString());
}
else if(obj instanceof Boolean)
{
putBoolean(Boolean.parseBoolean(obj.toString()));
}
else if(obj instanceof CommaSerialize)
{
((CommaSerialize)obj).toSerialize(this);
}
else if(obj instanceof int[])
{
putIntArray((int[])obj);
}
else if(obj instanceof float[])
{
int i;
float[] objIntArray=(float[])obj;
putInt(objIntArray.length);
for(i=0;i<objIntArray.length;i++)
{
putDouble(objIntArray[i]);
}
}
else if(obj instanceof double[])
{
putDoubleArray((double[])obj);
}
else if(obj instanceof String[])
{
putStringArray((String[])obj);
}
else if(obj instanceof Object[])
{
int i;
Object[] arrayObjects=(Object[])obj;
putInt(arrayObjects.length);
for(i=0;i<arrayObjects.length;i++)
{
putObject(arrayObjects[i]);
}
}
else if(obj instanceof List)
{
List<?> objCollection=(List<?>) obj;
putList(objCollection);
}
else if(obj instanceof HashMap)
{
putHashMap((HashMap<String, CommaSerialize>)obj);
}
else
{
Log.log("CommaString type error with '"+obj.getClass().toString()+"'");
}
}
反序列化序列化后的结果其实还是普通的字符串,只是中间有不少逗号以间隔。反序列化最关键的是以逗号为间隔获取字符串:
public String getNext()
{
String outString;
if(sourceString==null || haveNext==false)
return null;
end=sourceString.indexOf(',',begin);//根据begin end截取子串。
if(end==-1)
{
haveNext=false;//没有后续的字符串了
outString=sourceString.substring(begin); //最后一个子串 特殊处理
}
else
{
outString=sourceString.substring(begin, end);
}
begin=end+1; //更新begin 和end,以备下次获取子串
end++;
if(outString.equals("null"))//约定字符串null为空对象
return null;
return outString;
}
有了上面的方法支持,很方便的反序列化所有对象。例如要反序列化整数数组:
public int[] getIntArray()
{
int len=getNextInt();
int i;
int[] ret=new int[len];
for(i=0;i<len;i++)
{
ret[i]=getNextInt();//以整数为类型获取下一个对象
}
return ret;
}
反序列化的过程和序列化的过程恰好相反。其中getNextInt是在getNext的基础上,将获取到的字符串转化为int类型。对象序列化与反序列化举例:
假如类A有两个成员:int a和string b;那么类A的序列化函数和反序列化函数可以如下实现:
@Override
public void toSerialize(CommaString writer) {
// TODO Auto-generated method stub
writer.putObject(a);
writer.putObject(b);
}
@Override
public void deSerialize(CommaString args) {
// TODO Auto-generated method stub
a = args.getNextInt();
b = args.getNext();
}