当前位置: 首页 > news >正文

做网站卖赚钱吗/郑州seo软件

做网站卖赚钱吗,郑州seo软件,博兴网站建设,黄石网站建版权申明】非商业目的可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/80629348 出自:shusheng007 概述定义作用如何实现实现Serializable接口简单实现版本 serialVersionUID继承及引用对象序列化Java序列化算法自定义序列化…

版权申明】非商业目的可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/80629348
出自:shusheng007

  • 概述
  • 定义
  • 作用
  • 如何实现
    • 实现Serializable接口
      • 简单实现
      • 版本 serialVersionUID
      • 继承及引用对象序列化
      • Java序列化算法
      • 自定义序列化
    • 实现Externalizable接口
  • 结语

概述

什么是序列化?什么是反序列化?为什么需要序列化?如何序列化?应该注意什么?本文将从这几方面来论述。

定义

什么是序列化?什么是反序列化?

序列化: 把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。

作用

为什么需要序列化?

在当今的网络社会,我们需要在网络上传输各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都是以二进制序列的形式在网络上传送的,那么发送方就需要将这些数据序列化为字节流后传输,而接收方接到字节流后需要反序列化为相应的数据类型。当然接收方也可以将接收到的字节流存储到磁盘中,等到以后想恢复的时候再恢复。

综上,可以得出对象的序列化和反序列化主要有两种用途:

  • 把对象的字节序列永久地保存到磁盘上。(持久化对象)
  • 可以将Java对象以字节序列的方式在网络中传输。(网络传输对象)

如何实现

如何序列化和反序列化?

如果要让某个对象支持序列化机制,则其类必须实现下面这两个接口中任一个。

  • Serializable

    public interface Serializable {
    }
  • Externalizable

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

实现Serializable接口

简单实现

如果是对序列化的需求非常简单,没有对序列化过程控制的需求,可以简单实现Serializable接口即可。
Serializable的源码可知,其是一个标记接口,无需实现任何方法。例如我们有如下的Student

    public class Student implements Serializable {  private String name;private int age;public Student(String name,int age){System.out.println("有参数构造器执行");this.name=name;this.age=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;}}

序列化: 那么我们如何将此类的对象序列化后保存到磁盘上呢?

  1. 创建一个 ObjectOutputStream 输出流oos
  2. 调用此输出流ooswriteObject()方法
private static void serializ()
{try (ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("object.txt"));){Student s=new Student("ben",18);oos.writeObject(s);} catch (IOException e) {e.printStackTrace();}
}

上面代码将Sutent 的一个实例对象序列化到了一个文本文件中。

反序列化:我们如从文本文件中将此对象的字节序列恢复成Student对象呢?

  1. 创建一个ObjectInputStream 输入流ois
  2. 调用此输入流oisreadObject()方法。

     private static void deSerializ(){try(ObjectInputStream ois=new ObjectInputStream(new FileInputStream("object.txt"));){Student s= (Student) ois.readObject();System.out.println(s.toString());}catch (Exception e){e.printStackTrace();}}

    Node: 当反序列化的时候并没有调用Student的构造函数,说明反序列化机制无需通过构造器来构建Java对象,这就给实现了序列化机制的单例模式造成了麻烦。

版本 serialVersionUID

由于反序列化Java对象的时候,必须提供该对象的class文件,但是随着项目的升级class文件文件也会升级,Java如何保证兼容性呢?答案就是 serialVersionUID。每个可以序列化的类里面都会存在一个serialVersionUID,只要这个值前后一致,即使类升级了,系统仍然会认为他们是同一版本。如果我们不显式指定一个,系统就会使用默认值。

```
public class Student implements Serializable {private static final long serialVersionUID=1L;...
}
```

我们应该总是显式指定一个版本号,这样做的话我们不仅可以增强对序列化版本的控制,而且也提高了代码的可移植性。因为不同的JVM有可能使用不同的策略来计算这个版本号,那样的话同一个类在不同的JVM下也会认为是不同的版本。

