【前面的话】

做项目总是要用到很多东西,遇到一个新的知识,并不是这个知识出来的时间短,而是对于自己来说是新的,所以就需要自己去学习,希望今后可以提高学习的效率。

这篇文章是关于Java 序列化的,选择性阅读。

【知识点】

一、什么叫序列化?

我们都知道对象是暂时保存在内存中的,不能用U盘考走了,有时为了使用介质转移对象,并且把对象的状态保持下来,就需要把对象保存下来,这个过程就叫做序列化,通俗点,就是把人的魂(对象)收伏成一个石子(可传输的介质)。

二、什么叫反序列化?

就是再把介质中的东西还原成对象,把石子还原成人的过程。

三、可能的使用情况

1. 当你想把的内存中的对象写入到硬盘的时候;

比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把它拿出来用,那么这时候就要实现Serializable接口;

2. 当你想用套接字在网络上传送对象的时候;

在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。

3. 当你想通过RMI传输对象的时候;

如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。

四、Serializable接口

  1. Serializable接口:一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。
  2. Serializable实现代码:
 public interface Serializable {
}

可以看出Serializable接口是一个空的接口,目的只有一个就是表示一个类的对象可以被序列化。这个标签是类可以被序列化的特性,表示这个类可以被序列化。

五、Externalizable接口

  1. Externalizable接口:他是Serializable接口的子类
  2. Externalizable实现代码:
 public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

六、Serializable接口和Externalizable接口区别

  1. Serializable:一个对象想要被序列化,那么它的类就要实现此接口,这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。
  2. Externalizable:他是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性;

【学习demo And 解释】

一、Java实现序列化

      1. java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

      2. java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

3. 对象序列化包括如下步骤:

1)创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;

2)通过对象输出流的writeObject()方法写对象。

4. 对象反序列化的步骤如下:

1)创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;

2)通过对象输入流的readObject()方法读取对象。

5. 代码实现:

SerializableTest.java

 import java.io.*;
import java.util.Date; public class SerializableTest { public static void main(String[] args) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objectFile.obj"));
//序列化对象
Customer customer = new Customer("阿蜜果", 24);
out.writeObject("你好!");
out.writeObject(new Date());
out.writeObject(customer);//写入实现了序列化的对象
out.writeInt(123); //写入基本类型数据
out.close();
//反序列化对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("objectFile.obj"));
System.out.println("obj1=" + (String) in.readObject());
System.out.println("obj2=" + (Date) in.readObject());
Customer obj3 = (Customer) in.readObject();
System.out.println("obj3=" + obj3);
int obj4 = in.readInt();
System.out.println("obj4=" + obj4);
in.close();
}
}
class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "name=" + name + ", age=" + age;
}
}

6. 运行结果:

 obj1=你好!
obj2=Thu Apr 03 09:12:09 CST 2014
obj3=name=阿蜜果, age=24
obj4=123

二、Java实现序列化的时候使用关键字

      1. transient是Java语言的关键字,用来表示一个域不是该对象序列化的一部分。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

2. demo代码

其中Password定义为transient型,在输出的时候,就会不被序列化。输出null。

