<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    weidagang2046的專欄

    物格而后知致
    隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
    數據加載中……

    Java對象序列化

     在網上看了很多有關序列化的文章,我自己也寫了兩篇,現在感覺這些文章都沒有很好的把序列化說清楚(包括我自己在內),所以在此我將總結前人以及自己的經驗,用更淺顯易懂的語言來描述該機制,當然,仍然會有不好的地方,希望你看后可以指出,作為一名程序員應該具有不斷探索的精神和強烈的求知欲望!

    序列化概述:

          簡單來說序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化,流的概念這里不用多說(就是I/O),我們可以對流化后的對象進行讀寫操作,也可將流化后的對象傳輸于網絡之間(注:要想將對象傳輸于網絡必須進行流化)!在對對象流進行讀寫操作時會引發一些問題,而序列化機制正是用來解決這些問題的!

    問題的引出:

          如上所述,讀寫對象會有什么問題呢?比如:我要將對象寫入一個磁盤文件而后再將其讀出來會有什么問題嗎?別急,其中一個最大的問題就是對象引用!舉個例子來說:假如我有兩個類,分別是A和B,B類中含有一個指向A類對象的引用,現在我們對兩個類進行實例化{ A a = new A(); B b = new B(); },這時在內存中實際上分配了兩個空間,一個存儲對象a,一個存儲對象b,接下來我們想將它們寫入到磁盤的一個文件中去,就在寫入文件時出現了問題!因為對象b包含對對象a的引用,所以系統會自動的將a的數據復制一份到b中,這樣的話當我們從文件中恢復對象時(也就是重新加載到內存中)時,內存分配了三個空間,而對象a同時在內存中存在兩份,想一想后果吧,如果我想修改對象a的數據的話,那不是還要搜索它的每一份拷貝來達到對象數據的一致性,這不是我們所希望的!

    以下序列化機制的解決方案:

    1.保存到磁盤的所有對象都獲得一個序列號(1, 2, 3等等)

    2.當要保存一個對象時,先檢查該對象是否被保存了。

    3.如果以前保存過,只需寫入"與已經保存的具有序列號x的對象相同"的標記,否則,保存該對象

    通過以上的步驟序列化機制解決了對象引用的問題!

    序列化的實現:

          將需要被序列化的類實現Serializable接口,該接口沒有需要實現的方法,implements Serializable只是為了標注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。

    例子:

    import java.io.*;

    public class Test
    {
        public static void main(String[] args)
        {
            Employee harry = new Employee("Harry Hacker", 50000);
            Manager manager1 = new Manager("Tony Tester", 80000);
            manager1.setSecretary(harry);
           
            Employee[] staff = new Employee[2];
           
            staff[0] = harry;
            staff[1] = manager1;
            try
            {
                ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("employee.dat"));
                out.writeObject(staff);
                out.close();
               
                ObjectInputStream in = new ObjectInputStream(
                    new FileInputStream("employee.dat"));
                Employee[] newStaff = (Employee[])in.readObject();
                in.close();
      
                /**
                 *通過harry對象來加薪
                 *將在secretary上反映出來
                 */
                newStaff[0].raiseSalary(10);
               
                for (int i = 0; i < newStaff.length; i++)
                    System.out.println(newStaff[i]);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
       
    }

    class Employee implements Serializable
    {
        public Employee(String n, double s)
        {
            name = n;
            salary = s;
        }
       
        /**
         *加薪水
         */
        public void raiseSalary(double byPercent)
        {
            double raise = salary * byPercent / 100;
            salary += raise;
        }
       
        public String toString()
        {
            return getClass().getName()
                + "[name = "+ name
                + ",salary = "+ salary
                + "]";
        }
       
        private String name;
        private double salary;
    }

    class Manager extends Employee
    {
        public Manager(String n, double s)
        {
            super(n, s);
            secretary = null;
        }
       
        /**
         *設置秘書
         */
        public void setSecretary(Employee s)
        {
            secretary = s;
        }
       
        public String toString()
        {
            return super.toString()
                + "[secretary = "+ secretary
                + "]";
        }
       
        //secretary代表秘書
        private Employee secretary; 
    }

    修改默認的序列化機制:   

          在序列化的過程中,有些數據字段我們不想將其序列化,對于此類字段我們只需要在定義時給它加上transient關鍵字即可,對于transient字段序列化機制會跳過不會將其寫入文件,當然也不可被恢復。但有時我們想將某一字段序列化,但它在SDK中的定義卻是不可序列化的類型,這樣的話我們也必須把他標注為transient,可是不能寫入又怎么恢復呢?好在序列化機制為包含這種特殊問題的類提供了如下的方法定義:

    private void readObject(ObjectInputStream in) throws

             IOException, ClassNotFoundException;

    private void writeObject(ObjectOutputStream out) throws

             IOException;

    (注:這些方法定義時必須是私有的,因為不需要你顯示調用,序列化機制會自動調用的)

    使用以上方法我們可以手動對那些你又想序列化又不可以被序列化的數據字段進行寫出和讀入操作。

          下面是一個典型的例子,java.awt.geom包中的Point2D.Double類就是不可序列化的,因為該類沒有實現Serializable接口,在我的例子中將把它當作LabeledPoint類中的一個數據字段,并演示如何將其序列化!

    import java.io.*;
    import java.awt.geom.*;

    public class TransientTest
    {
        public static void main(String[] args)
        {
            LabeledPoint label = new LabeledPoint("Book", 5.00, 5.00);
            try
            {
                System.out.println(label);//寫入前
                ObjectOutputStream out = new ObjectOutputStream(new
                    FileOutputStream("Label.txt"));
                out.writeObject(label);
                out.close();
               
                System.out.println(label);//寫入后
               
                ObjectInputStream in = new ObjectInputStream(new
                    FileInputStream("Label.txt"));
                LabeledPoint label1 = (LabeledPoint)in.readObject();
                in.close();
                System.out.println(label1);//讀出并加1.0后
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
       
    }

    class LabeledPoint implements Serializable
    {
        public LabeledPoint(String str, double x, double y)
        {
            label = str;
            point = new Point2D.Double(x, y);
        }
       
        private void writeObject(ObjectOutputStream out) throws IOException
        {
            /**
             *必須通過調用defaultWriteObject()方法來寫入
             *對象的描述以及那些可以被序列化的字段
             */
            out.defaultWriteObject();
            out.writeDouble(point.getX());
            out.writeDouble(point.getY());
        }
       
        private void readObject(ObjectInputStream in)
            throws IOException, ClassNotFoundException
        {
            /**
             *必須調用defaultReadObject()方法
             */
            in.defaultReadObject();
            double x = in.readDouble() + 1.0;
            double y = in.readDouble() + 1.0;
            point = new Point2D.Double(x, y);
        }
       
        public String toString()
        {
            return getClass().getName()
                + "[label = "+ label
                + ", point.getX() = "+ point.getX()
                + ", point.getY() = "+ point.getY()
                + "]";
        }
       
        private  String label;
        transient private Point2D.Double point;
    }

    http://dev.csdn.net/article/31/31306.shtm

    posted on 2005-10-06 00:25 weidagang2046 閱讀(246) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 中文精品人人永久免费| 一级片在线免费看| 最近免费2019中文字幕大全| 国产偷v国产偷v亚洲高清| 成在人线av无码免费高潮水| 国产亚洲av片在线观看16女人| 国产午夜无码片免费| 亚洲欧洲免费视频| **毛片免费观看久久精品| 亚洲伊人久久大香线蕉影院| 日本亚洲免费无线码| 亚洲高清国产拍精品熟女| 国产人妖ts在线观看免费视频| 羞羞漫画在线成人漫画阅读免费| 亚洲av中文无码| a级毛片黄免费a级毛片| 91天堂素人精品系列全集亚洲| 国产成人精品免费视频网页大全| 亚洲伊人久久大香线蕉结合| 欧洲黑大粗无码免费| 国产亚洲精品第一综合| 亚洲精品乱码久久久久久久久久久久 | 亚洲国产一区二区三区在线观看| 国产大片91精品免费看3| 一级做a爱片特黄在线观看免费看| 亚洲色大成网站WWW久久九九| 久久99精品视免费看| 色老板亚洲视频免在线观| 免费h成人黄漫画嘿咻破解版| 精精国产www视频在线观看免费| 亚洲午夜久久影院| 免费看大黄高清网站视频在线| 国产精品99爱免费视频| 久久久无码精品亚洲日韩京东传媒| 破了亲妺妺的处免费视频国产| 成人av片无码免费天天看| 亚洲午夜精品一区二区公牛电影院 | 亚洲AV成人无码天堂| 亚洲午夜爱爱香蕉片| 免费v片在线观看视频网站| 免费观看亚洲人成网站|