序列化系列之一:java对象的序列化和反序列化

一,对象的序列化,反序列化
1.对象的序列化,就是将Object转换成byte序列,反之叫对象的反序列化
2.做序列化需要有流类,序列化流(ObjectOutputStream),是(字节的)过滤流,有writeObject方法,写一个对象
反序列化 流(ObjectInputStream)----readObject
3.序列化接口(Serializable)
对象必须实现序列化接口,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准
 /**
         * 如果将来希望这个对象能在网络中传输,也需要把这个对象进行序列化。(在网络中是以字节为单位进行传输的)
         * 所以当我们要保存这个对象,或在网络中传输这个对象时,都需要对这个对象进行序列化
         */

4.例子

对象实现Serializable接口:

import java.io.Serializable;

/**
 * Created by yaming on 17-8-15.
 */
public class Student implements Serializable {
    private Long id;
    private String name;
    private char gender;
    private transient double money;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                ", money=" + money +
                '}';
    }

}

将对象存储到硬盘上

import java.io.*;

/**
 * Created by yaming on 17-8-15.
 * 把对象序列化到文件夹(内存),和反序列化读取这个文件中的对象
 */
public class Student2Serializable {
    public static void main(String[] args) {
        /**
         * 如果将来希望这个对象能在网络中传输,也需要把这个对象进行序列化。(在网络中是以字节为单位进行传输的)
         * 所以当我们要保存这个对象,或在网络中传输这个对象时,都需要对这个对象进行序列化
         */
        String filePath="/home/yaming/Desktop/student.dat";
        //1.对象的序列化
//        ObjectOutputStream outputStream=null;
//        try {
//            outputStream=new ObjectOutputStream(new FileOutputStream(filePath));
//            Student student=new Student();
//            student.setId(1L);
//            student.setName("张三");
//            student.setGender('男');
//            student.setMoney(1);
//            outputStream.writeObject(student);
//            outputStream.flush();
//            outputStream.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        //2.对象的反序列化
        ObjectInputStream inputStream=null;
        try {
            inputStream=new ObjectInputStream(new FileInputStream(filePath));
            //使用readObj方法读出来,并进行强制类型转换
            Student student=null;
            try {
                student=(Student) inputStream.readObject();
                System.out.println(student);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


二,transient关键字
1,一个对象中有些属性不需要序列化,可以用transient关键子修饰。
用transient修饰的元素,该元素不会进行jvm默认的序列化。也可以自己完成这个元素的序列化
(在网络传输中,有些元素不需要传输,也就不用序列化,这样可以节省网络传输的流量)
如何自己完成序列化呢?
有两个方法签名可以实现。可以参考ArrayList里的两个方法 :
writeObject(java.io.ObjectOutputStream s),readObject(java.io.ObjectInputStream s)

import java.io.Serializable;

/**
 * Created by yaming on 17-8-15.
 */
public class Student implements Serializable {
    private Long id;
    private String name;
    private char gender;
    private transient double money;//该元素不会进行jvm默认的序列化

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                ", money=" + money +
                '}';
    }

    //自己实现序列化
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
        s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化
        s.writeDouble(money);//自己完成money的序列化,也可以用s.writeObject(money)
    }
    //自己实现反序列化
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化
        this.money=s.readDouble();//自己完成money的反序列化
    }
}


2,ArrayList序列化优化的问题(ArrayList源码)
ArrayList底层是数组,但我们往list中添加数据时,有添加不满的情况。数组中为空的元素就不用序列化了(有效元素才进行序列化,无效元素就不进行序列化了),这样可以提高性能。ArrayList对底层数组自己做序列化。

transient Object[] elementData; 


源码:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;

/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

/**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();

// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);

// Write out all elements in the proper order.
   //------>数组有效元素的序列化。
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}

if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}

/**
* Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;

// Read in size, and any hidden stuff
s.defaultReadObject();

// Read in capacity
s.readInt(); // ignored

if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);

Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
}

3,序列化中子父类构造函数的问题

如果父类实现了序列化接口,那么父类就可以序列化,子类就不需要再进行序列化接口了。

 3.1,一个类实现了序列化接口,那么其子类都可以进行序列化

 

 





posted @ 2017-09-19 16:54  inspire0x001  阅读(291)  评论(0编辑  收藏  举报