Java中的二进制流0101

1,710 阅读3分钟

今天在看HashMap的源码时,其hash算法使用了无符号右移16位的操作,好奇Java内存中到底是怎么存放这些数字的。虽然以前知道,计算机都是使用补码的形式存放的整数值,但我都没深究过内存中的字节。今天查查资料,把自己所学的记录在此。

java中基本整型的长度

java中基本整型的长度如下图:
byte:8位,short:16位,int:32位,long:64位

整型长度
而计算机中,程序员用得最多的是十进制和十六进制,十进制符合人的计算习惯,而二进制因为0101太长看起来不方便,将机器内的二进制转为十六进制方便人查看。

Java也提供了这两种进制的字面量,不写任何前缀如int i = 10;即代表该整型i是赋值十进制的10,而int i = 0x10;则表示i赋值的是十六进制的10,即十进制的16。System.out.println(i);默认以十进制打印出i,而System.out.printf("%x",i);则是以16进制打印i。

但值得注意的是0x10这个字面量是以int类型的,如0xff表示的是int类型的255,如果将其赋值给byte类型byte b = 0xff,编译器会报错,因为byte最大为127。这样的话,难道我就不能为一个byte赋值为全1吗?可以的,但是需要借由int来强制转换,如下:

int i = 0x00_00_00_ff; // JDK1.7之后可以使用下划线来分割整型字面量,便于阅读
byte b = (byte) i; // int类型强制转化为byte,会取最右边八位,即ff

内存中存储的是补码

我们知道,计算机在内存中存储的都是整数的补码,空口无凭,那怎么来验证一下呢?程序如下,将int位-1的每一个字节都以十六进制打印出来,确实是补码:0xff_ff_ff_ff

@Test
public void test(){
    int i = -1;
    byte[] bs = new byte[4];
    bs[0] = (byte)(i >>> 24);
    bs[1] = (byte)(i >>> 16);
    bs[2] = (byte)(i >>> 8);
    bs[3] = (byte) i;
    for(byte b : bs){
        System.out.printf("%x ", b);
    }
}

结果如下:

结果
反向验证一下,将byte设置为0xff,看打印是否为-1。

@Test
public void test(){
    int i = 0x01_23_45_ff;
    byte b = (byte) i;
    System.out.printf("%d", b);
}

得证,结果如下:

结果

一切皆0101

计算机中所有的东西都是0101,那么,现在我想用这些0101来组装一个句子“我喜欢你",打印出来可以吗?答案是,当然没问题,只要你知道这些文字的编码即可。上网查找到,“我喜欢你”这几个字的utf8编码是:\xE6\x88\x91\xE5\x96\x9C\xE6\xAC\xA2\xE4\xBD\xA0(\x表示十六进制),那可以使用byte[]数组来构建字符串了,如下:

@Test
public void test() throws UnsupportedEncodingException {
   byte[] bs = {(byte)0xe6, (byte)0x88, (byte)0x91,
           (byte)0xe5, (byte)0x96, (byte)0x9c,
           (byte)0xe6, (byte)0xac, (byte)0xa2,
           (byte)0xe4, (byte)0xbd, (byte)0xa0};
   String s = new String(bs, "utf8");
    System.out.printf("%s", s);
}

结果如下:

结果
当然,搜索unicode编码或其他编码,然后以该编码解码形成String字符串也可。 既然反向能形成字符串,正向也能从字符串获取到编码值,如下,将“我喜欢你”编码为unicode编码:

@Test
public void test() throws UnsupportedEncodingException {
   String s = "我喜欢你";
   byte[] bs = s.getBytes("unicode");
   for(byte b : bs){
       System.out.printf("%x ", b);
   }
}

结果如下,fe ff是unicode头,其余每2字节代表一个中文。

结果

Java字节序endian

写完之后发现遗漏了Java字节序相关的,等下班再补补。其实字节序很简单,就是超过一个字节时,字节在内存中是按什么顺序放置的。像int是四个字节,那么如果存放一个0x12_34_56_78,是在内存地址中按顺序12345678存放还是其他存放方式。这就是字节序。

以上。