精华内容
下载资源
问答
  • java 序列化

    2018-06-21 16:19:25
    java 序列化java 序列化java 序列化java 序列化java 序列化java 序列化
  •  Java中的序列化(serialization)机制能够将一个实例对象的状态信息写入到一个字节流中,使其可以通过socket进行传输、或者持久化存储到数据库或文件系统中;然后在需要的时候,可以根据字节流中的信息来重构一个...
  • Java序列化Jar包

    2018-01-16 10:00:23
    该资源提供了java常见的三个序列化框架,分别是:JBoss Marshalling,messagePack,protobuf-java
  • java序列化对象传给php

    2016-01-17 07:23:47
    android(包括java)序列化一个对象传给php去做处理,或是接到php的序列化的对象在java中做处理的工具jar包以及使用方法. 使用方法: byte[] b = null; b = PHPSerializer.serialize(一个对象);//将一个对象序列化后返回...
  • Java 序列化与反序列化

    千次阅读 2020-09-05 13:04:20
    介绍 Java序列化与反序列化

    Java 序列化与反序列化


    1 序列化与反序列化的概念

    • Java 序列化是指:将对象转化成一个字节序列(二进制数据)的过程。

    • 将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化。

    • Java 反序列化是指:将一个对象的字节序列恢复成 Java 对象的过程。

    • 一个平台中序列化的对象,可以在另一个平台中进行反序列化,因为这个过程是在 JVM 中独立完成的,可以依赖于 Java 的可移植性。


    2 核心类与关键字总览

    • ObjectOutputStream:IO 类,包含序列化对象的方法,writeObject()

    • ObjectInputStream:IO 类,包含反序列化对象的方法,readObject()

    • 上面两个 IO 流类是高层次的数据库,需要借助文件流进行序列化与反序列化操作。

    • Serializable ,接口,是一个标志性接口,标识可以在 JVM 中进行序列化,JVM 会为该类自动生成一个序列化版本号。参与序列化与反序列化的类必须实现 Serializable 接口。

    • serialVersionUID,类属性,序列化版本号,用于给 JVM 区别同名类,没有提供版本号,JVM会默认提供序列化版本号。

    • transient,关键字,当序列化时,不希望某些属性参与,则可以使用这个关键字标注该属性。


    3 序列化与反序列化的过程

    • 内存中的数据信息被拆分成一小块一小块的部分,为每个小块设置编号,然后存放到硬盘文件中,也就是将 Java 对象对象的状态保存下来存储到文件中的过程就叫做序列化。

    • 将硬盘中保存了 Java 对象状态的字节序列按照编号组装成对象恢复到内存中,这个过程称为反序列化。


    3 应用示例

    参与序列化和反序列化的 Java 类

    public class Student implements Serializable {
        private String name;
        private int age;
        //  以下省略有参构造、无参构造、set、get、toString
    }
    
    • 参与序列化和反序列化的类必须实现 Serializable 接口。

    序列化操作

    public static void main(String[] args) throws Exception {
        //  创建 Java 对象
        Student student = new Student("张三",22);
        //  对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student"));
        // 使用 writeObject 序列化对象
        oos.writeObject(student);
        // 刷新
        oos.flush();
        //  关闭流
        oos.close();
    }
    
    • 序列化后的二进制文件会被保存到文件输出流指定的路径。

    反序列化操作

    public static void main(String[] args) throws Exception {
        //  对象输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student"));
        //  使用 readObject() 反序列化  
        Object obj = ois.readObject();
        //  使用对象
        System.out.println(obj);
        //  关闭流
        ois.close();
    }
    
    • 反序列化需要借助文件输入流读取指定路径的二进制文件。

    4 序列化版本号的作用 serialVersionUID

    • JVM 首先会通过类名来区分 Java 类,类名不同,则不是同一个类。当类名相同时,JVM 就会通过序列化版本号来区分 Java 类,如果序列化版本号相同就为同一个类,序列化版本号不同就为不同的类。

    • 在序列化一个对象时,如果没有指定序列化版本号,后期对该类的源码进行修改并重新编译后,会导致修改前后的序列化版本号不一致,因为 JVM 会提供一个新的序列化版本号给该类对象。

    • 此时再用以往的反序列化代码去反序列化该类的对象,就会抛出异常 java.io.InvalidClassException ,所以序列化一个类时最好指定一个序列化版本号,或者永远不修改此类。

    public class Student implements Serializable {
        private static final Long serialVersionUID = 1L;
    }
    
    • 由 JVM 提供序列化版本号的好处是,同名却不同功能的类,会有两个不同的序列化版本号,JVM 可以通过序列化版本号加以区分,缺点是一旦修改源码,会重新提供序列化版本号,导致修改前后的序列化版本号不一致,进行反序列化时会出现运行出现异常。

    • 由 开发人员 手动提供序列化版本号的好处是,当修改了被序列化类的源码后,以往写的反序列化代码依然可以使用,如 JDK 中的 String 类。以便后期进行增强和维护不会影响使用。

    在这里插入图片描述


    5 transient 关键字

    • 这个关键字表示游离的,不参与序列化的。

    • 在序列化一个对象时,如果不希望某个属性参加序列化,可以使用 transient 修饰该属性。

    • 被该关键字修饰的属性不会参与到序列化中。

    public class Student implements Serializable {
    
        private static final Long serialVersionUID = 1L;
    
        private String name;
        private transient int age;
    }
    
    • 如上类,在序列化时就不会保存 age 属性,在反序列化时就不能会付出该属性,默认恢复成 null 或 0 ,由属性类型决定。

    6 序列化的好处及应用场景

    • 序列化会将内存中对象的状态转换成二进制文件保存到磁盘当中,当再次使用时会从磁盘中读取该二进制文件,将 Java 对象的状态恢复到内存中。

    • 当你想把内存中的对象保存到磁盘文件或数据库中时可以使用序列化。

    • 当你想在网络传输中传送 Java 对象时,可以使用序列化。

    • 当你想通过 RMI 传输对象时,可以使用序列化。


    7 序列化注意事项

    • 序列化只会保存对象的属性状态,不会保存对象中的方法。

    • 父类实现了 Serializable 接口,则其子类也自动实例化了该接口,也就是说子类不用显式实现 Serializable 接口也能参与序列化和反序列化。

    • 一个对象 A 的实例变量引用了其他对象 B,在 A 对象实例化的过程中 ,也会序列化 B ,前提是 A、B 两个类都实现了 Serializable 接口。

    • 当一个类实现 Serializable 接口时,最好手动指定一个序列化版本号(serialVersionUID),避免修改源代码后导致反序列化出现异常。

    • 当一个类对象会被多次重复使用,且一般不会对其属性做修改,就可以对其进行序列化。例如数据库操作中的实体类。


    参考博文:

    展开全文
  • 主要介绍了Java 序列化和反序列化实例详解的相关资料,需要的朋友可以参考下
  • java序列化和反序列化,面试必备

    千次阅读 多人点赞 2020-04-26 17:04:19
    意义:序列化机制允许将实现序列化Java对象转换为字节序列,并将字节序列保存在磁盘中,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使地对象可以脱离程序的运行而独立存在。 使用场景:所有在网络上...

    最近阅读Serializable接口和Externalizable接口的源码,并结合了一些资料,对面试过程中与序列化相关的内容做了一些总结。
    一、序列化、反序列化、使用场景、意义。
    序列化:将对象写入IO流中;
    反序列化:从IO流中恢复对象
    意义:序列化机制允许将实现序列化的Java对象转换为字节序列,并将字节序列保存在磁盘中,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使地对象可以脱离程序的运行而独立存在。
    使用场景所有在网络上传输的对象都必须是可序列化的。如:RMI (远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错。所有必须保存到磁盘的java对象都必须是可序列化的程序创建的JavaBean最好都实现Serializable接口
    二、实现序列化的方式
    实现序列化有两种方式:实现Serializable接口或Externalizable接口,通常情况下,实现Serializable接口即可。两种接口的对比如下:

    实现Serializable接口:
    1) 系统自动存储必要的信息;
    2) Java内建支持,易于实现,只需要实现接口接口,不需要任何代码支持;
    3) 性能略差;
    
    实现Externalizable接口:
    1) 自己决定要序列化哪些属性;
    2) 必须实现该接口内的两个方法:
    void writeExternal(ObjectOutput out) throws IOException;
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
    3) 性能略好;
    

    三、使用Serializable接口实现序列化。
    Serializable接口是一个标记接口,不用实现任何方法,一旦某个类实现了该方法,则该类的对象是可序列化的。
    1、通过以下步骤实现序列化:
    1)创建一个ObjectOutputStream输出流;
    2)调用OjectOutputSteam对象的writeObject ()输出可序列化对象。

    public class Person implements Serializable {
    	private String name;
    	private String age;
    
    	public Person() {
    		System.out.println("调用Person的无参构造函数");
    	}
    
    	public Person(String name, String age) {
    		this.name = name;
    		this.age = age;
    		System.out.println("调用Person的有参构造函数");
    	}
    
    	@Override
    	public String toString() {
    		// TODO 自动生成的方法存根
    		return "Person{'name' :" + name + ",'age' :" + age + "}";
    	}
    }
    
    public class WriteObject {
    	public static void main(String[] args) {
    		try {
    			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Person.txt"));
    			Person p = new Person("baby", "12");
    			oos.writeObject(p);
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    }
    

    输出的序列化文件如下:

    aced 0005 7372 0017 7365 7269 616c 697a
    6162 6c65 5465 7374 2e50 6572 736f 6e4e
    aff9 165f 38dd f602 0002 4c00 0361 6765
    7400 124c 6a61 7661 2f6c 616e 672f 5374
    7269 6e67 3b4c 0004 6e61 6d65 7100 7e00
    0178 7074 0002 3132 7400 0462 6162 79
    

    2、通过以下步骤实现反序列化:
    1)创建一个ObjectInputStream输入流;
    2)调用ObjectInputStream对象的readObject ()得到序列化对象。

    public class WriteObject {
    	public static void main(String[] args) {
    		try {
    			ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Person.txt"));
    			Person p = (Person) ois.readObject();
    			System.out.println(p.toString());
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    }
    

    输出结果如下:

    Person{'name' :baby,'age' :12}
    

    通过输出结果,我们知道反序列化没有调用类的构造方法,而是由JVM自己生成对象。
    3、当类的成员是引用数据类型时
    若一个类的成员不是基本数据类型,也不是String类型的时候,则该成员必须是可序列化的,否则会导致该类无法完成序列化。如下例子所示:

    // 去掉Person类实现的序列化接口
    public class Teacher implements Serializable {
    	private String name;
    	private Person person;
    
    	public Teacher(String name, Person person) {
    		this.name = name;
    		this.person = person;
    	}
    
    	public static void main(String[] args) throws Exception {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Teacher.txt"));
    		Person p = new Person("baby", "16");
    		Teacher t = new Teacher("mom", p);
    		oos.writeObject(t);
    	}
    }
    

    执行时会抛出下面的异常,异常指出,因为Person类不可序列化,导致Teacher类无法完成序列化操作。
    在这里插入图片描述
    4、序列化过程中存在的问题。
    1)同一对象,会被序列化多次吗?
    依次将p、t1、t2、t1序列化到文件SerializableMore中。

    public class WriteMore {
    	public static void main(String[] args) throws Exception {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SerializableMore.txt"));
    		Person p = new Person("baby", "16");
    		Teacher t1 = new Teacher("mom", p);
    		Teacher t2 = new Teacher("dad", p);
    
    		oos.writeObject(p);
    		oos.writeObject(t1);
    		oos.writeObject(t2);
    		oos.writeObject(t1);
    	}
    }
    

    接下来将反序列化文件SerializableMore。

    public class ReadMore {
    	public static void main(String[] args) throws Exception {
    		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("SerializableMore.txt"));
    		
    		// 注意:反序列化的顺序和序列化时的顺序一致
    		Person p = (Person) ois.readObject();
    		Teacher t1 = (Teacher) ois.readObject();
    		Teacher t2 = (Teacher) ois.readObject();
    		Teacher t3 = (Teacher) ois.readObject();
    
    		System.out.println("t1 == t2 ---------------------------->" + (t1 == t2));
    		System.out.println("t1.getPerson() == p ----------------->" + (t1.getPerson() == p));
    		System.out.println("t2.getPerson() == p ----------------->" + (t2.getPerson() == p));
    		System.out.println("t2 == t3 ---------------------------->" + (t2 == t3));
    		System.out.println("t1.getPerson() == t2.getPerson() ---->" + (t1.getPerson() == t2.getPerson()));
    	}
    }
    

    输出结果如下所示:

    t1 == t2 ---------------------------->false
    t1.getPerson() == p ----------------->true
    t2.getPerson() == p ----------------->true
    t2 == t3 ---------------------------->false
    t1.getPerson() == t2.getPerson() ---->true
    

    可以看到:针对同一对象进行多次序列化,Java并不会序列化多次,而是沿用第一次序列化获得的序列化编码
    2)由于Java序列化算法不会重复序列化同一个对象,只会记录已序列化对象的序列化编号。而当一个可变的对象中的内容发生改变时,此时进行序列化,却不会重新将此对象转换为字节序列,而是保存序列化编号。如下所示。

    public class WirteOnChange {
    	public static void main(String[] args) throws Exception {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("WriteOnchange.txt"));
    		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("WriteOnchange.txt"));
    
    		Person person = new Person("索隆", "20");
    		System.out.println("修改前:" + person.toString());
    		oos.writeObject(person);
    
    		person.setName("香吉士");
    		System.out.println("修改后:" + person.toString());
    		oos.writeObject(person);
    		
    		Person p1 = (Person) ois.readObject();
    		Person p2 = (Person) ois.readObject();
    		
    		System.out.println(p1 == p2);
    		System.out.println(p1.getName().equals(p2.getName()));
    	}
    }
    

    输出结果如下:

    修改前:Person{'name' :索隆,'age' :20}
    修改后:Person{'name' :香吉士,'age' :20}
    true
    true
    

    5、Java序列化算法

    1)所有保存到磁盘的对象都有一个序列化编号;
    2)当试图序列化一个对象时,会先检查该对象是否已经序列化过,只有该对象未被JVM序列化过,才会将该对象序列化为字节序列输出;
    3)如果此对象已经被序列化过,则直接输出序列化编码号即可。
    

    如下图所示:
    在这里插入图片描述
    6、可选的自定义序列化
    1)使用transient关键字指定不进行序列化的字段。
    使用transient修饰的属性,java序列化时会忽略该属性。而当反序列化时,被transient修饰的属性则赋予默认值对于引用类型则为nullboolean类型为false,基本类型为0

    public class Teacher implements Serializable {
    	private String name;
    	private transient String age;
    	private transient int height;
    	private Person person;
    	
    	public Teacher(String name, String age, int height, Person person) {
    		this.name = name;
    		this.age = age;
    		this.height = height;
    		this.person = person;
    	}
    	// ...省略getter、setter方法
    
    public class WirteOnChange {
    	public static void main(String[] args) throws Exception {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"));
    		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("teacher.txt"));
    
    		Person person = new Person("索隆", "20");
    		Teacher teacher = new Teacher("鹰眼", "30", 190, person);
    		
    		System.out.println("序列化之前:" + teacher.toString());
    		oos.writeObject(teacher);
    
    		Teacher t1 = (Teacher) ois.readObject();
    
    		System.out.println("序列化之后:" + t1.toString());
    	}
    }
    

    输出结果如下所示:

    序列化之前:Teacher{"name" : "鹰眼"; "age" : "30"; "height" : 190; "person" : Person{'name' :索隆,'age' :20}
    序列化之后:Teacher{"name" : "鹰眼"; "age" : "null"; "height" : 0; "person" : Person{'name' :索隆,'age' :20}
    
    

    2)通过下面的方法可以实现自定义序列化,可以控制序列化的方式或对序列化数据进行编码加密等。

    private void writeObject(java.io.ObjectOutputStream out) throws IOException
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
    private void readObjectNoData() throws ObjectStreamException;
    

    通过重写writeObject()readObject()方法,可选择哪些属性要序列化。如果writeObject使用了某种规则进行序列化,则readObject要使用相反的规则进行反序列化,以便能正确反序列化对象。

    // 对字符串name进行反转加密
    public class Person implements Serializable {
    	private String name;
    	private String age;
    	private int height;
    	
    	// 省略构造函数和getter、setter方法
    
    	private void WriteObject(ObjectOutputStream oos) throws IOException {
    		oos.writeObject(new StringBuilder(this.name).reverse()); // 利用StringBuilder实现字符串反转
    		oos.writeInt(height);
    	}
    
    	private void ReadObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    		this.name = ((StringBuilder) ois.readObject()).reverse().toString();
    		this.height = ois.readInt();
    	}
    

    当序列化流不完整时,readObjectNoData()方法可以正确地初始化反序列化的对象。例如,使用不同类接收反序列化对象,或者序列化流被篡改,系统都会调用readObjectNoData()来初始化反序列化对象。
    3)彻底的自定义序列化
    以下两个方法会在序列化前或反序列化后自动调用,可以实现更加彻底的自定义序列化。

    ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
    ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
    

    writeReplace()方法:在序列化前,会先调用该方法,再调用writeObject方法。此方法可以使用任意对象代替目标序列化对象。

    public class Person implements Serializable {
    	private String name;
    	private String age;
    	
    	// 省略构造方法、getter和setter方法
    
    	private Object writeReplace() throws ObjectStreamException {
    		ArrayList<String> list = new ArrayList<>();
    		list.add(this.name);
    		list.add(this.age);
    		return list;
    	}
    	
    	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
    		ObjectInputStream ios = new ObjectInputStream(new FileInputStream("person.txt"));
    
    		Person person = new Person("罗宾", "18");
    		oos.writeObject(person);
    
    		ArrayList<String> list = (ArrayList) ios.readObject();
    		System.out.println(list);
    	}
    

    输出结果如下:

    [罗宾, 18]
    

    readResolve()方法:替代反序列化输出的对象,反序列化出来的对象会被立即丢弃,此方法在readObject()后调用。

    public class Person implements Serializable {
    	private String name;
    	private String age;
    	private int height;
    	
    	// 省略构造方法、getter和setter方法
    	
    	private Object readResolve() throws ObjectStreamException {
    		return new Person("娜美", "23");
    	}
    	
    	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
    		ObjectInputStream ios = new ObjectInputStream(new FileInputStream("person.txt"));
    
    		Person person = new Person("罗宾", "18");
    		oos.writeObject(person);
    
    		Person p1 = (Person) ios.readObject();
    		System.out.println(p1);
    	}
    

    输出结果如下:

    Person{'name' :娜美,'age' :23}
    

    四、使用Externalizable接口实现序列化。
    Externalizable接口不同于Serializable接口,该接口需要强制重写两个方法。

    public interface Externalizable extends java.io.Serializable {
        void writeExternal(ObjectOutput out) throws IOException;
        void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
    }
    

    测试程序如下:

    public class PersonExternal implements Externalizable {
    	private String name;
    	private int age;
    
    	// 必须提供无参构造函数
    	public PersonExternal() {
    		System.out.println("调用无参构造方法!!");
    	}
    
    	public PersonExternal(String name, int age) {
    		this.name = name;
    		this.age = age;
    	}
    
    	@Override
    	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    		// 将读取的字符串反转后赋值给name实例变量
    		this.name = ((StringBuilder) in.readObject()).reverse().toString();
    		System.out.println("将name按相同的规则反序列化输出:" + name);
    		this.age = in.readInt();
    	}
    
    	@Override
    	public void writeExternal(ObjectOutput out) throws IOException {
    		// 将name反转后写入二进制流
    		StringBuilder reverse = new StringBuilder(name).reverse();
    		System.out.println("将name反转并序列化写入二进制流:" + reverse.toString());
    		out.writeObject(reverse);
    		out.writeInt(age);
    	}
    
    	@Override
    	public String toString() {
    		// TODO 自动生成的方法存根
    		return "Person{'name' :" + name + ", 'age' :" + age + "}";
    	}
    
    	public static void main(String[] args) throws Exception {
    		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("PersonExternal.txt"));
    		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PersonExternal.txt"));
    
    		System.out.println("序列化ing");
    		oos.writeObject(new PersonExternal("cindy", 23));
    
    		System.out.println("反序列化ing");
    		PersonExternal pe = (PersonExternal) ois.readObject();
    
    		System.out.println(pe.toString());
    	}
    
    }
    

    输出结果:

    序列化ing
    将name反转并序列化写入二进制流:ydarb
    反序列化ing
    调用无参构造方法!!
    将name按相同的规则反序列化输出:brady
    Person{'name' :brady, 'age' :23}
    

    可以看到的是,实现Externalizable接口必须提供public的无参构造器,因为在反序列化的时候需要通过反射创建对象。
    五、序列化版本号serialVersionUID 。
    介绍了那么多关于序列化的内容,我们知道,反序列必须要有class文件,但随着项目的升级,class文件也会随之升级。那么,序列化怎么保证升级前后的兼容性呢?
    Java序列化提供了一个serializableVersionUID的序列化版本号,只要版本号相同,即使更改了序列化属性,对象也可以被正确地反序列化回来。

    public class Person implements Serializable {
    	// 序列化版本号
    	private static final long serialVersionUID = 1227593270102525184L;
    	
    	private String name;
    	private String age;
    	private int height;
    

    但是,如果反序列化使用的class的版本号与序列化时使用的不一致,反序列化会报InvalidClassException异常。
    在这里插入图片描述序列化版本号可自由指定,如果不指定,JVM会根据类信息自己计算一个版本号,这样随着class的升级,就无法正确反序列化;
    不指定版本号另一个明显隐患是,不利于jvm间的移植,可能class文件没有更改,但不同jvm可能计算的规则不一样,这样也会导致无法反序列化。
    接下来列出几种序列化的情况:

    a) 只是修改了方法,反序列化不影响,则无需修改版本号
    b) 只是修改了静态变量,瞬态变量(transient修饰的变量),反序列化不受影响,无需修改版本号
    c) 修改了非瞬态变量,则可能导致反序列化失败。如果新类中实例变量的类型与序列化时类的类型不一致,则会反序列化失败,这时候需要更改serialVersionUID。如果只是新增了实例变量,则反序列化回来新增的是默认值;
    

    六、总结 。

    a) 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
    b) 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。
    c) 如果想让某个变量不被序列化,使用transient修饰。
    d) 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
    e) 反序列化时必须有序列化对象的class文件。
    f) 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
    g) 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
    i) 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
    j) 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。
    k) 数组不能显式地声明serialVersionUID,因为它们始终都有默认的计算值,但是对于数组类,无需匹配serialVersionUID。
    l) 可以通过序列化和反序列化的方式实现对象的深复制。
    
    展开全文
  • 面试题 - Java序列化和反序列化

    千次阅读 2020-09-15 18:03:22
    Java 序列化的高级认识 引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口,使用 ...

    Java 序列化的高级认识

    1.Java序列化,反序列化
    Java序列化指将Java对象转换为字节序列的过程,反序列化指将字节序列转换为目标对象的过程;
    2.什么情况下需要序列化
    当Java对象需要网络传输或者持久化到磁盘上时;
    3.序列化的实现?
    让类实现Serializable接口,标注该类对象可以被序列化;

    引言

    将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 进行对象的读写。然而在有些情况下,光知道这些还远远不够,文章列举了笔者遇到的一些真实情境,它们与 Java 序列化相关,通过分析情境出现的原因,使读者轻松牢记 Java 序列化中的一些高级认识。

    文章结构(背5点)

    本文将逐一的介绍几个情境,顺序如下面的列表。

    1. 序列化 ID 的问题
    2. 静态变量序列化
    3. 父类的序列化与 Transient 关键字
    4. 对敏感字段加密
    5. 序列化存储规则
      列表的每一部分讲述了一个单独的情境,读者可以分别查看。

    1.序列化 ID 问题

    情境 :两个客户端 A 和 B 试图通过网络传递对象数据,A 端将对象 C 序列化为二进制数据再传给 B,B 反序列化得到 C。

    问题 :C 对象的全类路径假设为 com.inout.Test,在 A 和 B 端都有这么一个类文件,功能代码完全一致。也都实现了 Serializable 接口,但是反序列化时总是提示不成功。

    解决 : 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L) 。清单 1 中,虽然两个类的功能代码完全一致,但是序列化 ID 不同,他们无法相互序列化和反序列化。

    清单 1. 相同功能代码不同序列化 ID 的类对比

    package com.inout;
    
     import java.io.Serializable;
    
     public class A implements Serializable {
    
         private static final long serialVersionUID = 1L;
    
         private String name;
    
         public String getName()
         {
             return name;
         }
    
         public void setName(String name)
         {
             this.name = name;
         }
     }
    
     package com.inout;
    
     import java.io.Serializable;
    
     public class A implements Serializable {
    
         private static final long serialVersionUID = 2L;
    
         private String name;
    
         public String getName()
         {
             return name;
         }
    
         public void setName(String name)
         {
             this.name = name;
         }
     }
    

    序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。

    特性使用案例

    读者应该听过 Façade 模式【提供一组统一的接口,使子系统更易用,可以解决:1.易用性(封装底层数据,对外暴露简单接口);2.性能问题(需要访问3次的接口,用一个接口分装,解决交互性能问题);3.解决分布式事务问题(一次请求需要两个模块操作共同成功,共同失败,直接封装到一个接口解决问题)】,它是为应用程序提供统一的访问接口,案例程序中的 Client 客户端使用了该模式,案例程序结构图如图 1 所示。

    图 1. 案例程序结构
    在这里插入图片描述
    Client 端通过 Façade Object 才可以与业务逻辑对象进行交互。而客户端的 Façade Object 不能直接由 Client 生成,而是需要 Server 端生成,然后序列化后通过网络将二进制对象数据传给 Client,Client 负责反序列化得到 Façade 对象。该模式可以使得 Client 端程序的使用需要服务器端的许可,同时 Client 端和服务器端的 Façade Object 类需要保持一致。当服务器端想要进行版本更新时,只要将服务器端的 Façade Object 类的序列化 ID 再次生成,当 Client 端反序列化 Façade Object 就会失败,也就是强制 Client 端从服务器端获取最新程序。

    2.静态变量序列化

    情境 :查看清单 2 的代码。

    清单 2. 静态变量序列化问题代码

    public class Test 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 Test());
                out.close();
    
                //序列化后修改为10
                Test.staticVar = 10;
    
                ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                        "result.obj"));
                Test t = (Test) 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();
            }
        }
    }
    

    清单 2 中的 main 方法,将对象序列化后,修改静态变量的数值,再将序列化对象读取出来,然后通过读取出来的对象获得静态变量的数值并打印出来。依照清单 2,这个 System.out.println(t.staticVar) 语句输出的是 10 还是 5 呢?

    最后的输出是 10,对于无法理解的读者认为,打印的 staticVar 是从读取的对象里获得的,应该是保存时的状态才对。之所以打印 10 的原因在于序列化时,并不保存静态变量,这其实比较容易理解,序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量 。

    3.父类的序列化与 Transient 关键字

    情境 :一个子类实现了 Serializable 接口,它的父类都没有实现 Serializable 接口,序列化该子类对象,然后反序列化后输出父类定义的某变量的数值,该变量数值与序列化时的数值不同。

    解决 : 要想将父类对象也序列化,就需要让父类也实现 Serializable 接口 。如果父类不实现的话的,就 需要有默认的无参的构造函数 。在父类没有实现 Serializable 接口时,虚拟机是不会序列化父对象的,而一个 Java 对象的构造必须先有父对象,才有子对象,反序列化也不例外。所以反序列化时,为了构造父对象,只能调用父类的无参构造函数作为默认的父对象。因此当我们取父对象的变量值时,它的值是调用父类无参构造函数后的值。如果你考虑到这种序列化的情况,在父类无参构造函数中对变量进行初始化,否则的话,父类变量值都是默认声明的值,如 int 型的默认是 0,string 型的默认是 null。

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

    特性使用案例

    我们熟悉使用 Transient 关键字可以使得字段不被序列化,那么还有别的方法吗?根据父类对象序列化的规则,我们可以将不需要被序列化的字段抽取出来放到父类中,子类实现 Serializable 接口,父类不实现,根据父类序列化规则,父类的字段数据将不被序列化,形成类图如图 2 所示。

    图 2. 案例程序类图

    在这里插入图片描述

    上图中可以看出,attr1、attr2、attr3、attr5 都不会被序列化,放在父类中的好处在于当有另外一个 Child 类时,attr1、attr2、attr3 依然不会被序列化,不用重复抒写 transient,代码简洁。

    4.对敏感字段加密

    情境 :服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。

    解决 :在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。基于这个原理,可以在实际应用中得到使用,用于敏感字段的加密工作,清单 3 展示了这个过程。

    清单 3. 静态变量序列化问题代码

    private static final long serialVersionUID = 1L;
    
        private String password = "pass";
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        private void writeObject(ObjectOutputStream out) {
            try {
                PutField putFields = out.putFields();
                System.out.println("原密码:" + password);
                password = "encryption";//模拟加密
                putFields.put("password", password);
                System.out.println("加密后的密码" + password);
                out.writeFields();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void readObject(ObjectInputStream in) {
            try {
                GetField readFields = in.readFields();
                Object object = readFields.get("password", "");
                System.out.println("要解密的字符串:" + object.toString());
                password = "pass";//模拟解密,需要获得本地的密钥
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    
        public static void main(String[] args) {
            try {
                ObjectOutputStream out = new ObjectOutputStream(
                        new FileOutputStream("result.obj"));
                out.writeObject(new Test());
                out.close();
    
                ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                        "result.obj"));
                Test t = (Test) oin.readObject();
                System.out.println("解密后的字符串:" + t.getPassword());
                oin.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    

    在清单 3 的 writeObject 方法中,对密码进行了加密,在 readObject 中则对 password 进行解密,只有拥有密钥的客户端,才可以正确的解析出密码,确保了数据的安全。执行清单 3 后控制台输出如图 3 所示。

    图 3. 数据加密演示

    在这里插入图片描述
    特性使用案例

    RMI 技术是完全基于 Java 序列化技术的,服务器端接口调用所需要的参数对象来至于客户端,它们通过网络相互传输。这就涉及 RMI 的安全传输的问题。一些敏感的字段,如用户名密码(用户登录时需要对密码进行传输),我们希望对其进行加密,这时,就可以采用本节介绍的方法在客户端对密码进行加密,服务器端进行解密,确保数据传输的安全性。

    5.序列化存储规则

    情境 :问题代码如清单 4 所示。

    清单 4. 存储规则问题代码

    ObjectOutputStream out = new ObjectOutputStream(
                        new FileOutputStream("result.obj"));
        Test test = new Test();
        //试图将对象两次写入文件
        out.writeObject(test);
        out.flush();
        System.out.println(new File("result.obj").length());
        out.writeObject(test);
        out.close();
        System.out.println(new File("result.obj").length());
    
        ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                "result.obj"));
        //从文件依次读出两个文件
        Test t1 = (Test) oin.readObject();
        Test t2 = (Test) oin.readObject();
        oin.close();
    
        //判断两个引用是否指向同一个对象
        System.out.println(t1 == t2);
    

    清单 4 中对同一对象两次写入文件,打印出写入一次对象后的存储大小和写入两次后的存储大小,然后从文件中反序列化出两个对象,比较这两个对象是否为同一对象。一般的思维是,两次写入对象,文件大小会变为两倍的大小,反序列化时,由于从文件读取,生成了两个对象,判断相等时应该是输入 false 才对,但是最后结果输出如图 4 所示。

    图 4. 示例程序输出
    在这里插入图片描述
    我们看到,第二次写入对象时文件只增加了 5 字节,并且两个对象是相等的,这是为什么呢?

    解答 :Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得清单 3 中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

    特性案例分析

    查看清单 5 的代码。

    清单 5. 案例代码

    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("result.obj"));
    Test test = new Test();
    test.i = 1;
    out.writeObject(test);
    out.flush();
    test.i = 2;
    out.writeObject(test);
    out.close();
    ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
                        "result.obj"));
    Test t1 = (Test) oin.readObject();
    Test t2 = (Test) oin.readObject();
    System.out.println(t1.i);
    System.out.println(t2.i);
    

    清单 5 的目的是希望将 test 对象两次保存到 result.obj 文件中,写入一次以后修改对象属性值再次保存第二次,然后从 result.obj 中再依次读出两个对象,输出这两个对象的 i 属性值。案例代码的目的原本是希望一次性传输对象修改前后的状态。

    结果两个输出的都是 1, 原因就是第一次写入对象以后,第二次再试图写的时候,虚拟机根据引用关系知道已经有一个相同对象已经写入文件,因此只保存第二次写的引用,所以读取时,都是第一次保存的对象。读者在使用一个文件多次 writeObject 需要特别注意这个问题。

    大神写的非常好,保存一下,引用来源:https://developer.ibm.com/zh/articles/j-lo-serial/

    展开全文
  • java序列化工具

    2018-11-21 09:20:05
    java序列化工具,覆盖jboss、weblogic、websphere。
  • (1)Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程; (2)**序列化:**对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。...

     

    一、基本概念

    1、什么是序列化和反序列化

    (1)Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程;

    (2)**序列化:**对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。

    (3)**反序列化:**客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。

    (4)本质上讲,序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态。

    2、为什么需要序列化与反序列化

    我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。

    那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的!如何做到呢?这就需要Java序列化与反序列化了!

    换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

    当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。

    总的来说可以归结为以下几点:

    (1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;
    (2)通过序列化以字节流的形式使对象在网络中进行传递和接收;
    (3)通过序列化在进程间传递对象;

    3、序列化算法一般会按步骤做如下事情:

    (1)将对象实例相关的类元数据输出。
    (2)递归地输出类的超类描述直到不再有超类。
    (3)类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
    (4)从上至下递归输出实例的数据

    二、Java如何实现序列化和反序列化

    1、JDK类库中序列化和反序列化API

    (1)java.io.ObjectOutputStream:表示对象输出流;

    它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;

    (2)java.io.ObjectInputStream:表示对象输入流;

    它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回;

    2、实现序列化的要求

    只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常!

    3、实现Java对象序列化与反序列化的方法

    假定一个User类,它的对象需要序列化,可以有如下三种方法:

    (1)若User类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化

    ObjectOutputStream采用默认的序列化方式,对User对象的非transient的实例变量进行序列化。
    ObjcetInputStream采用默认的反序列化方式,对对User对象的非transient的实例变量进行反序列化。

    (2)若User类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

    ObjectOutputStream调用User对象的writeObject(ObjectOutputStream out)的方法进行序列化。
    ObjectInputStream会调用User对象的readObject(ObjectInputStream in)的方法进行反序列化。

    (3)若User类实现了Externalnalizable接口,且User类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

    ObjectOutputStream调用User对象的writeExternal(ObjectOutput out))的方法进行序列化。
    ObjectInputStream会调用User对象的readExternal(ObjectInput in)的方法进行反序列化。

    4、JDK类库中序列化的步骤

    步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:

    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\object.out"));
    

    步骤二:通过对象输出流的writeObject()方法写对象:

    oos.writeObject(new User("xuliugen", "123456", "male"));
    

    5、JDK类库中反序列化的步骤

    步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:

    ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));
    

    步骤二:通过对象输出流的readObject()方法读取对象:

    User user = (User) ois.readObject();
    

    说明:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。

    6、序列化和反序列化的示例

    为了更好地理解Java序列化与反序列化,举一个简单的示例如下:

    public class SerialDemo {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
    	    //序列化
            FileOutputStream fos = new FileOutputStream("object.out");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            User user1 = new User("xuliugen", "123456", "male");
            oos.writeObject(user1);
            oos.flush();
            oos.close();
    		//反序列化
            FileInputStream fis = new FileInputStream("object.out");
            ObjectInputStream ois = new ObjectInputStream(fis);
            User user2 = (User) ois.readObject();
            System.out.println(user2.getUserName()+ " " + 
    	        user2.getPassword() + " " + user2.getSex());
            //反序列化的输出结果为:xuliugen 123456 male
        }
    }
    
    public class User implements Serializable {
        private String userName;
        private String password;
        private String sex;
        //全参构造方法、get和set方法省略
    }
    
    

    object.out文件如下(使用UltraEdit打开):

    这里写图片描述

    注:上图中0000000h-000000c0h表示行号;0-f表示列;行后面的文字表示对这行16进制的解释;对上述字节码所表述的内容感兴趣的可以对照相关的资料,查阅一下每一个字符代表的含义,这里不在探讨!

    类似于我们Java代码编译之后的.class文件,每一个字符都代表一定的含义。序列化和反序列化的过程就是生成和解析上述字符的过程!

    序列化图示:

    这里写图片描述

    反序列化图示:

    这里写图片描述

    三、相关注意事项

    1、序列化时,只对对象的状态进行保存,而不管对象的方法;

    2、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

    3、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

    4、并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

    • 安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

    • 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

    5、声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。

    6、序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途:

    • 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

    • 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

    该版本号serialVersionUID在反序列化期间用于验证序列化对象的发送方和接收方是否已加载与该序列化兼容的该对象的类。如果接收者已经为对象加载了一个类,该类serialVersionUID与对应的发送者类的对象不同,那么反序列化将导致一个 InvalidClassException。可序列化类可以serialVersionUID通过声明名为serialVersionUID必须为static,final和type 的字段来显式声明自己的类long:

    ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

    如果可序列化类未显式声明a serialVersionUID,则序列化运行时将serialVersionUID基于类的各个方面计算该类的默认值,如Java(TM)对象序列化规范中所述。但是,强烈建议所有可序列化类显式声明serialVersionUID值,因为默认serialVersionUID计算对类详细信息高度敏感,这些详细信息可能因编译器实现而异,因此InvalidClassExceptions在反序列化期间可能会导致意外。因此,为了保证serialVersionUID跨不同java编译器实现的一致值,可序列化类必须声明一个显式serialVersionUID值。强烈建议明确serialVersionUID声明在可能的情况下使用private修饰符,因为此类声明仅适用于立即声明的类serialVersionUID字段作为继承成员无用。
     

    7、Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;

    8、如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因;

     

    展开全文
  • 本篇文章主要介绍了Java实现几种序列化方式总结,包括Java原生以流的方法进行的序列化、Json序列化、FastJson序列化、Protobuff序列化。有兴趣的可以了解一下。
  • 什么是 java 序列化?什么情况下需要序列化

    万次阅读 多人点赞 2019-06-17 09:34:01
    什么是 java 序列化?什么情况下需要序列化序列化:将 Java 对象转换成字节流的过程。 反序列化:将字节流转换成 Java 对象的过程。 当Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java ...
  • 对象序列化(serialization)和反序列化(deserialization)是将对象转化为便于传输的...java序列化就是将对象转化为字节流,以便在进程或网络之间进行传输,而在接收方,需要以相同的方式对字节流进行反序列化,...
  • java序列化和反序列化以及序列化ID的作用分析

    万次阅读 多人点赞 2017-08-07 20:26:07
    java序列化和反序列化以及序列化ID的作用分析
  • java序列化详解

    万次阅读 多人点赞 2018-08-13 15:45:31
    序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转化成二进制的过程。 即将对象转化为二进制,用于...
  • 一篇搞懂java序列化Serializable

    千次阅读 2018-11-30 16:44:40
    序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。 一、序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化。 把字节序列恢复为对象的过程称为对象的反序列化。 对象的...
  • Java序列化工具.zip

    2019-05-31 16:45:28
    java序列化工具;weblogic反序列化工具;jboss反序列化工具。
  • Java 序列化及解决方案

    千次阅读 2020-06-11 18:14:47
      定义:Java序列化是指把Java对象转换为字节序列的过程;Java反序列化是指把字节序列恢复为Java对象的过程。   解析:简单来说,序列化只针对失血对象,所谓失血对象是指只有属性和getter/setter方法的数据类,...
  • 6种Java序列化框架

    千次阅读 2018-03-23 00:17:06
    下面介绍几种常用的Java序列化技术,耗时比较,单位纳秒0.002511:...
  • Java序列化的几种方式

    千次阅读 2019-04-08 17:44:05
    序列化和反序列化 序列化:可以将对象转化成一个字节序列,便于存储。 反序列化:将序列化的字节序列还原 优点:可以实现对象的”持久性”, 所谓持久性就是指对象的生命周期不取决于程序。 原生序列化方式 序列化...
  • java序列化和反序列化

    千次阅读 2018-07-20 18:26:41
    一:概念 序列化:将对象转化为二进制数据(字节序列)的过程成为序列化;... serialVersionUID:需要序列化的对象的成员属性,表示该对象的序列化版本id,反序列化的接收对象的serialVersionUID必须保持和序列化对...
  • 序列化漫谈 dubbo RPC是dubbo体系中最核心的一种高性能、高吞吐量的远程调用方式,我喜欢称之为多路复用的TCP长连接调用,简单的说: 长连接:避免了每次调用新建TCP连接,提高了调用的响应速度 多路复用:...
  • Java 序列化的几种方式 和反序列化

    千次阅读 2019-04-16 17:19:04
    字节序列:序列化 字节序列–>对象 :反序列化 序列化的用途:把对象的字节序列保存在磁盘上,通常存放在一个文件中;在网络上传送对象的字节序列。 存储在物理磁盘上的:Web服务器中的Session对象。当有 10万...
  • Java 序列化和反序列化(一)Serializable 使用场景 1. 最简单的使用:Serializable 接口 2. 序列化 ID 的问题 3. ...
  • java序列化之writeObject 和readObject

    千次阅读 2020-06-05 15:21:04
    java中,只有类实现了java.io.serializable接口,该类才能被序列化。 示例Demo1.java: package com.example.demo; import java.io.*; public class Demo1 { public static class Person implements S
  • java序列化与非序列化使用场景

    千次阅读 2019-09-25 21:48:00
    一、序列化使用场景 对象的序列化:目的:将一个具体的对象进行持久化,写入到硬盘上。(注意:静态数据不能被序列化,因为静态数据不在堆内存中,而是在静态方法区中) Serializable:用于启动对象的序列化功能,...
  • Java 序列化java开发面试笔试题

    千次阅读 2019-04-30 10:26:45
    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。 扫描二维码或搜索下图红色VX号...Java 序列化 简介 定义 序列化序列化是将对象转换为字节流。 反...
  • 本文主要介绍经典的序列化的实现方式Serializable和序列化被transient修饰的属性。 这里说到两个概念,序列化和反序列化序列化:简单理解就是把程序里面生成的对象以文件的形式保存到本地硬盘中,序列化写入...
  • 几种Java序列化方式的实现

    万次阅读 多人点赞 2017-03-04 11:01:46
    本文主要对几种常见Java序列化方式进行实现。包括Java原生以流的方法进行的序列化、Json序列化、FastJson序列化、Protobuff序列化。 1、Java原生序列化 Java原生序列化方法即通过Java原生流(InputStream和...
  • Kryo序列化与Java序列化

    千次阅读 2018-05-27 23:06:13
    将自定义的类型作为RDD的泛型类型时(比如JavaRDD,Student是自定义类型),所有自定义类型对象,都会进行序列化。因此这种情况下,也要求自定义的类必须实现Serializable接口。 使用可序列化的持久化策略时(比如...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 495,655
精华内容 198,262
关键字:

java序列化

java 订阅