java疯狂讲义笔记:
1.对象序列化
概念:是指将java对象保存在磁盘中,或是允许在网络中直接传输java对象。对象序列化机制允许把内存的java对象转化成与平台无关的二进制流,从而将这种二进制流保存在磁盘中,或是通过网络将这种二进制流传输到另一个网络节点中,一旦获得了这种二进制流就可以恢复成原来java对象。
序列化可以使java对象脱离程序的运行而独立存在;
对象的序列化是指将一个java对象写入io流中,同样对象的反序列化是指从io流中恢复该java对象
2.如何实现序列化
如果需要让某个对象支持序列化机制,必须让他的类是可序列化的,为了让某个类是可序列化的该类必须实现两个接口中的一个“
Serializable
Externalizable
3.使用对象流实现序列化
若实现Serializable接口,只需要让目标类实现Serializable标记接口,而不需要实现任何方法;
程序可以通过如下两个步骤将对象序列化
1)创建一个ObjectOutputStream,这个输出流是个处理流 必须建立在其他节点流的基础上
eg:ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("test.txt");
2)调用ObjectOutputStream的对象的方法wirteObject输出可序列化的对象
eg:os.write(person);
如果希望从二进制流恢复java对象,则需要反序列化;步骤如下:
1)创建ObjectInputStream
2)调用ObjectInputStream的readObject方法
class PersonOne implements java.io.Serializable{
private String name;
private int age;
public PersonOne(String name,int age)
{
System.out.println("Person的有参构造函数");
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class ObjectSerializableTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//System.out.println(p.getName()+p.getAge());
ObjectOutputStream os=null;
ObjectInputStream oi=null;
try
{
//序列化操作
os=new ObjectOutputStream(new FileOutputStream("serializableTest.txt"));
PersonOne p=new PersonOne("zz",50);
//保存对象
os.writeObject(p);
//反序列化操作
oi=new ObjectInputStream(new FileInputStream("serializableTest.txt"));
PersonOne per=(PersonOne) oi.readObject();
System.out.println(per.getName() +":"+per.getAge());
}catch(Exception e)
{
e.printStackTrace();
}finally
{
try
{
os.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
}
}
结果:
PersonOne的有参构造函数
zz:50
从结果中可以看出反序列化时程序并没有调用类的构造函数表明反序列化时无需通过java构造器初始化对象
4.对象引用的序列化
java序列化采用一个特殊的序列化算法
1)所有保存在磁盘里的对象都有一个序列化编号
2)当程序试图序列化一个对象时,程序先检测该对象是否已经被序列化,如果没有被序列化才将对象序列化,如果已经序列化了,程序将只是输出一个序列化编号,而不是重新序列化对象
public class Teacher
implements java.io.Serializable
{
private String name;
private Person student;
public Teacher(String name , Person student)
{
this.name = name;
this.student = student;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void setStudent(Person student)
{
this.student = student;
}
public Person getStudent()
{
return this.student;
}
}
public class WriteTeacher
{
public static void main(String[] args)
{
ObjectOutputStream oos = null;
try
{
//创建一个ObjectOutputStream输出流
oos = new ObjectOutputStream(
new FileOutputStream("teacher.txt"));
Person per = new Person("孙悟空", 500);
Teacher t1 = new Teacher("唐僧" , per);
Teacher t2 = new Teacher("菩提祖师" , per);
//依次将四个对象写入输出流
oos.writeObject(t1);
oos.writeObject(t2);
oos.writeObject(per);
oos.writeObject(t2);
}
catch (IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (oos != null)
oos.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
实际的序列化图形如下:
public class ReadTeacher
{
public static void main(String[] args)
{
ObjectInputStream ois = null;
try
{
//创建一个ObjectInputStream输入流
ois = new ObjectInputStream(
new FileInputStream("teacher.txt"));
//依次读取ObjectInputStream输入流中的四个对象
Teacher t1 = (Teacher)ois.readObject();
Teacher t2 = (Teacher)ois.readObject();
Person p = (Person)ois.readObject();
Teacher t3 = (Teacher)ois.readObject();
//输出true
System.out.println("t1的student引用和p是否相同:"
+ (t1.getStudent() == p));
//输出true
System.out.println("t2的student引用和p是否相同:"
+ (t2.getStudent() == p));
//输出true
System.out.println("t2和t3是否是同一个对象:"
+ (t2 == t3));
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (ois != null)
ois.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
5.自定义序列化
在一些特殊的场景下,如果某个类包含的属性值是敏感信息,例如银行账号的信息的时候,这时候不系统程序对该属性进行序列化,这个时候我们可以在该属性的前面加上transient关键字,这样java序列化就不会理会该属性,不会讲java对象的值序列化。
注:transient只能修饰关键字,不能修饰java的其他的成分
java提供了另一种序列化机制,通过这种自定义的序列化机制,可以使程序控制如何序列化属性,甚至完全不序列化某些属性;
在序列化和反序列化中,对于特殊处理的类应该提供一下特殊签名的方法这些特殊的方法用以实现自定义序列化:
private void writeObject(java.io.ObjectOutputStream out)throw IOException
private void readObject(java.io.ObjectInputStream in)throw IOException,ClassNotFoundException
private void readObjectNoData()throw ObjectStreamException;