Java 字节的常用封装

栏目: 编程工具 · 发布时间: 5年前

内容简介:byte (字节) 是 Java 中的基本数据类型,一个 byte 包含8个 bit(位),byte 的取值范围是-128到+127。byte 跟 Java 其他基本类型的关系:由于工作关系,我封装了一个操作字节的库
Java 字节的常用封装

一. Java 的字节

byte (字节) 是 Java 中的基本数据类型,一个 byte 包含8个 bit(位),byte 的取值范围是-128到+127。

byte 跟 Java 其他基本类型的关系:

基本类型 所占字节数 备注
byte 1
short 2
int 4
long 8
char 2
float 4
double 8
boolean 1、4 《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来

二. 常用封装

由于工作关系,我封装了一个操作字节的库

github 地址: github.com/fengzhizi71…

2.1 bytekit 的特点:

  • 支持多种方式创建 Bytes
  • 支持字节数组、ByteBuffer 的操作
  • 支持 Immutable 对象:ByteArrayBytes、ByteBufferBytes
  • 支持 Transformer: 内置 copy、contact、reverse、xor、and、or、not,也支持自定义 Transformer
  • 支持 Hash: 内置 md5、sha1、sha256
  • 支持转换成16进制字符串
  • 支持 mmap 常用读写操作:readByte/writeByte、readBytes/writeBytes、readInt/writeInt、readLong/writeLong、readDouble/writeDouble、readObject/writeObject
  • 支持对象的序列化、反序列化、深拷贝
  • 不依赖任何第三方库
Java 字节的常用封装

Bytes 是一个接口,它有三个实现类:ByteArrayBytes、ByteBufferBytes、MmapBytes。其中,前面两个实现类是 Immutable 对象。

2.2 支持 Immutable 对象

Immutable 对象(不可变对象),即对象一旦被创建它的状态(对象的数据,也即对象属性值)就不能改变。

它的优点:

  • 构造、测试和使用都很简单
  • 线程安全
  • 当用作类的属性时不需要保护性拷贝
  • 可以很好的用作Map键值和Set元素

2.3 支持 Hash 加密

对 Bytes 中的 byte[] 进行加密。在 Bytes 接口中,包含下面的默认函数:

/**
     * 使用md5加密
     * @return
     */
    default Bytes md5() {

        return transform(new MessageDigestTransformer("MD5"));
    }

    /**
     * 使用sha1加密
     * @return
     */
    default Bytes sha1() {

        return transform(new MessageDigestTransformer("SHA-1"));
    }

    /**
     * 使用sha256加密
     * @return
     */
    default Bytes sha256() {

        return transform(new MessageDigestTransformer("SHA-256"));
    }
复制代码

进行单元测试:

@Test
    public void testHash() {

        Bytes bytes = ByteArrayBytes.create("hello world");

        assertEquals("5eb63bbbe01eeed093cb22bb8f5acdc3", bytes.md5().toHexString());
        assertEquals("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", bytes.sha1().toHexString());
        assertEquals("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", bytes.sha256().toHexString());
    }
复制代码

2.4 序列化、反序列化、深拷贝

支持对象的序列化、反序列化以及深拷贝。在 Bytes 接口中,包含下面的静态函数:

/**
     * 序列化对象,转换成字节数组
     * @param obj
     * @return
     */
    static byte[] serialize(Object obj) {
        byte[] result = null;
        ByteArrayOutputStream fos = null;

        try {
            fos = new ByteArrayOutputStream();
            ObjectOutputStream o = new ObjectOutputStream(fos);
            o.writeObject(obj);
            result = fos.toByteArray();
        } catch (IOException e) {
            System.err.println(e);
        } finally {

            IOUtils.closeQuietly(fos);
        }

        return result;
    }

    /**
     * 反序列化字节数字,转换成对象
     * @param bytes
     * @return
     */
    static Object deserialize(byte[] bytes) {
        InputStream fis = null;

        try {
            fis = new ByteArrayInputStream(bytes);
            ObjectInputStream o = new ObjectInputStream(fis);
            return o.readObject();
        } catch (IOException e) {
            System.err.println(e);
        } catch (ClassNotFoundException e) {
            System.err.println(e);
        } finally {

            IOUtils.closeQuietly(fis);
        }

        return null;
    }

    /**
     * 通过序列化/反序列化实现对象的深拷贝
     * @param obj
     * @param <T>
     * @return
     */
    static <T> T cloneObject(T obj) {
        
        return (T) deserialize(serialize(obj));
    }
复制代码

进行单元测试:

@Test
    public void testSerializeAndDeserialize() {

        User u = new User();
        u.name = "tony";
        u.password = "123456";

        byte[] bytes = Bytes.serialize(u);

        User newUser = (User)Bytes.deserialize(bytes);
        assertEquals(u.name, newUser.name);
        assertEquals(u.password,newUser.password);
    }

    @Test
    public void testDeepCopy() {

        User u = new User();
        u.name = "tony";
        u.password = "123456";

        User newUser = Bytes.cloneObject(u);
        System.out.println(u);
        System.out.println(newUser);
        assertNotSame(u,newUser);
        assertNotSame(u.name,newUser.name);
    }
复制代码

testDeepCopy() 执行后,u 和 newUser 地址的不同,u.name 和newUser.name 指向的内存地址也不同。

com.safframework.bytekit.domain.User@2b05039f
com.safframework.bytekit.domain.User@17d10166
复制代码

2.5 copy、contact、reverse

