Java SerializableExternalizable实现序列化反序列化-实例-statictransient修饰的变量不会被序列化

Posted 二十六画生的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java SerializableExternalizable实现序列化反序列化-实例-statictransient修饰的变量不会被序列化相关的知识,希望对你有一定的参考价值。

在JAVA中,对象的序列化和反序列化被广泛的应用到RMI(远程方法调用)及网络传输中。

实现Serializable接口 和实现Externalizable接口实现序列化、反序列化的区别:

1 类实现Serializable接口不用实现方法;类实现Externalizable接口需要实现writeExternal,readExternal方法,不然反序列后的对象不含有属性值,都是默认的初始值

2 类实现Serializable接口时无参构造函数和带参构造函数可以同时写,也可以不同时写(只写一个或都不写均可);类实现Externalizable接口时如果写了带参构造函数,则必须要写无参构造函数,不然报错

3 如果不实现Serializable 则 报错Exception in thread "main" java.io.NotSerializableException: 类路径和类名

4 无static修饰是对象属性,只用transient修饰,不序列化,反序列化后是默认值
5 有static修饰是类属性,不序列化,反序列化后是最新值
6 有static、transient同时修饰时,仍然是当作类属性处理

transient变量不会贯穿对象的序列化和反序列化,生命周期仅存于调用者的内存中而不会写到磁盘里进行持久化。

---------------------------

首先介绍一下序列化Serializable

通常一个类实现序列化方式是实现序列化接口:   class XXX implements Serializable

序列化的作用:把数据长久的保存在磁盘中,磁盘和内存是不同的,内存一般在程序运行时占用,数据保存周期短,随程序结束而结束,磁盘可以长久保存数据

transient关键字的作用,在已实现序列化的类中,有的变量不需要保存在磁盘中,就要transient关键字修饰,如银行卡密码等,就这个作用------在已序列化的类中使变量不序列化

---------------------------

1 实现Serializable接口 

package com.company;

/**
 * Title:
 *
 * @Author
 * @CreateTime 2019/6/3 16:04
 */

import java.io.Serializable;

public class User1 implements Serializable 
//public class User1 
//报错Exception in thread "main" java.io.NotSerializableException: Serializable.User1


    private String name;
    private int 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;
    

    @Override
    public String toString() 
        return "User1" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '';
    
package com.company;

/**
 * Title:
 *
 * @Author
 * @CreateTime 2019/6/3 16:05
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo1 

    public static void main(String[] args) throws Exception, IOException 
        //初始化对象
        User1 user = new User1();
        user.setName("lisi");
        user.setAge(22);
        System.out.println(user);
        //序列化对象到文件中
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template2"));
        oos.writeObject(user);
        oos.close();
        //反序列化
        File file = new File("template2");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        User1 newUser = (User1) ois.readObject();
        System.out.println(newUser);
    


输出:

User1name='lisi', age=22
User1name='lisi', age=22

如果类User1中只有一个构造函数(带两个参数),没有无参构造函数,依然能正常序列化和反序列化。

2.1实现Externalizable

package com.company;

/**
 * Title:
 *
 * @Author
 * @CreateTime 2019/6/3 16:04
 */

import java.io.*;

public class User1 implements Externalizable 

    private String name;
    private int 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;
    

    @Override
    public String toString() 
        return "User1" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '';
    

    @Override
    public void writeExternal(ObjectOutput out) throws IOException 

    

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException 

    

用1中同样的main方法,输出如下:

User1name='lisi', age=22
User1name='null', age=0

需要自己实现方法中的细节!

Externalizable继承了Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。

2.2 User1类的实现方法修改为如下:

    @Override
    public void writeExternal(ObjectOutput out) throws IOException 
        out.writeObject(name);
        out.writeInt(age);

    

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException 
        name = (String) in.readObject();
        age = in.readInt();

    

输出:

User1name='lisi', age=22
User1name='lisi', age=22

如果类User1中只有一个构造函数(带两个参数),没有无参构造函数,依然能正常序列化,但是反序列化时报错。

3 static修饰的变量不会被序列化

package com.company;

import java.io.*;

public class Main implements Serializable 

    private static final long serialVersionUID = 1L;

    public static int staticVar = 5;

    public static void main(String[] args) 
        try 
            //初始时staticVar为5
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("result.obj"));
            out.writeObject(new Main());
            out.close();

            //序列化后修改为10
            Main.staticVar = 10;

            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                    "result.obj"));
            Main t = (Main) oin.readObject();
            oin.close();

            //再读取,通过t.staticVar打印新的值
            System.out.println(t.staticVar);

         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        
    

