Java基本类型的Writable封装
目前Java基本类型
对应的Writable封装
如表所示
所有这些Writable
类都继承自WritableComparable
。也就是说,它们是可比较的。
同时,它们都有get()
和set()
方法,用于获得和设置封装的值。
对整形(int
和long
)进行编码的时候,有固定长度格式(IntWritable
和LongWritable
)和可变长度格式(VIntWritable
和VLongWritable
)两种选择。
固定长度格式的整形,序列化后的数据是定长的,而可变长度格式则是用一种比较灵活的编码方式,对于数之比较小的整形,它们往往比较节省空间。
同时,由于VIntwritable
和VLongWritable
的编码规则是一样的,所以VIntwritable
的输出可以用VLongWritable
读入。
下面以VLongWritable
为例,说明Writable
的Java基本类
封装实现。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
public
class
VIntWritable
implements
WritableComparable
&
lt
;
VIntWritable
&
gt
;
{
private
int
value
;
public
VIntWritable
(
)
{
}
public
VIntWritable
(
int
value
)
{
set
(
value
)
;
}
/** 设置VIntWritable的值. */
public
void
set
(
int
value
)
{
this
.
value
=
value
;
}
/** 获取VIntWritable的值. */
public
int
get
(
)
{
return
value
;
}
@
Override
public
void
readFields
(
DataInput
in
)
throws
IOException
{
value
=
WritableUtils
.
readVInt
(
in
)
;
}
@
Override
public
void
write
(
DataOutput
out
)
throws
IOException
{
WritableUtils
.
writeVInt
(
out
,
value
)
;
}
/** Returns true iff <code>o</code> is a VIntWritable with the same value. */
@
Override
public
boolean
equals
(
Object
o
)
{
if
(
!
(
o
instanceof
VIntWritable
)
)
return
false
;
VIntWritable
other
=
(
VIntWritable
)
o
;
return
this
.
value
==
other
.
value
;
}
@
Override
public
int
hashCode
(
)
{
return
value
;
}
/** Compares two VIntWritables. */
@
Override
public
int
compareTo
(
VIntWritable
o
)
{
int
thisValue
=
this
.
value
;
int
thatValue
=
o
.
value
;
return
(
thisValue
&
lt
;
thatValue
?
-
1
:
(
thisValue
==
thatValue
?
0
:
1
)
)
;
}
@
Override
public
String
toString
(
)
{
return
Integer
.
toString
(
value
)
;
}
}
|
首先,每个Java基本类型
的Writale
封装,其类的内部都包含一个对应基本类型的成员变量value
,get()
和set()
方法就是用来对该变量进行取值/赋值操作的。
而Writable
接口要求的readFields()
和write()
方法,VIntWritable
则是通过调用Writable
工具类中提供的readVInt()
和writeVInt()
读/写数据。方法readVInt()
和writeVInt()
的实现也只是简单调用了readVLong()
和writeVLong()
,所以,通过writeVInt()
写的数据自然可以通过readVLong()
读入。
读:
1
2
3
4
5
6
7
8
|
public
static
int
readVInt
(
DataInput
stream
)
throws
IOException
{
long
n
=
readVLong
(
stream
)
;
if
(
(
n
&
gt
;
Integer
.
MAX_VALUE
)
||
(
n
&
lt
;
Integer
.
MIN_VALUE
)
)
{
throw
new
IOException
(
&
quot
;
value
too
long
to
fit
in
integer
&
quot
;
)
;
}
return
(
int
)
n
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
static
long
readVLong
(
DataInput
stream
)
throws
IOException
{
byte
firstByte
=
stream
.
readByte
(
)
;
int
len
=
decodeVIntSize
(
firstByte
)
;
if
(
len
==
1
)
{
return
firstByte
;
}
long
i
=
0
;
for
(
int
idx
=
0
;
idx
&
lt
;
len
-
1
;
idx
++
)
{
byte
b
=
stream
.
readByte
(
)
;
i
=
i
&
lt
;
&
lt
;
8
;
i
=
i
|
(
b
&
amp
;
0xFF
)
;
}
return
(
isNegativeVInt
(
firstByte
)
?
(
i
^
-
1L
)
:
i
)
;
}
|
1
2
3
4
5
6
7
8
9
|
public
static
int
decodeVIntSize
(
byte
value
)
{
if
(
value
&
gt
;
=
-
112
)
{
return
1
;
}
else
if
(
value
&
lt
;
-
120
)
{
return
-
119
-
value
;
}
return
-
111
-
value
;
}
|
写:
1
2
3
4
|
public
static
void
writeVInt
(
DataOutput
stream
,
int
i
)
throws
IOException
{
writeVLong
(
stream
,
i
)
;
}
|
writeVLong()
方法实现了对整形数值的变长编码,它的编码规则如下:
如果输入的整数大于或等于-112
同时小于或等于127
,那么编码需要1字节
否则,序列化结果的第一个字节,保存了输入整数的符号和后续编码的字节数。
符号和后续字节数依据下面的编码规则(又一个规则):
- 如果是正数,则编码值范围落在
-113
和-120
间(闭区间),后续字节数可以通过-(v+112)
计算。 - 如果是负数,则编码值范围落在
-121
和-128
间(闭区间),后续字节数可以通过-(v+120)
计算。
后续编码将高位在前,写入输入的整数(除去前面全0字节)。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public
static
void
writeVInt
(
DataOutput
stream
,
int
i
)
throws
IOException
{
writeVLong
(
stream
,
i
)
;
}
/**
* Serializes a long to a binary stream with zero-compressed encoding.
* For -112 <= i <= 127, only one byte is used with the actual value.
* For other values of i, the first byte value indicates whether the
* long is positive or negative, and the number of bytes that follow.
* If the first byte value v is between -113 and -120, the following long
* is positive, with number of bytes that follow are -(v+112).
* If the first byte value v is between -121 and -128, the following long
* is negative, with number of bytes that follow are -(v+120). Bytes are
* stored in the high-non-zero-byte-first order.
*
* @param stream 保存序列化结果输出流
* @param i 被序列化的整数
* @throws java.io.IOException
*/
public
static
void
writeVLong
(
DataOutput
stream
,
long
i
)
throws
IOException
{
// 处于[-112,127]的整数
if
(
i
&
gt
;
=
-
112
&
amp
;
&
amp
;
i
&
lt
;
=
127
)
{
stream
.
writeByte
(
(
byte
)
i
)
;
return
;
}
// 计算情况2的第一个字节
int
len
=
-
112
;
if
(
i
&
lt
;
0
)
{
i
^=
-
1L
;
// take one's complement'
len
=
-
120
;
}
long
tmp
=
i
;
while
(
tmp
!=
0
)
{
tmp
=
tmp
&
gt
;
&
gt
;
8
;
len
--
;
}
stream
.
writeByte
(
(
byte
)
len
)
;
len
=
(
len
&
lt
;
-
120
)
?
-
(
len
+
120
)
:
-
(
len
+
112
)
;
// 输出后续字节
for
(
int
idx
=
len
;
idx
!=
0
;
idx
--
)
{
int
shiftbits
=
(
idx
-
1
)
*
8
;
long
mask
=
0xFFL
&
lt
;
&
lt
;
shiftbits
;
stream
.
writeByte
(
(
byte
)
(
(
i
&
amp
;
mask
)
&
gt
;
&
gt
;
shiftbits
)
)
;
}
}
|