新手求教在二手iphone哪里买靠谱电池靠谱

Java 序列化Serializable详解(附详细例子)
序列化Serializable详解(附详细例子)
1、什么是序列化和反序列化
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。
2、什么情况下需要序列化
a)当你想把的内存中的对象保存到一个文件中或者中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
3、如何实现序列化
将需要序列化的类实现Serializable接口就可以了,Serializable接口中没有任何方法,可以理解为一个标记,即表明这个类可以序列化。
4、序列化和反序列化例子
如果我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后将这些OutputStream封装在一个ObjectOutputStream中。这时候,只需要调用writeObject()方法就可以将对象序列化,并将其发送给OutputStream(记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构)。而反序列的过程(即将一个序列还原成为一个对象),需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()即可。
package com.
import java.io.FileInputS
import java.io.FileNotFoundE
import java.io.FileOutputS
import java.io.IOE
import java.io.ObjectInputS
import java.io.ObjectOutputS
import java.io.S
public class MyTest implements Serializable
private static final long serialVersionUID = 1L;
private String name="SheepMu";
private int age=24;
public static void main(String[] args)
{//以下代码实现序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名为 my.out ;ObjectOutputStream能把Object输出成Byte流
MyTest myTest=new MyTest();
oos.writeObject(myTest);
oos.flush();
oos.close(); //关闭流
} catch (FileNotFoundException e)
e.printStackTrace();
} catch (IOException e)
e.printStackTrace();
fan();//调用下面的
public static void fan()//反序列的过程
ObjectInputStream oin =//局部变量必须要初始化
oin = new ObjectInputStream(new FileInputStream("my.out"));
} catch (FileNotFoundException e1)
e1.printStackTrace();
} catch (IOException e1)
e1.printStackTrace();
MyTest mts =
mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.out.println("name="+mts.name);
System.out.println("age="+mts.age);
}会在此项目的工作空间生成一个 my.out文件。序列化后的内容稍后补齐,先看反序列化后输出如下:
name=SheepMu
5、序列化ID
序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的
1L 就可以,这样可以确保代码一致时反序列化成功。这也可能是造成序列化和反序列化失败的原因,因为不同的序列化id之间不能进行序列化和反序列化。
6.序列化前和序列化后的对象的关系
"=="还是equal? or
是浅复制还是深复制?
答案:深复制,反序列化还原后的对象地址与原来的的地址不同
序列化前后对象的地址不同了,但是内容是一样的,而且对象中包含的引用也相同。换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的”深度复制(deep
copy)"——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。
7.静态变量能否序列化
若把上面的代码中的 age变量前加上 static ,输出任然是
name=SheepMu
但是看下面的例子:
package com.
import java.io.FileInputS
import java.io.FileNotFoundE
import java.io.FileOutputS
import java.io.IOE
import java.io.ObjectInputS
import java.io.ObjectOutputS
import java.io.S
public class MyTest implements Serializable
private static final long serialVersionUID = 1L;
private String name="SheepMu";
private static int age=24;
public static void main(String[] args)
{//以下代码实现序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名为 my.out ;ObjectOutputStream能把Object输出成Byte流
MyTest myTest=new MyTest();
oos.writeObject(myTest);
oos.flush();
oos.close(); //关闭流
} catch (FileNotFoundException e)
e.printStackTrace();
} catch (IOException e)
e.printStackTrace();
fan();//调用下面的
public static void fan()
new MyTest().name="SheepMu_1";//!!!!!!!!!!!!!!!!重点看这两行 更改部分
age=1;//!!!!!!!!!!!!!!!!!!!重点看这两行 更改部分
ObjectInputStream oin =//局部变量必须要初始化
oin = new ObjectInputStream(new FileInputStream("my.out"));
} catch (FileNotFoundException e1)
e1.printStackTrace();
} catch (IOException e1)
e1.printStackTrace();
MyTest mts =
mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.out.println("name="+mts.name);
System.out.println("age="+mts.age);
输出结果为:
name=SheepMu
为何把最上面代码的age变量添上static 后还是反序列化出了24呢?而新的从新对变量赋值的代码,不是static的得到了序列化本身的值,而static的则得到的是从新附的值。原因: 序列化会忽略静态变量,即序列化不保存静态变量的状态。静态成员属于类级别的,所以不能序列化。即 序列化的是对象的状态不是类的状态。这里的不能序列化的意思,是序列化信息中不包含这个静态成员域。最上面添加了static后之所以还是输出24是因为该值是JVM加载该类时分配的值。注:transient后的变量也不能序列化,但是情况稍复杂,稍后开篇说。
a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
c) static,transient后的变量不能被序列化;&&&&&&&&&&&
概述:当一个类实现了Serializable接口(该接口仅为标记接口,不包含任何方法定义),表示该类可以序列化.序列化的目的是将一个实现了Serializable接口的对象转换成一个字节序列,可以。&把该字节序列保存起来(例如:保存在一个文件里),以后可以随时将该字节序列恢复为原来的对象。甚至可以将该字节序列放到其他计算机上或者通过网络传输到其他计算机上恢复,只要该计&算机平台存在相应的类就可以正常恢复为原来的对象。&实现:要序列化一个对象,先要创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内,再调用writeObject()方法即可序列化一个对象;反序列化也类似。&import java.io.*;&public class Person implements Serializable {&private String userN&private S&public Person(String userName, String password) {&this.userName = userN&this.password =&}&public String toString() {&return "userName:" + userName + "& password:" +&}&public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {&//序列化一个对象(存储到一个文件)&ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.out"));&oos.writeObject("Save a object:\n");&oos.writeObject(new Person("Bruce", "123456"));&oos.close();&//反序列化,将该对象恢复(存储到一个文件)&ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.out"));&String s = (String)ois.readObject();&Person p = (Person)ois.readObject();&System.out.println(s + p);&//序列化一个对象(存储到字节数组)&ByteArrayOutputStream baos = new ByteArrayOutputStream();&ObjectOutputStream oos2 = new ObjectOutputStream(baos);&oos2.writeObject("Save another object:\n");&oos2.writeObject(new Person("Phil", "654321"));&oos2.close();&//反序列化,将该对象恢复(存储到字节数组)&ObjectInputStream ois2 = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));&s = (String)ois2.readObject();&p = (Person)ois2.readObject();&System.out.println(s + p);&}&}&//输入如下信息&Save a object:&userName:Bruce& password:123456&Save another object:&userName:Phil& password:654321&transient关键字:&自动序列化将对象的所有字段都持久化了,有时候需要对某些字段不进行自动化(如密码,因为序列化会暴光密码信息),这个时候可以使用transient关键字(只能和Serializable对象一起使&用),其作用是不序列化某些字段。将Person类的字段改为如下定义,再运行上面的程序:&private String userN&private transient S&//输入如下信息&Save a object:&userName:Bruce& password:null&Save another object:&userName:Phil& password:null&控制序列化字段,甚至该字段是被transient修饰的字段也能将其序列化。手动序列化需要添加两个私有(private)方法(writeObject()和readObject()),在该私有方法中控制序列花字段。&import java.io.*;&public class Person implements Serializable {&private String userN&private transient S&public Person(String userName, String password) {&this.userName = userN&this.password =&}&public String toString() {&return "userName:" + userName + "& password:" +&}&private void writeObject(ObjectOutputStream out) throws IOException {&out.defaultWriteObject();& //序列化所有非transient字段,必须是该方法的第一个操作&out.writeObject(password); //序列化transient字段&}&private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {&in.defaultReadObject();&&&&&&&&&&&& //反序列化所有非transient字段,必须是该方法的第一个操作&password = (String)in.readObject(); //反序列化transient字段&}&public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {&//序列化一个对象(存储到一个文件)&ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.out"));&oos.writeObject("Save a object:\n");&oos.writeObject(new Person("Bruce", "123456"));&oos.close();&//反序列化,将该对象恢复(存储到一个文件)&ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.out"));&String s = (String)ois.readObject();&Person p = (Person)ois.readObject();&System.out.println(s + p);&}&}&//输入如下信息&Save a object:&userName:David& password:13579&控制序列化字段还可以使用Externalizable接口替代Serializable借口。此时需要定义一个默认构造器,否则将为得到一个异常(java.io.InvalidClassException: P P no&valid constructor);还需要定义两个方法(writeExternal()和readExternal())来控制要序列化的字段。&import java.io.*;&public class Person implements Externalizable {&private String userN&private S&public Person() {&System.out.println("default constructor invoked!");&}&public Person(String userName, String password) {&this.userName = userN&this.password =&}&public String toString() {&return "userName:" + userName + "& password:" +&}&public void writeExternal(ObjectOutput out) throws IOException {&//序列化字段&out.writeObject(userName);&out.writeObject(password);&}&public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {&//反序列化字段&userName = (String)in.readObject();&password = (String)in.readObject();&}&public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {&//序列化一个对象(存储到一个文件)&ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.out"));&oos.writeObject("Save a object:\n");&oos.writeObject(new Person("Leo", "1984"));&oos.close();&//反序列化,将该对象恢复(存储到一个文件)&ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.out"));&String s = (String)ois.readObject();&Person p = (Person)ois.readObject();&System.out.println(s + p);&}&}&//输入如下信息&default constructor invoked!&Save a object:&userName:Leo& password:1984&以上方式只能恢复成Java对象,如果想要恢复成其他对象(如C++对象),那就要将Java对象转换为XML格式,这样可以使其被各种平台和各种语言使用。可以使用随JDK一起发布的javax.xam.*类库,或者使用开源XOM类库(可以从www.xom.nu下载并获得文档)。
阅读(...) 评论() &Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨 - Kent.Kwan的技术博客 - ITeye技术网站
博客分类:
没啥好说的,直接开始Part II吧。
谈到了对象的克隆,就不得不说为什么要对对象进行克隆。Java中所有的对象都是保存在堆中,而堆是供全局共享的。也就是说,如果同一个Java程序的不同方法,只要能拿到某个对象的引用,引用者就可以随意的修改对象的内部数据(前提是这个对象的内部数据通过get/set方法曝露出来)。有的时候,我们编写的代码想让调用者只获得该对象的一个拷贝(也就是一个内容完全相同的对象,但是在内存中存在两个这样的对象),有什么办法可以做到呢?当然是克隆咯。
首先,我们是程序员,当然是用我们程序员的语言来交流。
import java.util.D
public class User implements Cloneable {
public User(String username, String password, Date birthdate) {
this.username =
this.password =
this.birthdate =
protected Object clone() throws CloneNotSupportedException {
return super.clone();
public int hashCode() {
// 省略equals的实现(可用eclipse自动生成)
public boolean equals(Object obj) {
// 省略equals的实现(可用eclipse自动生成)
// 省略一大堆get/set方法
上述代码构建了一个User类,并且实现了java.lang.Cloneable接口。顾名思义,Cloneable的意思就是说明这个类可以被克隆的意思。
而我们先去看看java.lang.Cloneable这个接口有些什么。
/* * @(#)Cloneable.java 1.17 05/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package java./** * A class implements the &code&Cloneable&/code& interface to
* indicate to the {@link java.lang.Object#clone()} method that it
* is legal for that method to make a
* field-for-field copy of instances of that class.
* &p& * Invoking Object's clone method on an instance that does not implement the
* &code&Cloneable&/code& interface results in the exception
* &code&CloneNotSupportedException&/code& being thrown. * &p& * By convention, classes that implement this interface should override
* &tt&Object.clone&/tt& (which is protected) with a public method. * See {@link java.lang.Object#clone()} for details on overriding this * method. * &p& * Note that this interface does &i&not&/i& contain the &tt&clone&/tt& method. * Therefore, it is not possible to clone an object merely by virtue of the * fact that it implements this interface.
Even if the clone method is invoked * reflectively, there is no guarantee that it will succeed. * * @author
unascribed * @version 1.17, 11/17/05 * @see
java.lang.CloneNotSupportedException * @see
java.lang.Object#clone() * @since
JDK1.0 */public interface Cloneable { }
不要惊讶,没错,除了一大堆的鸡肠以外,这个接口没有定义任何的方法签名。也就是说,我们要克隆一个对象,但是他又不给我提供一个方法。那该怎么办呢?不怕,我们还有全能的Object类,别忘记他可是所有类的始祖啊(神一般的存在着),所以,有事没事都该去问候一下他老人家。
/* * @(#)Object.java 1.73 06/03/30 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package java./** * Class &code&Object&/code& is the root of the class hierarchy.
* Every class has &code&Object&/code& as a superclass. All objects,
* including arrays, implement the methods of this class.
* * @author
unascribed * @version 1.73, 03/30/06 * @see
java.lang.Class * @since
JDK1.0 */public class Object {
// 省略N多的代码
* Creates and returns a copy of this object.
The precise meaning
* of "copy" may depend on the class of the object. The general
* intent is that, for any object &tt&x&/tt&, the expression:
* &blockquote&
* x.clone() != x&/pre&&/blockquote&
* will be true, and that the expression:
* &blockquote&
* x.clone().getClass() == x.getClass()&/pre&&/blockquote&
* will be &tt&true&/tt&, but these are not absolute requirements.
* While it is typically the case that:
* &blockquote&
* x.clone().equals(x)&/pre&&/blockquote&
* will be &tt&true&/tt&, this is not an absolute requirement.
* By convention, the returned object should be obtained by calling
* &tt&super.clone&/tt&.
If a class and all of its superclasses (except
* &tt&Object&/tt&) obey this convention, it will be the case that
* &tt&x.clone().getClass() == x.getClass()&/tt&.
* By convention, the object returned by this method should be independent
* of this object (which is being cloned).
To achieve this independence,
* it may be necessary to modify one or more fields of the object returned
* by &tt&super.clone&/tt& before returning it.
Typically, this means
* copying any mutable objects that comprise the internal "deep structure"
* of the object being cloned and replacing the references to these
* objects with references to the copies.
If a class contains only
* primitive fields or references to immutable objects, then it is usually
* the case that no fields in the object returned by &tt&super.clone&/tt&
* need to be modified.
* The method &tt&clone&/tt& for class &tt&Object&/tt& performs a
* specific cloning operation. First, if the class of this object does
* not implement the interface &tt&Cloneable&/tt&, then a
* &tt&CloneNotSupportedException&/tt& is thrown. Note that all arrays
* are considered to implement the interface &tt&Cloneable&/tt&.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, the
* contents of the fields are not themselves cloned. Thus, this method
* performs a "shallow copy" of this object, not a "deep copy" operation.
* The class &tt&Object&/tt& does not itself implement the interface
* &tt&Cloneable&/tt&, so calling the &tt&clone&/tt& method on an object
* whose class is &tt&Object&/tt& will result in throwing an
* exception at run time.
a clone of this instance.
* @exception
CloneNotSupportedException
if the object's class does not
support the &code&Cloneable&/code& interface. Subclasses
that override the &code&clone&/code& method can also
throw this exception to indicate that an instance cannot
be cloned.
* @see java.lang.Cloneable
protected native Object clone() throws CloneNotSupportedE
呵呵,又是一大串的鸡肠,别以为我是来凑字数的,这些都是Sun公司Java开发人员写的技术文章,多看看少说话吧。
没错,又是个native方法,果然是个高深的东西,不过我们还是要占一下他的便宜。而且他这个方法是protected的,分明就是叫我们去占便宜的。
再继续看看下面测试代码。
import java.util.D
import org.junit.T
public class TestCase {
public void testUserClone() throws CloneNotSupportedException {
User u1 = new User("Kent", "123456", new Date());
User u2 = u1;
User u3 = (User) u1.clone();
System.out.println(u1 == u2);
System.out.println(u1.equals(u2)); // true
System.out.println(u1 == u3);
System.out.println(u1.equals(u3)); // true
这个clone()方法果然牛,一下子就把我们的对象克隆了一份,执行结果也符合我们的预期,u1和u3的地址不同但是内容相同。
通过上述的例子,我们可以看出,要让一个对象进行克隆,其实就是两个步骤:
1. 让该类实现java.lang.Cloneable接口;
2. 重写(override)Object类的clone()方法。
但是,事实上真的是如此简单吗?再看下面的代码。
public class Administrator implements Cloneable {
public Administrator(User user, Boolean editable) {
this.user =
this.editable =
protected Object clone() throws CloneNotSupportedException {
return super.clone();
public int hashCode() {
public boolean equals(Object obj) {
上面定义了一个Administrator类,这个类持有一个User类的对象。接下来我们看看对Administrator对象进行克隆会有什么效果。
import java.util.D
import org.junit.T
public class TestCase {
public void testAdministratorClone() throws CloneNotSupportedException {
Administrator a1 = new Administrator(new User("Kent", "123456", new Date()), true);
Administrator a2 = a1;
Administrator a3 = (Administrator) a1.clone();
System.out.println(a1 == a2);
System.out.println(a1.equals(a2));
System.out.println(a1 == a3);
System.out.println(a1.equals(a3));
System.out.println(a1.getUser() == a3.getUser());
//true ! It's not our expected!!!!!
System.out.println(a1.getUser().equals(a3.getUser())); //true
呵呵呵!出问题了吧。Java哪是那么容易就能驾驭的说!
这里我们就可以引入两个专业的术语:浅克隆(shallow clone)和深克隆(deep clone)。
所谓的浅克隆,顾名思义就是很表面的很表层的克隆,如果我们要克隆Administrator对象,只克隆他自身以及他包含的所有对象的引用地址。
而深克隆,就是非浅克隆。克隆除自身以外所有的对象,包括自身所包含的所有对象实例。至于深克隆的层次,由具体的需求决定,也有“N层克隆”一说。
但是,所有的基本(primitive)类型数据,无论是浅克隆还是深克隆,都会进行原值克隆。毕竟他们都不是对象,不是存储在堆中。注意:基本数据类型并不包括他们对应的包装类。
如果我们想让对象进行深度克隆,我们可以这样修改Administrator类。
protected Object clone() throws CloneNotSupportedException {
Administrator admin = (Administrator) super.clone();
admin.user = (User) admin.user.clone();
由于Boolean会对值进行缓存处理,所以我们没必要对Boolean的对象进行克隆。并且Boolean类也没有实现java.lang.Cloneable接口。
1. 让该类实现java.lang.Cloneable接口;
2. 确认持有的对象是否实现java.lang.Cloneable接口并提供clone()方法;
3. 重写(override)Object类的clone()方法,并且在方法内部调用持有对象的clone()方法;
5. 多麻烦啊,调来调去的,如果有N多个持有的对象,那就要写N多的方法,突然改变了类的结构,还要重新修改clone()方法。
难道就没有更好的办法吗?
接下来要重点介绍一下使用java.lang.Serializable来实现对象的深度克隆。
首先,我们编写一个工具类并提供cloneTo()方法。
import java.io.ByteArrayInputS
import java.io.ByteArrayOutputS
import java.io.IOE
import java.io.ObjectInputS
import java.io.ObjectOutputS
public abstract class BeanUtil {
@SuppressWarnings("unchecked")
public static &T& T cloneTo(T src) throws RuntimeException {
ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
ObjectOutputStream out = null;
ObjectInputStream in = null;
T dist = null;
out = new ObjectOutputStream(memoryBuffer);
out.writeObject(src);
out.flush();
in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
dist = (T) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (out != null)
out.close();
out = null;
} catch (IOException e) {
throw new RuntimeException(e);
if (in != null)
in.close();
in = null;
} catch (IOException e) {
throw new RuntimeException(e);
看不懂,没关系,直接拿去用就可以了。嘻嘻。
接下来我们测试一下是否能通过这个工具来实现深度克隆。
又是这个可爱的TestCase,可怜的每次都要动他……
import java.util.D
import org.junit.T
public class TestCase {
public void testCloneTo() {
Administrator src = new Administrator(new User("Kent", "123456", new Date()), true);
Administrator dist = BeanUtil.cloneTo(src);
System.out.println(src == dist);
System.out.println(src.equals(dist));
System.out.println(src.getUser() == dist.getUser());
//false ! Well done!
System.out.println(src.getUser().equals(dist.getUser())); //true
好了,无论你的对象有多么的复杂,只要这些对象都能够实现java.lang.Serializable接口,就可以进行克隆,而且这种克隆的机制是JVM完成的,不需要修改实体类的代码,方便多了。
为什么这么简单就可以实现对象的克隆呢?java.lang.Serializable接口又是干嘛用的呢?如果想知道这些问题的答案,
浏览 19078
浏览: 28984 次
来自: 广州
private String userN priva ...
不错,有段代码并没有看懂。
很不错,楼主
有想法。。
不错, 解决了我的问题。

我要回帖

更多关于 演唱会门票哪里买靠谱 的文章

 

随机推荐