SerializableTest.java

 import java.io.*; 

 public class SerializableTest {
public static void main(String args[]) {
testObjectSeri();
testObjectInSeri();
}
/**
* 对象序列化测试
*/
public static void testObjectSeri() {
Person person = new Person("熔岩", "341022225562156", "lavasoft");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("person.dat");
oos = new ObjectOutputStream(fos);
oos.writeObject(person);
} catch (FileNotFoundException e) {
System.out.println("找不到指定的文件!");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 对象反序列化测试
*/
public static void testObjectInSeri() {
FileInputStream fis = null;
ObjectInputStream ois = null;
Person person = null;
try {
fis = new FileInputStream("person.dat");
ois = new ObjectInputStream(fis);
person = (Person) ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(person.toString());
}
}
/**
* 测试序列化所用的类
*/
class Person implements Serializable {
private String username;
private String cardNumber;
private transient String password;
public Person(String username, String cardNumber, String password) {
this.username = username;
this.cardNumber = cardNumber;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String toString() {
StringBuffer sb = new StringBuffer(this.getClass().getName());
sb.append("[");
sb.append("\n\t");
sb.append("username=" + this.username);
sb.append("\n\t");
sb.append("cardNumber=" + this.cardNumber);
sb.append("\n\t");
sb.append("password=" + this.password);
sb.append("]");
return sb.toString();
}
}

4. 运行结果:

 Person[
username=熔岩
cardNumber=341022225562156
password=null]

【几个问题】

一、序列化版本serialVersionUID

1. serialVersionUID作用:

序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。

类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地定义serialVersionUID有两种用途:

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

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

2. 有两种生成方式:

一个是默认的1L,比如:private static final long serialVersionUID = 1L;

一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:

private static final long serialVersionUID = xxxxL;

当你一个类实现了Serializable接口,如果没有定义serialVersionUID,Eclipse会提供这个 ,提示功能告诉你去定义 。在Eclipse中点击类中warning的图标一下,Eclipse就会自动给定两种生成的方式。如果不想定义它,在Eclipse的设置中也 可以把它关掉的,设置如下:

Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems

将Serializable class without serialVersionUID的warning改成ignore即可。

二、其他说明:

  1. 基本类型的数据可以直接序列化
  2. 对象要被序列化,它的类必须要实现Serializable接口;如果一个类中有引用类型的实例变量,这个引用类型也要实现Serializable接口。

      如果不想让引用类实现Serializable接口,并且让本类成功序列化也可以,使用transient关键字。

【参考资料】

  1. Serializable 作用
  2. Java对象的序列化和反序列化实践
  3. java.io 序列化 总结(一)---Serializable 和 Externalizable 的区别与联系

【后面的话】

随波逐流虽易,努力生活不易,且行且珍惜。

——TT

Java学习笔记(十七)——java序列化的更多相关文章

  1. Java学习笔记十七:Java中static使用方法

    Java中static使用方法 一:Java中的static使用之静态变量: 我们都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立.然而在某些时候,我们更希望该类所有的 ...

  2. Java学习笔记42(序列化流)

    对象中的数据,以流的形式,写入到文件中保存 过程称为写出对象,对象的序列化 ObjectOutputStream将对象写到文件中,实现序列化 在文件中,以流的形式,将对象读取出来, 读取对象,对象的反 ...

  3. Java学习笔记之—Java基础

    将学习到的JAVA基础用xmind记录了下来,需要原件的可以私信

  4. Java学习笔记--通过java.net.URLConnection发送HTTP请求

    http://www.cnblogs.com/nick-huang/p/3859353.html 使用Java API发送 get请求或post请求的步骤: 1. 通过统一资源定位器(java.net ...

  5. java 学习笔记1 java语言概述及开发环境

    高级语言运行机制 高级语言按程序的执行方式分为编译型和解释型两种. java语言比较特殊,Java程序的执行必须经过先编译后解释的步骤. 1 编译生成字节码,只面向JVM(.class) 2Jvm执行 ...

  6. Java 学习笔记 (三) Java 日期类型

    以下内容摘自:  https://www.cnblogs.com/crazylqy/p/4172324.html import java.sql.Timestamp; import java.text ...

  7. JAVA学习笔记之JAVA 对象引用以及赋值

      关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没 ...

  8. 8.4(Java学习笔记)java脚本引擎(Rhino)

    一.java脚本引擎 java脚本引擎是沟通java和脚本语句之间的桥梁,可以通过对应的脚本引擎在java中调用各种脚本语言. 二.脚本引擎执行脚本代码 ScriptEngineManager:为Sc ...

  9. Java 学习笔记(4)——java 常见类

    上次提前说了java中的面向对象,主要是为了使用这些常见类做打算,毕竟Java中一切都是对象,要使用一些系统提供的功能必须得通过类对象调用方法.其实Java相比于C来说强大的另一个原因是Java中提供 ...

  10. java学习笔记之对象序列化

    1.简述 java对象序列化就是将对象编程二进制数据流的一种方法,从而实现对对象的传输和存储 2.作用 java是门面向对象编程语言,即一切皆对象,但是java对象只能存在于jvm中,一旦jvm停掉那 ...

随机推荐

  1. c++基础回顾

    #include <iostream> #include <vector> #include <string> int main(int argc, const c ...

  2. JavaScript中奇葩的假值

    通常在以下语句结构中需要判断真假 if分支语句 while循环语句 for里的第二个语句 如 if (boo) { // do something } while (boo) { // do some ...

  3. ORA-01034: ORACLE not available如何解决

    一个小小的问题,让我折腾了一个上午,下午三点彻底解决了,分享一个给大家解决方法,尽管在测试服务器上,但是经验是值得总结和分享的. ERROR:ORA-01034: ORACLE not availab ...

  4. POJ 1061 青蛙的约会【扩展欧几里德】

    设跳的次数为t 根据题意可得以下公式:(x+mt)%L=(y+nt)%L 变形得 (x+mt)-(y+nt)=kL (n-m)t+kL=x-y 令a=(n-m),b=L,c=x-y 得 at+bk=c ...

  5. HTML设置超链接字体颜色和点击后的字体颜色

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. MySQL数据库学习笔记(二)----MySQL数据类型

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  7. 关于phpmyadmin #1045无法登陆服务器的问题

    修改/home/wwwroot/phpmyadmin/libraries/config.default.php 文件,找到下面两行 $cfg['Servers'][$i]['nopassword'] ...

  8. swift为UIView添加extension扩展frame

    添加swift file:UIView+Extension import UIKit extension UIView { // x var x : CGFloat { get { return fr ...

  9. 【转】【C#】【Thread】【Task】多线程

    多线程 多线程在4.0中被简化了很多,仅仅只需要用到System.Threading.Tasks.::.Task类,下面就来详细介绍下Task类的使用. 一.简单使用 开启一个线程,执行循环方法,返回 ...

  10. Linux下Tomcat的启动、关闭、杀死进程

    打开终端 cd /java/tomcat #执行 bin/startup.sh #启动tomcat bin/shutdown.sh #停止tomcat tail -f logs/catalina.ou ...