那么我们如何维护这个版本号呢?

  • 只修改了类的方法,无需改变serialVersionUID
  • 只修改了类的static变量和使用transient 修饰的实例变量,无需改变serialVersionUID
  • 如果修改了实例变量的类型,例如一个变量原来是int改成了String,则反序列化会失败,需要修改serialVersionUID;如果删除了类的一些实例变量,可以兼容无需修改;如果给类增加了一些实例变量,可以兼容无需修改,只是反序列化后这些多出来的变量的值都是默认值。

继承及引用对象序列化

当要序列化的类存在父类的时候,直接或者间接福来,其父类也必须可以序列化。

当要序列化的类中引用了其他类的对象,那么这些对象的类也必须是可序列化的,如下面代码中的Teacher 类也必须是可以序列化的

public class Student implements Serializable {    private Teacher teacher;...
}

Java序列化算法

Java序列化遵循以下算法:

  • 所有序列化过的,包括磁盘中的的实例对象都有一个序列化编号
  • 当试图序列化一个对象时,程序会先检查该对象是否已经被序列化过,当对象在本次虚拟机中从未被序列化过,则系统将其序列化为字节序列并输出
  • 如果某个对象在本次虚拟机中已经序列化过,则直接输出这个序列化编号

鉴于以上的算法可能会造成一个潜在的问题:当序列化一个可变对象时,只有第一次使用writeObject()方法输出时才会输出字节序列,而第二次调用时仅仅输出一个序列化编号,即使我们改变了这个对象的一些属性,这些改变后的属性也不会序列化到磁盘上,这点在开发中需要非常注意。下面我们看一下代码:

private static void reSerialize()
{try(ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("student.txt"));ObjectInputStream ois=new ObjectInputStream(new FileInputStream("student.txt"));){Student s=new Student("ben",18);oos.writeObject(s);Student rs1= (Student) ois.readObject();s.setAge(32);oos.writeObject(s);Student rs2= (Student) ois.readObject();System.out.println("两个对象是否相等:"+ (rs1==rs2));System.out.println("希望年龄变为32:"+rs2.getAge());}catch (Exception e){e.printStackTrace();}
}

输出结果:

两个对象是否相等:true
希望年龄变为3218

从输出结果可以看出,修改前后反序列化出来的两个对象时绝对相等的,输出的其实是第一个对象,而且我们队年龄做的修改也没有生效。

自定义序列化

  • 通过tansient阻止实例变量的序列化。

    Java默认会序列化所有的实例变量,如果我们不想序列化某一个实例变量,就可以使用tansient这个关键字修饰。

    private transient String name;
  • 通过writeObject()readObject()方法控制序列化过程
    只需要为实现了Serializable接口的类提供两个如下签名的方法,就可完全控制序列化和发序列化过程。

       private void writeObject(ObjectOutputStream out) throws IOExceptionprivate void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException

    例如我们给前面介绍的Student类添加两个如下方法。

       private void writeObject(ObjectOutputStream out) throws IOException{out.writeObject("hello "+name);out.writeInt(age);}private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{name= (String) in.readObject();age=in.readInt();}

    那么反序列化后name 属性的值就会加上hello 前缀。

  • 通过writeReplace()方法控制序列化过程

    为实现了Serializable接口的类提供 如下签名的方法

    Any-Access-Modifier Object writeReplace() throws ObjectStreamException

    该方法在开始序列化writeObject()之前执行,所以可以在序列化对象之前对要序列化的对象做一些处理,甚至完全替换掉原来的对象。 例如下面的代码无论被序列化的对象是什么,反序列化出来的对象总是一个字符串“总有刁民想害朕”。

      private Object writeReplace() throws ObjectStreamException{return "总有刁民想害朕";}
  • 通过readResolve()方法控制反序列化过程

    为实现了Serializable接口的类提供 如下签名的方法

    Any-Access-Modifier Object readResolve() throws ObjectStreamException

    该方法在反序列化readObject()后执行,所以可以在反序列化后对获得的对象做一些处理,甚至完全替换为其他对象。例如下面代码无论反序列化后得到的对象是什么,都会被替换成一个字符串”昏君人人得而诛之”。

       private Object readResolve() throws ObjectStreamException{return "昏君人人得而诛之";}

    这个函数在单例类实现序列化时特别有用,通过前面的介绍 我们知道,通过序列化可以不使用构造函数而获取一个类的实例,这样的话一个单例类就会存在两个实例了,就失去效用了。那么如何解决这个问题呢?

    1、最好是使用枚举enum来构建一个单例,这是最好的方法,解决了序列化以及反射生成实例的问题。

    public enum Singleton {INSTANCE;
    }

    2、如果只是解决由于序列化导致的单例破坏问题,可以使用readResolve()方法解决,如下代码所示:

    public class Singleton implements Serializable{public static final Singleton INSTANCE = new Singleton();private Singleton() {}protected Object readResolve() {return INSTANCE;}...
    }

