一、字节

所谓字节(Byte),是计算机数据存储的一种计量单位。一个二进制位称为比特(bit),8个比特组成一个字节,也就是说一个字节可以用于区分256(2的8次方)个整数(0~255)。由此我们可以知道,字节本是面向计算机数据存储及传输的基本单位,后续的字符也就是以字节为单位存储的,不同编码的字符占用的字节数不同。
在Java中,字节码是最小的存储单位,Java还将字节Byte作为一种基本数据类型,该数据类型在内存中占用一个字节,用于表示(-128~127)范围内的所有整数.
字节码可以使用Byte进行定义,字节码的具体值可以使用十进制,十六进制,八进制和二进制等数字的值表示。java中的println函数打印出来的字节码的值是十进制的。

实例如下:

public static void main(String[] args) {
        //定义字节码变量a和b,值是十进制的数字-128和127
		byte a = -128;
		byte b = 127;
		System.out.println(a + ", " + b); // 默认是十进制输出:output: -128, 127
        // 定义字节码变量a和b,值是十六进制的数字0x80, 0x7F
        byte a = -0x80, b = 0x7F;
        System.out.println(a + ", " + b); //  默认是十进制输出:output: -128, 127
        // 定义字节码变量a和b,值是八进制的数字0200, 0177;
        byte a = -0200, b = 0177;
        System.out.println(a + ", " + b); //  默认是十进制输出:output: -128, 127
        // 定义字节数组c,值是八进制的数字0200, 0177;
        byte[] c=new byte[];
    }

实例2如下,

public static void main(String[] args) throws Exception {
        // 对字符串用不同编码格式编码
        String s1 = "abc 我是谁";
        char[] chars1 = s1.toCharArray();
        byte[] bytes1 = s1.getBytes("ISO-8859-1");
        byte[] bytes2 = s1.getBytes("GBK");
        byte[] bytes3 = s1.getBytes("UTF-8");
        byte[] bytes4 = s1.getBytes("UTF-16");
        printChart(chars1); // output: 61 62 63 20 6211 662F 8C01
        printChart(bytes1); // output: 61 62 63 20 3F 3F 3F
        printChart(bytes2); // output: 61 62 63 20 CE D2 CA C7 CB AD
        printChart(bytes3); // output: 61 62 63 20 E6 88 91 E6 98 AF E8 B0 81
        printChart(bytes4); // output: FE FF 00 61 00 62 00 63 00 20 62 11 66 2F 8C 01
        // 对字符串用不同编码格式解码
        System.out.println(Charset.defaultCharset().name()); // output: GBK (不同操作系统不同语言默认的系统编码格式有可能不同,LZ是中文Win7)
        System.out.println(chars1); // output: abc 我是谁
        System.out.println(new String(bytes1, "ISO-8859-1")); // output: abc ???(不可逆的乱码)
        System.out.println(new String(bytes2)); // output: abc 我是谁
        System.out.println(new String(bytes2, "UTF-8")); // output: abc ?????(乱码)
        System.out.println(new String(bytes3, "UTF-8")); // output: abc 我是谁
        System.out.println(new String(bytes4, "UTF-16")); // output: abc 我是谁
    }

字符串"abc 我是谁",对应的编码值。在不同的编码方式下,同一个汉字对应的编码值可能是不一样的,但是同一个阿拉伯字母对应的编码值可能是一样的。

class和字节码 java java中什么是字节码_System

总的来说,字节在Java中有两种含义:

  1. 最小的数据存储单位 ,
  2. Java的数据类型,用于表示-128~127范围的整数,

二、字符

计算机底层存储的是字节,字符的设计则是用于展示符号。屏幕上显示的各种文字,数字,符号等就是解码的字符。所以我们说字符是用来显示的符号,它将存储的字节转换成人们看得懂的符号,因此字符的核心就是定义字节与展示符号之间的关系,这种映射关系通常也叫做编码。字符在不同的编码方式中都是一样的含义,但是同一个字符在不同的编码方式中对应的编码值可能却是不一样的,尤其是汉字的编码值,例如,如上图,汉字,”我“,在UTF-8中对应的编码值是E698AF(十六进制),在GBK中对应的编码值是CED2(十六进制)。但是阿拉伯字母的编码大多数是一样的,因为字母也就只有26个而已,一个字节(8个位)就可以全部表示这个26个字母。

例如如下所示,字母abcxyz的编码值,在不同的编码格式下,对应的编码值都是一样的,但是汉字“我是谁”,对应的编码值确实完全不同的。

class和字节码 java java中什么是字节码_System_02

三、编码

如今有很多编码格式,常见的如ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16等等。

ASCII编码是最基础的编码格式,标准的ASCII码一共有128个,占用1个字节的低7位,能够将英语的26个字母符号全覆盖住,但是总的来说能表示的字符还是非常有限。不支持中文编码。
ISO-8859-1编码是ASCII编码的一种扩展,它用了字节的8位,能表示256种字符,且向下兼容ASCII,包含了绝大多数的西欧符号。不支持中文。
GB2312是占用2个字节进行编码,意味着它使用两个字节(16个位)来表示符号,可以表示65536(2的16次方)个字符,其中就有6763个汉字,支持中文。
GBK是GB2312的一个扩展,也是双字节编码,意味着它使用两个字节(16个位)来表示符号,可以表示65536(2的16次方)个字符,能够表示21003个汉字,且向下兼容GB2312。

编码的规范越来越多,不同语言的国家都定义了自己的语言符号编码标准,一时间编码标准百花齐放,在互联网的时代里交流十分不便,不同编码体系之间的信息交流都需要采用不同的解码方案,不然就会出现乱码的现象。于是国际标准化组织ISO制定了一个能够容纳世界上所有文字和符号的字符编码方案Unicode。Unicode是一个字符集,它规定了人类所有字符对应的二进制数,至于这个二进制数怎么存储则是由开发者来进行实现。其中比较流行的实现是UTF-8和UTF-16,还有一种UTF-32。

UTF-32编码使用4个字节,也就是32位二进制存储Unicode字符,可以表示大约500亿(2的32次方)个字符,效率高但是空间浪费。
UTF-8编码是一种可变化的编码方式,它使用1~6个字节来存储,对于英语系的字符使用一个字节,对于汉字则使用两个字节,依次类推,向下兼容ASCII,这样就能够节省一定的空间。
UTF-16编码是介于两者之间的一种编码方式。对于部分字符采用2个字节,另一部分字符采用4个字节。因此UTF-16无法兼容ASCII。

在平时的使用中,UTF-8的使用还是比较多,就是由于它既能向下兼容ASCII,还能够在一定程度上节省空间。