相关知识点:RMI
关键点:
Serializable
1.一个类只要继承Serializable,就可以被序列化
2.静态变量不会保存,序列化只针对变量,不针对方法
3.通过ObjectOutputStream进行序列化,ObjectInputStream反序列化
4.虚拟机是否允许反序列化,不仅跟存储路径、功能代码是否一致,另一个非常重要的因素的序列化ID是否一致(private static final Long serialiVersionUID)
5.通过在变量前面加入关键字transient,可以阻止该变量序列化到文件中,当反序列化时,该变量被设置为初始值,int->0 string->null
6.服务器给客户端发送序列化数据时,如果里面有敏感数据(例如密码),可以在序列化时加密,而客户端拥有解密的密钥,这样就可以保证通信安全。
7.ArrayList实现了Serializable,AttayList底层存储数据的是一个数组,这个数组变量被transient修饰符修饰,但是我们存进去数据后,对ArrayList对象进行序列化却可以将数据保存下去,这是因为ArrayList 定义了writeObject()和readObject(),被序列化的类定义了这两个方法,虚拟机就会调用者两个方法来实现自定义序列化和反序列化。相反,如果,没有定义,默认会调用ObjectOutputStream的defaultWriteObject()方法,ObjectInputStream的defaultReadObject()。ArrayList之所以要讲内部数组定义为transient,再重写序列化方法,是因为数组很大的话,假如数组长度为100,但是只有一个值,其它为null,如果此时直接把数组序列化,就会做大量的无用功,所以将内部数组定义为transient,同时为了满足内部数据可以被序列化,就重写了writeObject()和readObject()
8.要实现自定义序列化,只需要在序列化类中,添加writeObject()和readObject()
9.通过反射调用writeObject()和readObject()
10.Serializable只是一个空接口,当序列化的时候对类型检查来保证只有实现Serializable的类或者属于Enum/Array类的一种才能被序列化
11.Serializable没有属性和方法,只是用来标记是否可以序列化
12.可序列化的所有子类,都可以序列化
13.还有一个接口:Externalizable继承Serializable,并且它会强制继承者自己实现writeObject()和readObject(),不然数据就不会被序列化,只有类结构被序列化,当反序列化时,对象参数都是默认值。
14.序列化ID两种生成策略:1.固定值1L,2,使用jdk工具生成一个随机的long类型数据,不同的编译器可能生成的值不同,所以序列化ID最好固定死后(1L)不要动,否则容易导致无法解析旧数据对象。
15.如果一个类的所有父类都没有被序列化,此时想要序列化,则它的所有父类都 必须要有一个空参的构方法,因为父类不能序列化,但是所有的子类都是从父类来的,反序列化的时候就需要通过这个 构造函数构造出一个父类,父类的所有值都是默认值。
16.将一个对象序列化两次,占用的内存只会比一个对象序列化占用的内存多一点点,因为java序列化机制对同一个对象多次序列化做了优化以节省存储空间,第二个只会拥有第一个的引用,当反序列化后,这两个对象是想等的。注意,当第一次序列化后,修改对象后再序列化,第二个序列化还是只会拥有第一个序列化的引用,所以此次修改对序列化后的数据无效,取出两个对象值相同,因为还是优化机制,只会判断是否是一个对象,并不会判断对象值是否相等。
Parcelable
- Intent之间可以传递简单的数据,但是当数据结构比较复杂时就需要进行序列化
- Parcelable作为中间层,底层利用c++直接操作内存
两者对比:
1.Parcelable内存使用优于Serializable
2.Serializable在序列化时会产生大量的临时变量(反射机制),会导致大量的GC,所以性能上会略逊色。
3.Parcelable是以IBindler作为载体的,内存开销小,所以当消息传递对象时(内存之间传递),一般使用Parcelable。
4.Parcelable直接在内存中进行读写,而Serializable是以字节流的形式写入到硬盘的。
5.Parcelable并不能持久的存储数据,它只是在传递时比较有优势,对于那些需要长久保存的对象,还是需要Serializable。
1.什么是?
序列化就是一种持久保存对象的手段,而反序列化就是对持久保存的对象进行读取。
现已广泛应用于:持久化对象、RMI(远程方法调用)、远程传递对象
Parcelable是Android SDK提供的用来序列化和反序列化的一种方式。
2.为什么要?
我们知道,java平台运行我们创建可复用的对象,但通常这些对象只有当JVM运行期间才有效,也就是普通的对象的生命周期肯定小于JVM的生命周期。在实际开发过程了,我们可能需要保留一些对象,保留期限超过JVM生命周期,这个时候需要一种技术,来满足这种要求。
序列化就出现了,他通过将对象状态存储为一组字节,当需要的时候,进行从字节到对象的转化(反序列化)。由于只是存储对象的状态,所以它不会存储静态变量。
Java提供的Serializable,进行序列化或者反序列化都 需要大量的I/O操作,成本太大,不适合Android面向的小内存设备,所以需要一种开销小的方式来进行序列化和反序列化,它就是Parcelable
54
3.怎么使用?
文本描述:如果一个类想要实现序列化,只需要继承Serializable
实际操作演示:
User类
import java.beans.Transient;
import java.io.Serializable;
public class User implements Serializable {
private static String age="18";
private String name;
private transient String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age='" + age + '\'' +
'}';
}
}
实际操作类:
import java.io.*;
public class Main {
private static String FILE_NAME="temp";
public static void main(String[] args) throws Exception {
User user=new User();
user.setName("小马哥");
user.setSex("小帅锅");
System.out.println(user);
//将对象写入文件
ObjectOutputStream objectOutputStream=
new ObjectOutputStream(new FileOutputStream(FILE_NAME));
objectOutputStream.writeObject(user);
//注意,正确做法应该使用try----finally来关闭
objectOutputStream.close();
//为了看出static没有被实例化,修改age的值
User.age="20";
//将对象从文件红读取到内存中
File file=new File(FILE_NAME);
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
User oldUser= (User) objectInputStream.readObject();
System.out.println("从文件读取的对象"+oldUser);
}
}
最后结果:
User{name='小马哥', sex='小帅锅', age='18'}
从文件读取的对象User{name='小马哥', sex='null', age='20'}
Parcalable:
User:
package com.xiaomage.parcelabledemo;
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
public User(String name, String sex) {
this.name = name;
this.sex = sex;
}
protected User(Parcel in) {
//从序列化中创建对象:反序列化操作
name = in.readString();
sex=in.readString();
age=in.readString();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
//从序列化中创建对象:反序列化操作
return new User(in);
}
@Override
public User[] newArray(int size) {
//创建指定长度的原始对象数组
return new User[size];
}
};
@Override
public void writeToParcel(Parcel dest, int flags) {
//将对象写入序列化中
dest.writeString(name);
dest.writeString(age);
dest.writeString(sex);
}
@Override
public int describeContents() {
//几乎所有的情况都返回0,仅在当前对象存在文件描述符时返回1
return 0;
}
public static String age="18";
private String name;
private transient String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age='" + age + '\'' +
'}';
}
}