Java 数据类型与编码(ASCII、Unicode 和 UTF-8)

机械硬盘硬件结构(了解)https://diy.pconline.com.cn/cpu/study_cpu/1009/2215404_all.html

 

一、数据储存单位

1.bit(位)

计算机数据在硬盘中,以机械硬盘为例,其内部由磁性材料制成。磁极有 N\S 两级,可表示两种状态。可以看成 0/1。这是计算机最小储存单位,称为

2.Byte(Octet、字节)

一块磁盘中有许多这样的小磁块,可以表示许多 0/1。而 0/1 正好可以表示二进制数

单单看一个二进制数并没有什么价值。上个世纪 60 年代,美国制定了一套字符编码,对英语字符二进制数之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。

ASCII 码一共规定了 128 个字符的编码。如空格(SPACE)是 32(00100000),大写字母 A 是 65(01000001)。这 128 个符号(包括 32 个不能打印出来的控制符号),只占用了一个字节的后面 7 位,最前面的一位统一规定为 0。

尽管 1 Byte(B、字节) = 8 bit(b、比特) 已经十分常用,但早期计算机会随着硬件不同而变化。于是专门定义 1 Octet = 8 bit。https://www.zhihu.com/question/367812743 & https://www.zhihu.com/question/24601215

3.使用(存储容量/传输速率)

IEC(二进制):K(Kilo) = 2^10、M(Mega)= 2^20、G(Giga) = 2^30、T(Tera) = 2^40、P(Peta) = 2^50、E(Exa) = 2^60、Z(Zetta) = 2^70、Y(Yotta) = 2^80、Bront、Nona、Dogga、Corydon...

SI(十进制):K(Kilo) = 10^3、M(Mega)= 10^6、G(Giga) = 10^9、T(Tera) = 10^12、P(Peta) = 10^15、E(Exa) = 10^18、Z(Zetta) = 10^21、Y(Yotta) = 10^24、Bront、Nona、Dogga、Corydon...

为解决表示混乱,国际电工委员会(IEC)在 1990 年代末定义了一套二进制前缀,专门用于表示 2 的幂次方,它们通过在 SI 前缀后面加上 "bi"(binary 的缩写)来区分:

1 KIB(Kibibyte/KB/千字节) = 2^10 Bytes = 1024 B

1 MIB(Mebibyte/MB/兆字节) = 2^20 Bytes = 1024 KiB

1 GIB(Gibibyte/GB/千兆字节) = 2^30 Bytes = 1024 MiB

1 TIB(Tebibyte/TB/太字节) = 2^40 Bytes = 1024 GiB

Pebibyte、Exbibyte、Zebibyte、Yobibyte、Bront Byte、Nona Byte、Dogga Byte、Corydon Byte...

这些 IEC 标准前缀旨在明确表示二进制倍数,而 K、M、G、T 等(没有 "i")则保留为表示十进制倍数。

然而,尽管这些标准已经存在多年,但它们在日常使用中并未完全普及,尤其是消费者和一些行业仍然习惯使用传统的 KB、MB、GB、TB 来表示二进制容量,导致了持续的混淆。 

通常,内存(RAM)容量总是使用二进制。文件大小和操作系统显示的存储容量通常使用二进制。硬盘、SSD、U 盘等存储设备的生产商标称容量通常使用十进制。网络传输速度总是使用十进制的比特(bit)。例:

网速 1 Kb/s(Kbps/kbps/千比特每秒) = 1 × 10^3 bit/s(bps,bits per second),网速 1600 MB/s = 1600 × 10^6 Byte/s(Bps,Bytes per second),手机存储 128GB = 128×10⁹ 字节,系统显示约 119.2GiB(128×10⁹ / 2³⁰)

b(bit) 和 B(Byte):

1 Kb = 1000 bit,例:网络传输速率 100Kbps = 12.5KB/s

1 KB = 1024 Byte,例:内存容量 8GB 内存 = 8*1024³ B

1 Mb = 1,000,000 bit,例:网络带宽 500M 宽带 = 62.5MB/s

1 MB = 1,048,576 Byte,例:文件存储 1MB 文件 = 8,388,608 bit

4 Gb/Gbit(4 千兆比特) = 4×2^30 b

16 GB/Gbyte(16 千兆字节) = 16×2^30 B

 