实现Externalizable接口

如果采用这种方式的话,序列化过程必须完全由程序员自己完成,看如下代码:

public class Teacher implements Externalizable{private String name;private Integer age;public Teacher(String name,Integer age){System.out.println("有参构造");this.name = name;this.age = age;}//setter、getter方法省略//编写自己的序列化逻辑@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject("hello:"+name); //将name加上前缀out.writeInt(age);  //注掉这句后,age属性将不能被序化}//编写自己的反序列化逻辑@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {name = ((StringBuffer) in.readObject()).reverse().toString();age = in.readInt();  }@Override public String toString() {  return "[" + name + ", " + age+ "]";  } 
}

可见Externalizable将序列化和反序列化的工作完全交给了程序员,那样的好处就是自由度变大,如果碰上牛逼程序员,效率也会提升,碰上傻逼程序员就真的傻逼了。鉴于多年编程经验,一般情况下还是使用Serializable较为稳妥,和开发效率比起来,性能就是个屁,不然Java之类的语言也不会打败C++。

结语

每次写完一个主题的总结文章就感觉相关分知识其实不难也不多,为什么我以前感觉那么难那么多呢?只能说明自己知道的还是不够多,需要继续努力。等以后对这部分知识有了新的认识再来更新。

参考文章: https://blog.csdn.net/zcl_love_wx/article/details/52126876

http://www.jmfq.cn/news/5109121.html

相关文章:

  • 网上商城平台开发/seo公司厦门
  • 成都专业的网站建设公司/如何在百度搜索到自己的网站
  • 网站备案上海/网络营销渠道有哪些
  • 阿里云怎么部署网站/网店运营的工作内容
  • 微网站怎么做的好名字吗/网络营销策略都有哪些
  • 电子政务政府网站建设方案/品牌推广方案案例
  • 做网站框架可用jpg图吗/班级优化大师的功能
  • 广东新闻联播直播回放/在线网站seo诊断
  • 电子烟网站建设/百度网址大全旧版本
  • 专门做海产品的网站/房地产销售工作内容
  • 关于营销的网站有哪些/宁德seo公司
  • 网站的软件维护包括什么/网页制作教程步骤
  • 网站建设包涵哪些领域/关键词快速排名不限行业
  • 沧州做英文网站哪家公司好/营销型网站建设怎么做
  • 杭州微网站建设公司哪家好/免费下载百度软件
  • 关于景区网站规划建设方案书/品牌营销和市场营销的区别
  • 珠海斗门建设局网站/海口seo快速排名优化
  • 无锡建设教育协会网站/台州关键词优化服务
  • 网站建设 定制/有没有购买链接
  • 给平顶山公安局做网站的公司/网站排名优化培训哪家好
  • 网站设计规划方案/可以免费推广的平台
  • 新浪博客怎么给自己网站做链接吗/宁波seo搜索引擎优化公司
  • 广州化妆品网站建设/公司网络营销策划书
  • 美仑美家具的网站谁做的/湖南株洲疫情最新情况
  • 新建网站做优化/win11优化大师
  • 厦门做网站/seo云优化
  • 滁州做网站hi444/毛戈平化妆培训学校官网
  • 西安搬家公司电话/刘连康seo培训哪家强
  • 给客户做网站 客户不付尾款/成都网站建设系统
  • 海报设计思路/seo网络推广外包公司