Serializable
序列化实现
package com.nan.mylibrary;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* 要序列化需要实现Serializable接口
* Created by nan on 18-3-23.
*/
public class Student implements Serializable {
/**
*可以不指定,可以由系统生成,也可手动指定,后面具体分析其使用及作用
*/
private static final long serialVersionUID = -3042243308847924453L;
public static String TAG;
int age;
String name;
transient String nickname;
boolean male;
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
", male=" + male +
'}' + " | Static TAG:" + TAG;
}
Student(int age, String name, String nickname, boolean male) {
this.age = age;
this.name = name;
this.nickname = nickname;
this.male = male;
}
public static void main(String[] args) {
//1. 第一次运行main中注释的部分,直接输出studnet对象
/*Student student = new Student(18, "dog", "feifei", false);
Student.TAG = "hello student";
System.out.println(student);
serialize(student);*/
//2.第二次运行反序列化代码部分,得到反序列化的数据并打印
Student student1 = (Student) deserialize();
System.out.println(student1);
}
/**
*序列化对象
*/
private static void serialize(Object object) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("cache.txt");
ObjectOutputStream ouput = new ObjectOutputStream(fileOutputStream);
ouput.writeObject(object);
ouput.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("file not found");
} catch (IOException e) {
e.printStackTrace();
System.out.println("IOException");
}
}
/**
*反序列化对象
*/
private static Object deserialize() {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("cache.txt");
ObjectInputStream input = new ObjectInputStream(fileInputStream);
Student student = (Student) input.readObject();
return student;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
- 正常打印student对象
Student{age=18, name='dog', nickname='feifei', male=false} | Static TAG:hello student
在当前对象中直接打印student对象可以看到所有信息都正常输出
- 反序列打印student对象
Student{age=18, name='dog', nickname='null', male=false} | Static TAG:null
由此可见序列化不会对static
变量和transient
关键字修饰成员进行序列化
serialVersionUID
注
反序列得到的对象只是在内容上和序列前对象内容一致,但本质是两个对象
- 不指定serialVersionUID
系统会在序列化时自动根据class类计算serialVersionUID,如果类有任何变化serialVersionUID就会发生变化,在反序列化时如果检测到前后序列码不一致则会反序列失败,报错如下
java.io.InvalidClassException: com.nan.mylibrary.Student; local class incompatible: stream classdesc serialVersionUID = 8719351234228157191, local class serialVersionUID = -2675111980170094111
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1829)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1986)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at com.nan.mylibrary.Student.deserialize(Student.java:74)
at com.nan.mylibrary.Student.main(Student.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
- IDE自动生成serialVersionUID
类如何发生变化,则该ID也会发生变化,反序列化也会报错 - 手动指明
如果一些成员发生变化,系统会尽最大程度的恢复数据,但如果系统的发生重大变化(类名,类结构发生变化,此时发序列话也可能失败)。
注意
- 父类实现Serializable接口,子类被序列化,父类也会被序列化
- 父类没有实现Serializable接口,子类被序列化,父类不会被序列化
Parcelable
实现了Parcelable接口的对象可以实现序列化并可以通过Intent和Binder传递
示例
/**
*step1 实现Parcelable接口
*/
public class Student implements Parcelable {
public static String TAG;
String name;
transient String nickname;
int age;
boolean male;
public Student(String name, String nickname, int age, boolean male) {
this.name = name;
this.nickname = nickname;
this.age = age;
this.male = male;
}
/**
* step5 读取数据必须和序列化中写数据顺序严格一致,否则可能值错乱,也有可能出错
*
* @param source
*/
public Student(Parcel source) {
this.name = source.readString();
this.nickname = source.readString();
this.age = source.readInt();
this.male = source.readByte() == 1 ? true : false;
TAG = source.readString();
}
/**
* step2 必须实现,返回0即可
* TODO:具体作用
*
* @return
*/
@Override
public int describeContents() {
return 0;
}
//step3 将要序列化的内容写如Parcel
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(nickname);
dest.writeInt(age);
dest.writeByte((byte) (male ? 1 : 0));//writeboolean的特殊处理
dest.writeString(TAG);
}
//step4 该CREATOR变量名称不能改变.
public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
@Override
public Student createFromParcel(Parcel source) {
//step6 从序列化的对象中创建原始对象
return new Student(source);
}
@Override
public Student[] newArray(int size) {
return new Student[0];
}
};
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
", male=" + male +
'}' + " | Static TAG:" + TAG;
}
}
测试该对象在两个不同进程的Activity传递,通过Intent
来传递
MainActivity 进程
com.nan.ipc
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View view) {
Student student = new Student("dog", "feifei", 18, true);
Student.TAG = "hello student";
Intent intent = new Intent(this, SecondActivity.class);
//intent.putExtra接收为基本类型或者Parcelable和Serializable对象
intent.putExtra("student", student);
startActivity(intent);
}
}
SecondActivity 进程
com.nan.ipc:second
public class SecondActivity extends Activity {
public static final String TAG = "SecondActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Student student = getIntent().getParcelableExtra("student");
Log.i(TAG, "onCreate: " + student);
}
}
打印log如下
01-01 15:43:14.202 10986 10986 I SecondActivity: onCreate: Student{age=18, name='dog', nickname='feifei', male=true} | Static TAG:hello student
由上可知,写入Parcel中的数据都可以反序列出来,即使是transient
修饰符修饰的变量或者static
修饰的变量
注意
- List和Map也可以序列化,前提是他们里面的每个元素都是可序列化的
- 如果序列化时包含已经序列化的对象,在读取是需要传入当前线程的上下文类加载器
book = source.readParcelable(Thread.currentThread().getContentClassLoader());
Serializable和Parcelable的区别
- Parcelable和Serializable都是实现序列化并且都可以用于Intent间传递数据
- Serializable是Java的实现方式,会频繁的IO操作,所以消耗比较大,但是实现方式简单。适用本地存储和网络传输。
- Parcelable是Android提供的方式,其是将一个对象进行效率比较高,但是实现起来复杂一些 。
二者的选取规则是:内存序列化上选择Parcelable, 存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)
网友评论