二、编码

1.字符

字符并不是一个储存单位,而是一个语言符号。由此来引出码表与编码问题。

英语用 128 个符号使用 ASCII 码表就够了,但是用来表示其他语言,128 个符号是不够的。

简体中文常见的码表是 GB2312,使用两个 Byte 表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。

2.Unicode 码表

世界上这么多国家,存在着多种码表,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它对应的码表,否则用错误的码表解读,就会出现乱码。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,是一种所有符号的码表。

Unicode 现在的规模可以容纳 100 多万个符号。每个符号的编码都不一样。如,U+0041 表示英语的大写字母 A,U+4E25 表示汉字严(具体的符号对应表,可以查询 unicode.org,或者专门的 汉字对应表)。

以往一套码表对应一种编码方式。如 ASCII 中 8 bit 为一个字符,GB2312 中 16 bit 为一个字符。用了 Unicode 后就不行了,靠前的字符二进制数值小,靠后的字符二进制数值大。

若全部以最长字符的位数去编码,那靠前的字符就会出现许多 0 填充,造成了许多空间浪费。所以用了 Unicode 码表后,计算机要以多少位去编码就是一个问题。

3.UTF-8 编码(由 RFC 3629 定义)

首先 UTF-8Unicode 的实现方式之一。其它实现方式还有 UTF-16((UCS-2)字符用两个字节或四个字节表示)和 UTF-32((UCS-4)字符用四个字节表示)

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它使用 1~4 个字节表示一个符号,根据不同的符号而变化字节长度。

注:Java 是标准的 UTF-8(1~4字节),MySQL 是 utf8mb4(1~4字节)  和 utf8(1~3字节)。

UTF-8 的编码规则很简单,只有二条:

  • 对于单字节的符号,字节的第一位设为 0,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  • 对于 n(n > 1)字节的符号,第一个字节的前 n 位都设为 1,第 n + 1 位设为0,后面字节的前两位一律设为 10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母 x 表示可用编码的位。

Unicode符号范围      |       UTF-8编码方式
(十六进制)           |           (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

以汉字严为例

  • 严的 Unicode 是 4E25(100111000100101)
  • 根据上表,4E25 处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是 1110xxxx 10xxxxxx 10xxxxxx。
  • 从严的最后一个二进制位开始,依次从后向前填入格式中的 x,多出的位补 0。这样就得到了严的 UTF-8 编码 11100100 10111000 10100101,转换成十六进制就是 E4B8A5。

 

三、Java 基本数据类型

关于 boolean 型存储

Java 虚拟机中会将 boolean 映射到 int,使用 1 来表示 true,0 表示 false。
即 boolean 型占用 1 bit。
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.3.4

关于浮点型范围

https://blog.csdn.net/shichimiyasatone/article/details/85276316

关于浮点型比较

public static void main(String[] args) {
    Float x = 12.4F;
    Float y = 12.4F;

    // 比较对象地址
    System.out.println(x == y);

    // 比较值,不准确,会丢失精度
    System.out.println(x.equals(y));

    // x 与 y 的绝对值
    System.out.println(Math.abs(x - y));

    // 比较精度比值的精度多一位即可
    if (Math.abs(x - y) > .01) {
        System.out.println("不相等");
    } else {
        System.out.println("相等");
    }
}

https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.2.4

https://blog.csdn.net/f641385712/article/details/86525051

https://www.bilibili.com/video/BV1EJ41187Nv

https://devtool.tech/double-type

关于自动拆装箱

https://www.cnblogs.com/dolphin0520/p/3780005.html

关于类型转换

  • 当在计算中有不同精度的数时,Java 会将低精度的操作数转换成高精度的操作数,然后进行运算。运算的结果也是高精度的值。
  • 将一个高精度的值转换成低精度值的时,要确定这个高精度类型变量的值是否能够在低精度中表示。
  • 低精度到高精度为自动类型转换((byte,short,char)--int--long--float--double)
  • 高精度到低精度为强制类型转换

 


https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.2.1

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

http://www.ruanyifeng.com/blog/2014/12/unicode.html

https://www.bilibili.com/video/BV1HJ411E7d3

posted @ 2019-07-30 18:47  江湖小小白  阅读(2475)  评论(0)    收藏  举报