Java对象实例化问题

官方说法:

什么叫对象序列化?
对象序列化就是把对象写入到输出流中,用来存储或者传输
对象的反序列化就是从输入流中读取对象
将对象转换为字节流保存起来,并在日后还原这个对象,这种机制叫做对象序列化
我们可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化!)

为什么要序列化?
1.
需要将对象的状态保存到文件中,而后能够通过读入对象状态来重新构造对象,恢复程序状态
2.
使用套接字在网络上传送对象的程序来说,是很有用的。
在对对象流进行读写操作时会引发一些问题,而序列化机制正是用来解决这些问题的!读写对象会有什么问题呢?其中一个最大的问题就是对象引用!举个例子来说:假如我有两个类,分别是ABB类中含有一个指向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接口,Serializable接口是一个标识接口,没有需要实现的方法,它主要用来通知Java虚拟机(JVM)需要将一个对象序列化。implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用ObjectInputStream提供从输入流中读出对象的readObject方法。
Serializable
有一个子接口Externalizable,实现Externalizable接口的类可以自行控制对象序列化和反序列化过程。

实现了序列化接口的类,如果其成员不需要序列化进去,则使用transient关键字进行修饰。

注意的问题:
(1)
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) long 型字段)显式声明其自己的serialVersionUID    ANY-ACCESS-MODIFIERstatic final long serialVersionUID = 42L;如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范中所述。不过,强烈建议所有可序列化类都显式声明 serialVersionUID 值,原因计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修改器显示声明serialVersionUID(如果可能),原因是这种声明仅应用于立即声明类 -- serialVersionUID 字段作为继承成员没有用处。serialVersionUID Eclipse里可以自动生成,可是在其他大部分IDE工具里面都不能自动生成。

(2)并非所有类都可以序列化,在cmd下,我们输入serialverjava.net.socket,可以得到socket是否可序列化的信息,实际上socket是不可序列化的。
(3)java
有很多基础类已经实现了serializable接口,比如string,vector等。但是比如hashtable就没有实现serializable接口。
(4)
是否所有的对象都可以序列化?当然是不可以的了,就有很多原因了,比如:安全方面的原因,比如一个对象拥有private,publicfield,对于一个要传输的对象,比如写到文件,或者进行rmi传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;资源分配方面的原因,比如socket,thread,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现.

(5)反序列化对象时,并不会调用该对象的任何构造方法,仅仅是根据所保存的对象的状态信息,在内存中重新构建对象!
(6)
当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量
(7)
如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!

序列化的作用:

同时有10个用户登录,10个请求携带用户名和密码,都到了tomcat服务器,那么首先因为请求都是通过页面调用的loginActionstruts就会让spring去创建10loginAction类。

假设登录后要返回userinfo VO类,那么这10action类就每个类被spring分配一个userinfo ,因为userinfo被序列化了,这10userinfo上都写着号。

然后这10action就各自运行内部方法,最快运行到调用serviceaction就去service那儿了,后面的action依次运行完都往service那儿跑。

service login方法因为有synchronized,所以,他一看10action请求一下子都过来了,就让他们排队,排好队一个一个处理他们的请求,给每个action手里的VO对象装上数据打发走人。整体流程大概就是这样的。

多用户访问的情况下,容易出现问题,所以保险起见,可以将实体类VO类以及service类的实现类都implements Serializable,实现对象的实例化。

Serializable含义可以理解为访问排队,当一个访问被返回后才接受下一个访问,只需要将service接口的实现类做implements Serializabledao因为都是有service调用的,就不需要加implements Serializableaction的实例化是struts操控的,也不需要加implements Serializable

J2ee的项目需要什么地方用到序列化implements Serializable

1所有的VOimplements Serializable,实体类生成对象的时候就进行了序列化。

2serviceImpl类,所有的方法synchronized(实现串行),public synchronized 返回方法名(参数){},相当于在方法明前面加上一个标记。

3daoImpl类的方法最好也加上synchronized,这是防止数据请求延时造成前一个的调用还没响应,后一个调用已经到达

implements Serializable的类就实现了序列化,需要implements Serializable的类一般都是要携带数据的,好比淘宝发的包裹,implements Serializable理解为在包裹上写明地址和收件人,而synchronized的方法好比办理业务的窗口,一个用户一个用户的来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值