//10 




import java.io.*;

public class Main24 implements Serializable 

    private static final long serialVersionUID = 1L;

    public static int staticVar = 5;//类属性,不序列化,反序列化后是最新值

    public static void main(String[] args) 
        try 
            //初始时staticVar为5
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("result.obj"));
            out.writeObject(new Main24());
            out.close();

            //原对象序列化后修改为10
            //Main24.staticVar = 10;//类属性,不序列化,反序列化后是最新值

            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                    "result.obj"));
            Main24 t = (Main24) oin.readObject();
            oin.close();

            //再读取,通过t.staticVar打印新的值
            System.out.println(t.staticVar);

         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        
    

//5



public class Main24 implements Serializable 

    private static final long serialVersionUID = 1L;

    public static transient int staticVar = 5;//类属性,不序列化,反序列化后是最新值

    public static void main(String[] args) 
        try 
            //初始时staticVar为5
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("result.obj"));
            out.writeObject(new Main24());
            out.close();

            //序列化后修改为10
            //Main24.staticVar = 10;

            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                    "result.obj"));
            Main24 t = (Main24) oin.readObject();
            oin.close();

            //再读取,通过t.staticVar打印新的值
            System.out.println(t.staticVar);

         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        
    

//5





import java.io.*;

public class Main24 implements Serializable 

    private static final long serialVersionUID = 1L;

    public transient int staticVar = 5;//对象属性,只用transient,不序列化,反序列化后是默认值值0

    public static void main(String[] args) 
        try 
            //初始时staticVar为5
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("result.obj"));
            out.writeObject(new Main24());
            out.close();

            //序列化后修改为10
            //Main24.staticVar = 10;

            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                    "result.obj"));
            Main24 t = (Main24) oin.readObject();
            oin.close();

            //再读取,通过t.staticVar打印新的值
            System.out.println(t.staticVar);

         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        
    

//0



序列化时,并不保存静态变量,这其实比较容易理解,序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。

Java序列化是不能序列化static变量的,因为其保存的是对象的状态,而static变量保存在全局数据区,在对象未实例化时就已经生成,属于类的状态。

这正是因为我们并没有序列化static变量,所以它并没有被写入流中,所以当我们要读取test的值时,它不可能在反序列化的文件里找到新的值,而是去全局数据区取值

参考:Java序列化与static_YXY_1989的博客-CSDN博客_static序列化

4 transient修饰的变量不会被序列化

Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

package com.company;

/**
 * Title:
 *
 * @Author
 * @CreateTime 2019/6/3 16:04
 */

import java.io.*;

public class User1 implements Serializable 

    private String name;
    private int age;
    private transient String t1;
    private transient Integer t2;
    private transient int t3;

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

    public void setAge(int age) 
        this.age = age;
    

    public void setT1(String t1) 
        this.t1 = t1;
    

    public void setT2(Integer t2) 
        this.t2 = t2;
    

    public void setT3(int t3) 
        this.t3 = t3;
    

    @Override
    public String toString() 
        return "User1" +
                "name='" + name + '\\'' +
                ", age=" + age +
                ", t1='" + t1 + '\\'' +
                ", t2=" + t2 +
                ", t3=" + t3 +
                '';
    
package com.company;

/**
 * Title:
 *
 * @Author
 * @CreateTime 2019/6/3 16:05
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo1 

    public static void main(String[] args) throws Exception, IOException 
        //初始化对象
        User1 user = new User1();
        user.setName("lisi");
        user.setAge(22);
        user.setT1("T1");
        user.setT2(23);
        user.setT3(24);
        System.out.println(user);
        //序列化对象到文件中
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template1"));
        oos.writeObject(user);
        oos.close();
        //反序列化
        File file = new File("template1");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        User1 newUser = (User1) ois.readObject();
        System.out.println(newUser);
    


输出:

User1name='lisi', age=22, t1='T1', t2=23, t3=24
User1name='lisi', age=22, t1='null', t2=null, t3=0

参考:Java对象的序列化(Serialization)和反序列化详解_艾米莉Emily的博客-CSDN博客_对象序列化和反序列化

以上是关于Java SerializableExternalizable实现序列化反序列化-实例-statictransient修饰的变量不会被序列化的主要内容,如果未能解决你的问题,请参考以下文章

Java 布尔运算

java [Java] Java常用代码#java

Java - 35 Java 实例

Java While 循环

Java 字符串

Java If ... Else