java序列化与反序列化以及浅谈一下hadoop的序列化

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

神马是序列化呢,序列化就是把内存中的对象的状态信息,转换成字节序列以便于存储(持久化)和网络传输。(网络传输和硬盘持久化,你没有一定的手段来进行辨别这些字节序列是什么东西,有什么信息,这些字节序列就是垃圾)。

反序列化就是将收到字节序列或者是硬盘的持久化数据,转换成内存中的对象

2、JDK的序列化

JDK的序列化只有实现了serializable接口就能实现序列化与反序列化,但是记得一定要加上序列化版本ID serialVersionUID

这个是识别序列化的之前那个类的到底是哪一个?我们显示这个序列化版本ID的目的就是为了:

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

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

java的序列化算法要考虑到下面这些东西:

◆将对象实例相关的类元数据输出。

◆递归地输出类的超类描述直到不再有超类。

◆类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。

◆从上至下递归输出实例的数据

所以java的序列化确实很强大,序列化后得到的信息也很详细,所以反序列化就so easy.

但是这样做也有它的坏处,序列化后很占内存,所以不一定详细就是好处,简单有时也是不错的。

在hadoop中,hadoop实现了一套自己的序列化框架,hadoop的序列化相对于JDK的序列化来说是比较简洁的。在集群中信息的传递主要就是靠这些序列化的字节序列来传递的所以更快速度更小的容量就变得非常地重要了。

说了太多的废话,还是扯回JDK的序列化吧。下面我们看一下在JDK中式如何实现序列化的。

首先我们有一个需要序列化的类如下(必须实现serializable接口)

import java.io.Serializable;

public class Block implements Serializable{

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	private int id;
	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Block(int id, String name) {
		this.id = id;
		this.name = name;
	}

}

下面我们来测试一下序列化的结果:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestSerializable {
	public static void main(String[] args) throws IOException,
			ClassNotFoundException {
		//将序列化化的数据写到文件out里面(持久化)
		FileOutputStream fos = new FileOutputStream("./out");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		for (int i = 0; i < 100; i++) {
			Block b = new Block(i, "B"+i);
			oos.writeObject(b);
		}
		oos.flush();
		oos.close();

		//读出一个序列化的对象的字节序列(^..^)就是反序列化
		FileInputStream fis = new FileInputStream("./out");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Block b2 = (Block) ois.readObject();
		ois.close();
		System.out.println(b2.getName());
	}
}

测试的结果:(取出第一个对象的name)

B0

生成一百个对象的持久化数据的大小是:1.60 KB (1,643 字节)一个对象平均16个字节,该类只有两个字段一个是int,一个字符串但是字符串的长度为2,所以我们可以感受到这冗余还是挺大的。

3、hadoop的序列化

hadoop的序列化的特点是:

1、紧凑:由于带宽是集群中信息传递的最宝贵的资源所以我们必须想法设法缩小传递信息的大小,hadoop的序列化就为了更好地坐到这一点而设计的。

2、对象可重用:JDK的反序列化会不断地创建对象,这肯定会造成一定的系统开销,但是在hadoop的反序列化中,能重复的利用一个对象的readField方法来重新产生不同的对象。

3、可扩展性:当前hadoop的序列化有多中选择

*可以利用实现hadoop的Writable接口。

*使用开源的序列化框架protocol Buffers,Avro等框架。

我们可以注意到的是hadoop2.X之后是实现一个叫YARN的云操作系统,所有应用(如mapreduce,或者其他spark实时或者离线的计算框架都可以运行在YARN上),YARN还负责对资源的调度等等。

YARN的序列化就是用Google开发的序列化框架protocol Buffers,proto目前支持支持三种语言C++,java,Python所以RPC这一层我们就可以利用其他语言来做文章,满足其他语言开发者的需求。

我屮艸芔茻,扯得有点远。

回到hadoop原生的序列化,hadoop原生的序列化类需要实现一个叫Writeable的接口,类似于serializable接口。

还有hadoop也为我们提供了几个序列化类,他们都直接或者间接地实现了Writable接口。如:IntWritable,LongWritable,Text等等。