copy、contact、reverse 都是采用 Transformer 的方式。在 AbstractBytes 类中,包含下面的函数:

@Override
    public Bytes copy() {

        return transform(new CopyTransformer(0, size()));
    }

    @Override
    public Bytes copy(int offset, int length) {

        return transform(new CopyTransformer(offset, length));
    }

    @Override
    public Bytes contact(byte[] bytes) {

        return transform(new ConcatTransformer(bytes));
    }

    @Override
    public Bytes reverse() {

        return transform(new ReverseTransformer());
    }
复制代码

进行单元测试:

@Test
    public void testContact() {

        Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());

        assertEquals(bytes.toString(), "hello world tony");
    }

    @Test
    public void testCopy() {

        Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());

        assertEquals(bytes.toString(), bytes.copy().toString());
    }

    @Test
    public void testReverse() {

        Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());

        assertEquals(bytes.toString(), bytes.reverse().reverse().toString());
    }
复制代码

2.6 位操作

xor、and、or、not 也是采用 Transformer 的方式。在 AbstractBytes 类中,包含下面的函数:

@Override
    public Bytes xor(byte[] bytes) {

        return transform(new BitWiseOperatorTransformer(bytes,BitWiseOperatorTransformer.Mode.XOR));
    }

    @Override
    public Bytes and(byte[] bytes) {

        return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.AND));
    }

    @Override
    public Bytes or(byte[] bytes) {

        return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.OR));
    }

    @Override
    public Bytes not(byte[] bytes) {

        return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.NOT));
    }
复制代码

进行单元测试:

@Test
    public void testBitWise() {

        ByteBufferBytes bytes = (ByteBufferBytes)ByteBufferBytes.create("hello world").contact(" tony".getBytes());

        assertEquals(bytes.toString(), bytes.and(bytes.toByteArray()).or(bytes.toByteArray()).toString());
        assertEquals(bytes.toString(), bytes.not(bytes.toByteArray()).not(bytes.toByteArray()).toString());
        assertEquals(bytes.toString(), bytes.xor(bytes.toByteArray()).xor(bytes.toByteArray()).toString()); //两次xor 返回本身
    }
复制代码

2.7 Base64 编码、解码

@Test
    public void testBase64() {

        ByteBufferBytes bytes = (ByteBufferBytes)ByteBufferBytes.create("hello world").contact(" tony".getBytes());

        String base64 = new String(bytes.encodeBase64());
        assertEquals(bytes.toString(), new String(Bytes.parseBase64(base64)));
    }
复制代码

2.8 Bytes 转换成字节数组

@Test
    public void testToByteArray() {

        Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());

        assertEquals(bytes.toString(), new String(bytes.toByteArray()));
    }
复制代码

三. mmap 的操作

Linux 的 mmap 是一种内存映射文件的方法。

mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。 mmap系统调用是将一个打开的文件映射到进程的用户空间,mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read()、write()等操作。

import com.safframework.bytekit.domain.User;
import com.safframework.bytekit.jdk.mmap.MmapBytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static junit.framework.TestCase.assertEquals;

/**
 * Created by tony on 2018-12-24.
 */
public class MmapBytesTest {

    private MmapBytes mmapBytes;
    private String file;

    @Before
    public void setUp() {

        file = "test";
        mmapBytes = new MmapBytes(file, (long) 1024 * 10); // 10M
    }

    @Test
    public void testWriteAndRead() throws Exception {

        mmapBytes.writeInt(12);
        mmapBytes.writeInt(34);
        mmapBytes.writeByte((byte) 5);
        mmapBytes.writeBytes(("this is tony").getBytes());
        mmapBytes.writeLong(6666L);
        mmapBytes.writeDouble(3.14d);

        assertEquals(12, mmapBytes.readInt());
        assertEquals(34, mmapBytes.readInt());
        assertEquals((byte) 5, mmapBytes.readByte());
        assertEquals("this is tony", new String(mmapBytes.readBytes(12)));
        assertEquals(6666L, mmapBytes.readLong());
        assertEquals(3.14d, mmapBytes.readDouble());
    }

    @Test
    public void testObject() throws Exception {

        User u = new User();
        u.name = "tony";
        u.password = "123456";

        mmapBytes.writeObject(u);

        User temp = (User)mmapBytes.readObject(117);

        assertEquals(u.name, temp.name);
        assertEquals(u.password, temp.password);
    }

    @Test
    public void testFree() throws Exception {

        mmapBytes.writeInt(12);
        mmapBytes.writeInt(34);
        mmapBytes.writeByte((byte) 5);

        mmapBytes.free();

        mmapBytes = new MmapBytes(file, (long) 1024 * 10); // 10M
        mmapBytes.writeInt(67);

        assertEquals(67, mmapBytes.readInt());
    }

    @After
    public void tearDown() {
        mmapBytes.free();
    }
}
复制代码

四. 总结

bytekit 是一个操作字节的 工具 库,不依赖任何第三方库。它封装了字节数组、ByteBuffer 的操作,支持 mmap 常用的读写。

当然,它还可以封装 protobuf 的 ByteString 或者 Android 中的 Parcel,只需实现 Bytes 接口即可。

参考资料:

  1. 你真的知道Java中boolean类型占用多少个字节吗?

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Designing for Emotion

Designing for Emotion

Aarron Walter / Happy Cog / 2011-10-18 / USD 18.00

Make your users fall in love with your site via the precepts packed into this brief, charming book by MailChimp user experience design lead Aarron Walter. From classic psychology to case studies, high......一起来看看 《Designing for Emotion》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具