实现Writable接口必须实现两个方法:write(DataOutputStream out);readField(DataInputStream in)方法。

下面是一个hadoop的序列化例子:

package hadoop;

import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.junit.Test;

public class Testhadoop_serializable_writable {
	@Test
	public void serializable() throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		DataOutputStream dataOut = new DataOutputStream(out);
		FileOutputStream fos = new FileOutputStream("./hadoop_out");
		for (int i = 0; i < 10; i++) {
			Text t1 = new Text(String.valueOf(i));
			Text t2 = new Text("mw");
			MyWritable mw = new MyWritable(t1,t2);
			mw.write(dataOut);
		}
		dataOut.close();
		fos.write(out.toByteArray());
		fos.flush();
		fos.close();

		FileInputStream fis = new FileInputStream("./hadoop_out");
		DataInputStream dis = new DataInputStream(fis);
		for (int i = 0; i < 10; i++) {
			MyWritable mw = new MyWritable(new Text(), new Text());
			mw.readFields(dis);
			System.out.println(mw.getId() + " " + mw.getName());
		}

	}
}

class MyWritable implements Writable {
	private Text id;
	private Text name;

	public MyWritable(Text id, Text name) {
		super();
		this.id = id;
		this.name = name;
	}

	public synchronized Text getId() {
		return id;
	}

	public synchronized void setId(Text id) {
		this.id = id;
	}

	public synchronized Text getName() {
		return name;
	}

	public synchronized void setName(Text name) {
		this.name = name;
	}

	@Override
	public void write(DataOutput out) throws IOException {
		id.write(out);
		name.write(out);
	}

	@Override
	public void readFields(DataInput in) throws IOException {
		id.readFields(in);
		name.readFields(in);
	}

}

我们可以看到我们实现的自己序列化类MyWritable。他有两个字段都是Text,Text是hadoop自带的序列化类,可以看做字符串(类似吧)吧?!

write()和readField()用到的是回调函数,将流(DataOutputStream DataInputStream)写出,或者读出,都是用到回调函数(hook(钩子))。

上面的运行结果如下:

生成的字节序列:

命令行结果:

完!

java序列化与反序列化以及浅谈一下hadoop的序列化

时间: 2024-08-02 02:46:34

java序列化与反序列化以及浅谈一下hadoop的序列化的相关文章

对kotlin和java中的synchronized的浅谈

synchronized在java中是一个关键字,但是在kotlin中是一个内联函数.假如分别在java和kotlin代码锁住同一个对象,会发生什么呢,今天写了代码试了试.首先定义people类 12345678910111213 public class { public void () { for (int i = 0; i < 10; i ++) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStac

访问修饰限定符的简单总结、final/abstruct/interface对类的限制、自动加载机制、序列化与反序列化【数据持久化和对象的序列化问题】、对象的拷贝(按引用是因为对象标识)和克隆(__clone方法中的this指向)

1.针对访问修饰限定符的理解只需要两点:(1)针对的是类的概念和访问代码的位置来确定是否能够访问(2)对访问修饰限定符的使用时只需要对该成员的使用场景注意即可[也就是内部,继承类,外部进行访问的权限] 不需要对内部进行太多理解[需要对php底层理解时进行理解] [重点][用途]通过访问修饰限定符将内部成员的权限合理的限制,然后再使用公共接口来调用这个基本服务,保证外部不能访问其内部的构件[这样既能够通过类内的设置,将内部的功能实现更好的限制,只有最外层的接口可以正常被访问到,而不了解内部的业务]

Java序列化与对象流浅谈

今晚又重新回顾了Java中序列化与对象流的知识,接触了一位有着上亿行有效代码量的大佬之思想,2333. 1.序列化与反序列化 Java中的序列化简而言之就是为了避免要重复使用的实例在每次执行程序过程中都要重新申请堆空间,序列化后直接加载,节约时间.序列化过程中,保存在文件中的对象只记录了对象的状态(属性),包括成员和类类型(名称),而不会存储对象的方法.可看做将一个有着灵魂的人进行灵魂转移,转移的只是他的记忆,他自己的各种行为,比如吃饭.睡觉--,每个人都拥有,且行为表现一样,即只需转移(保存)

为什么这些java接口没有抽象方法?浅谈Java标记接口

在jdk的源码中,存在这样的一些接口,他们不包含任何的(抽象)方法,但是却广泛的存在. 这种接口我们称之为Mark Interface,也就是标记接口. 这些接口呢,我们不用来实现任何的方法,他们的作用就是当某个类实现这个接口的时候,我们就认为这个类拥有了这个接口标记的某种功能了. 下面通过三个例子,分别介绍java中常用的三个标记接口: RandomAccess .Cloneable.java.io.Serializable (1)RandomAccess  在C#中经常会有很多人在争论,在遍

Java中Integer和String浅谈

http://qxzxcjq-126-com.iteye.com/blog/883283 Java中的基本数据类型有八种:int.char.boolean.byte.long.double.float.short.Java作为一种面向对象的编程语言,数据在Java中也是一种对象.我们用基本数据类型创建的对象,如 int x = 0;这里的x只有值这个属性,没有(或者很少)有其他的方法.这在一些需要对数据进行操作时变的很不方便,程序员需要自己编写很多代码去实现一些常用的功能,增加了工作量及程序的大

一个两年Java的面试总结,浅谈自己的面试经验

前言16年毕业到现在也近两年了,最近面试了阿里集团(菜鸟网络,蚂蚁金服),网易,滴滴,点我达,最终收到点我达,网易offer,蚂蚁金服二面挂掉,菜鸟网络一个月了还在流程中... 最终有幸去了网易. 但是要特别感谢点我达的领导及HR,真的非常非常好,很感谢他们一直的关照和指导 面试整体事项1.简历要准备好,联系方式一定要正确清晰醒目,项目经历按照时间倒序阐述,注意描述自己在项目中承担的职责,简历的模板尽量选择简洁的,毕竟程序员大部分还是喜欢简单明了的.2.推荐boss直聘,我觉得很好用(不是广告)

java中的异常处理原理浅谈

什么是异常呢: 在现实生活中,总会有一些问题,聚焦在生活上,我们会有工作问题,比如工作不满意,工作薪水低,工作没有发展前景,那么我们会成为这是一个“问题”. 在java的世界中,那么我们相对应的是程序,那么程序也有这样或者那样的问题,那么我们成为“异常”.异常就是程序在运行时出现的不正常现象. java把异常封装成对象的描述,来高度的概括. java中Error我们无能为力.我们还是聊聊Exception Exception的分类: 1.编译时异常 必须进行捕获 2.运行时异常(也就是Runti

Java重点之小白解析--浅谈数据流形式图片上载

文档上载,上载也不知道哪个大神(混球)起的名字,读起来怪怪的,反正平时我只读上传. 闲话少说,直入主题.先等等这两天做文件上传,都快把宝宝折磨疯了,不会呀,各种查呀,最可悲的是废了老大功夫学会了传送文档的方法,自测的时候特别顺利,图片名,后缀名等等都可以得到了,终于可以跟前端对接了妹的死活接不上,文件上传失败呀,疯了.....于是找原因呀,终于知道,我测试用的form 表单,前端用的数据流,哎,改吧,命苦不能怪政府,谁让人家是资深工程师,我是小白呢,人家随便说句话我就掉坑里了,改吧,人家忙,没空

Java重点之小白解析--浅谈HashMap与HashTable

这是一个面试经常遇到的知识点,无论什么公司这个知识点几乎是考小白必备,为什么呢?因为这玩意儿太特么常见了,常见到你写一百行代码,都能用到好几次,不问这个问哪个.so!本小白网罗天下HashMap与HashTable知识重点只是为应对面试官各种神奇提问方式. 最常见的莫过于,问他们的区别了: 其实API中给出了一句相当简短的介绍,在介绍HashMap的一章中,原文是这么说的 [ 基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和