Java进制和存储
# 前言
Java以前自学过一些,现在工作了,时间太久有一些知识都遗忘了,今天开始就更新Java了,想着把之前的Java基础知识捡起来;从最基础的开始,打好Java基础,便于以后复习。也欢迎大家跟我一起复习。
# 1. 进制(了解)
计算机世界中只有二进制。那么在计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。
# 1.1 进制的分类
十进制:
- 数字组成:0-9
- 进位规则:逢十进一
二进制:以
0b
或0B
开头。- 数字组成:0-1
- 进位规则:逢二进一
十进制的256,二进制:100000000,为了缩短二进制的表示,又要贴近二进制,在程序中引入八进制和十六进制
八进制:以数字
0
开头表示(很少使用)- 数字组成:0-7
- 进位规则:逢八进一
与二进制换算规则:每三位二进制是一位八进制值
十六进制:以
0x
或0X
开头表示。此处的A-F不区分大小写- 数字组成:0-9,a-f
- 进位规则:逢十六进一
与二进制换算规则:每四位二进制是一位十六进制值
# 1.2 进制的换算
十进制 | 二进制 | 八进制 | 十六进制 |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
2 | 10 | 2 | 2 |
3 | 11 | 3 | 3 |
4 | 100 | 4 | 4 |
5 | 101 | 5 | 5 |
6 | 110 | 6 | 6 |
7 | 111 | 7 | 7 |
8 | 1000 | 10 | 8 |
9 | 1001 | 11 | 9 |
10 | 1010 | 12 | a或A |
11 | 1011 | 13 | b或B |
12 | 1100 | 14 | c或C |
13 | 1101 | 15 | d或D |
14 | 1110 | 16 | e或E |
15 | 1111 | 17 | f或F |
16 | 10000 | 20 | 10 |
十进制数据转成二进制数据: 使用除以2倒取余数的方式
二进制数据转成十进制数据:
从右边开始依次是2的0次,2的1次,2的2次。。。。
二进制数据转八进制数据
从右边开始,三位一组
二进制数据转十六进制数据
从右边开始,四位一组
# 十进制转换为二进制
要将一个十进制数转换为二进制数,可以使用以下步骤:
- 将十进制数除以2,得到商和余数。
- 将余数记录下来,然后将商作为新的十进制数,重复步骤1,直到商为0为止。
- 将记录的余数从下往上排列,得到的就是对应的二进制数。
例如,将十进制数27转换为二进制数: 27 ÷ 2 = 13 ... 1 13 ÷ 2 = 6 ... 1 6 ÷ 2 = 3 ... 0 3 ÷ 2 = 1 ... 1 1 ÷ 2 = 0 ... 1 所以27的二进制数为11011。
# 二进制转换为十进制
将二进制数每一位权值找出来,然后每个权值与对应二进制位相乘,最后将它们相加,即可得到十进制数。
什么是权值? 在二进制中,权值指的是每个位所代表的数值大小,即二进制中每个位的位置所代表的数值大小。例如,在二进制数1101中,最高位的权值为8,次高位的权值为4,第三位的权值为2,最低位的权值为1。
例如,二进制数1101转换为十进制数的计算过程如下: 1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 8 + 4 + 0 + 1 = 13 因此,二进制数1101转换为十进制数为13。
# 练习一下
将以下十进制的数字转换为二进制:
- 243:11110011
- 165
- 89
将以下二进制的数字转换为十进制:
- 101010
- 111100
- 011001
# 十进制转换为八进制
将十进制数除以8,直到商为0,然后将每次的余数从下往上排列即为该十进制数的八进制表示。 例如,将十进制数27转换为八进制: 27 ÷ 8 = 3 … 3 3 ÷ 8 = 0 … 3 所以27的八进制表示为33。
# 八进制转换为十进制
八进制转换为十进制的方法如下:
- 将八进制数的每一位按权展开,权值分别为8的0次方、8的1次方、8的2次方,以此类推。
- 将每一位的值乘以对应的权值,然后将所有结果相加。
例如,将八进制数 346 转换为十进制数: 3×8^2 + 4×8^1 + 6×8^0 = 3×64 + 4×8 + 6×1 = 198 因此,八进制数 346 转换为十进制数为 198。
# 十进制转换为十六进制
- 首先将十进制数除以16,得到商和余数。
- 将余数转换为对应的十六进制数,如果余数小于10,则直接写下来,否则用A、B、C、D、E、F表示10、11、12、13、14、15。
- 将商作为新的十进制数,重复步骤1和2,直到商为0为止。
- 将每一步得到的十六进制数倒序排列,即为最终的十六进制数。
例如,将十进制数255转换为十六进制数:
- 255 ÷ 16 = 15 余 15
- 余数15对应的十六进制数为F,所以最后一位为F。
- 15 ÷ 16 = 0 余 15
- 余数15对应的十六进制数为F,所以第二位为F。
- 最终的十六进制数为FF。
# 十六进制转换为十进制
将十六进制转换为十进制的方法是将每一位的十六进制数值乘以对应的权值,再将各位的结果相加。 例如,将十六进制数ABCD转换为十进制数:
- 将A、B、C、D分别转换为对应的十进制数值,即10、11、12、13。
- 根据十六进制的权值规则,从右往左依次乘以16的0次方、1次方、2次方、3次方,即1、16、256、4096。
- 将各位的乘积相加,即:13×1 + 12×16 + 11×256 + 10×4096 = 43981。
- 所以,十六进制数ABCD转换为十进制数为43981。
另一种简便的方法是,将十六进制数中的每一位转换为4位的二进制数,再将这些二进制数转换为十进制数,最后将各位的结果相加。
# 二进制转换为十六进制
二进制转换为十六进制的方法如下:
- 将二进制数从右往左每四位一组,不足四位则在左侧补0,得到若干个四位二进制数。
- 将每个四位二进制数转换为对应的十六进制数,可以使用下表进行转换:
二进制数 | 十六进制数 |
---|---|
0000 | 0 |
0001 | 1 |
0010 | 2 |
0011 | 3 |
0100 | 4 |
0101 | 5 |
0110 | 6 |
0111 | 7 |
1000 | 8 |
1001 | 9 |
1010 | A |
1011 | B |
1100 | C |
1101 | D |
1110 | E |
1111 | F |
- 将每个四位二进制数对应的十六进制数按照从左往右的顺序排列,得到最终的十六进制数。
例如,将二进制数1101011010111011转换为十六进制数:
- 从右往左每四位一组,得到1101 0110 1011 1011。
- 将每个四位二进制数转换为对应的十六进制数,得到D 6 B B。
- 将每个四位二进制数对应的十六进制数按照从左往右的顺序排列,得到最终的十六进制数:D6BB。
# 十六进制转换为二进制
将每个十六进制数位转换为四位二进制数即可。 例如:将十六进制数 AF 转换为二进制数。 A 对应的二进制数为 1010,F 对应的二进制数为 1111,因此 AF 对应的二进制数为 10101111
# 1.3 在代码中如何表示四种进制的常量值
请分别用四种类型的进制来表示10,并输出它的结果:(了解)
十进制:正常表示
System.out.println(10);
二进制:0b或0B开头
System.out.println(0B10);
八进制:0开头
System.out.println(010);
十六进制:0x或0X开头
System.out.println(0X10);
# 2. 计算机存储单位(掌握)
字节(Byte): 是计算机信息技术用于计量存储容量的一种计量单位,一字节等于八位。
**位(bit): **是数据存储的最小单位。也就是二进制。二进制数系统中,每个0或1就是一个位,叫做bit(比特),其中8 bit 就称为一个字节(Byte)。
转换关系:
- 8 bit = 1 Byte
- 1024 Byte = 1 KB
- 1024 KB = 1 MB
- 1024 MB = 1 GB
- 1024 GB = 1 TB
# 3. Java的基本数据类型的存储范围(掌握)
float:单精度浮点型,占内存:4个字节,精度:科学记数法的小数点后6~7位
double:双精度浮点型,占内存:8个字节,精度:科学记数法的小数点后15~16位
# 4. 计算机如何表示数据(理解)
# 4.1 如何表示boolean类型的值
true
底层使用1
表示。
false
底层使用0
表示。
# 4.2 如何表示整数?
# 原码反码补码
原码、反码和补码都是计算机二进制的表示方式。在这三种编码方式中,原码是最简单的,也是最直接的表示方式;反码可以解决原码在计算过程中的问题;补码可以解决反码在计算过程中的问题。 计算机在底层是采用补码形式表示数据的。 在二进制当中,最高位表示符号位,0表示正数,1表示负数。
规定:正数的补码与反码、原码一样,称为三码合一;
负数的补码与反码、原码不一样:
负数的原码:把十进制 转为二进制,然后最高位设置为1
负数的反码:在原码的基础上,最高位不变,其余位取反(0变1,1变0)
负数的补码:反码+1
例如:byte类型(1个字节,8位)
25 ==> 原码 0001 1001 ==> 反码 0001 1001 -->补码 0001 1001
-25 ==>原码 1001 1001 ==> 反码1110 0110 ==>补码 1110 011
正数的原码反码补码
正数的原码、反码和补码都是相同的。 例如,一个十进制数+5的二进制原码为00000101,反码为00000101,补码为00000101。 原码:将正数的二进制表示直接写下来,最高位为0。 反码:正数的反码就是其原码本身。 补码:正数的补码也就是其原码本身。
127的原码反码补码
127的原码为01111111,其反码和补码均与原码相同。
负数的原码反码补码
负数的原码运算规则:将绝对值转换为二进制后,最高位改为1。 -5的原码:10000101 -5的反码:11111010(原则是:以原码作为参考,符号位不变,其他位取反。) -5的补码:11111011(原则是:以反码作为参考,符号位不变,加1)
-128的原码反码补码
-128的原码为10000000,其反码为11111111,补码为10000000。注意,对于-128这个特殊的数,它的补码和原码相同。
整数:
正数:25 00000000 00000000 000000000 00011001(原码)
正数:25 00000000 00000000 000000000 00011001(反码)
正数:25 00000000 00000000 000000000 00011001(补码)
负数:-25 10000000 00000000 000000000 00011001(原码)
负数:-25 11111111 11111111 111111111 11100110(反码)
负数:-25 11111111 11111111 111111111 11100111(补码)
2
3
4
5
6
7
8
# 计算机底层为什么采用补码
算机采用补码形式进行数值计算的原因有以下几点:
- 可以简化电路设计:采用补码形式可以将加减法运算转化为相同的操作,从而简化电路设计。
- 解决了0的正负问题:在原码中,0有两个表示,+0和-0,这样会导致计算结果不唯一,而在补码中,0只有一种表示,即全0,可以避免这个问题。
- 解决了负数溢出问题:在原码中,负数的表示范围比正数少1,这样在进行减法运算时容易出现负数溢出的情况,而在补码中,负数的表示范围与正数相同,可以避免负数溢出的问题。
- 方便计算机进行运算:补码形式可以方便计算机进行加减法运算,而且可以使用相同的电路进行运算,从而提高了计算机的运算效率。
下面是一个简单的数据演示:假设我们要计算-3+2的结果
- 使用原码进行计算:
-3的原码为10000011,2的原码为00000010,进行加法运算得到的结果为10000101,转换成十进制为-5,这个结果错误。
- 使用补码进行计算:
-3的补码为11111101,2的补码为00000010,进行加法运算得到的结果为11111111,转换成十进制为-1,这个结果正确。
# 一个字节可以存储的整数范围是多少?
1个字节:8位
0000 0001 ~ 0111 111 ==> 1~127
1000 0001 ~ 1111 1111 ==> -127 ~ -1
0000 0000 ==>0
1000 0000 ==> -128(特殊规定)=-127-1
2
3
4
5
6
7
8
9
# 4.3 如何表示小数?
了解小数如何存储是为了理解如下问题:
- 为什么float(4个字节)比long(8个字节)的存储范围大?
- 为什么float和double不精确?
- 为什么double(8个字节)比float(4个字节)精度范围大?
因为float、double底层也是二进制,先把小数转为二进制,然后把二进制表示为科学记数法,然后只保存:
①符号位②指数位(需要移位)③尾数位
float:符号位(1位),指数位(8位,偏移127),尾数位(23位)
double:符号位(1位),指数位(11位,偏移1023),尾数为(52位)
float指数-126~+127
double指数-1022~+1023
float类型
小数:8.25 1000.01
1.00001(科学计数法)
符号位0,指数位3+127(偏移量)=130->10000010,尾数00001
0 10000010 00001000000000000000000 原码
0 10000010 00001000000000000000000 反码
0 10000010 00001000000000000000000 补码
小数:-8.25 -1000.01(原码)
1 10000010 00001000000000000000000 原码
1 01111101 11110111111111111111111 反码
1 01111101 11111000000000000000000 补码
double类型:
小数:8.25 1000.01
1.00001(科学计数法)
符号位0,指数位3+1023(偏移量)=1026->10000000010,尾数00001
0 10000000010 0000 10000000 00000000 00000000 00000000 00000000 00000000 原码
0 10000000010 0000 10000000 00000000 00000000 00000000 00000000 00000000 反码
0 10000000010 0000 10000000 00000000 00000000 00000000 00000000 00000000 补码
double类型:
小数:-8.25 -1000.01(原码)
1.00001(科学计数法)
符号位0,指数位3+1023(偏移量)=1026->10000000010,尾数00001
1 10000000010 0000 10000000 00000000 00000000 00000000 00000000 00000000 原码
1 01111111101 1111 01111111 11111111 11111111 11111111 11111111 11111111 反码
1 01111111101 1111 10000000 00000000 00000000 00000000 00000000 00000000 补码
为什么float类型指数位偏移127,double类型指数位偏移1023。
因为指数+3,偏移127就是130
因为指数-3,偏移127就是124
130>124,比较大小比较方便。
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
# 4.4 Java程序中如何表示和处理单个字符?
(1)使用单引号将单个字符引起来:例如:'A','0','尚'
char c = '尚';//使用单引号
String s = '尚';//错误的,哪怕是一个字符,也要使用双引号
char kongChar = '';//错误,单引号中有且只能有一个字符
String kongStr = "";//可以,双引号中可以没有其他字符,表示是空字符串
2
3
4
5
(2)特殊的转义字符
\n:换行
\r:回车
\t:Tab键
\\:\
\":"
\':'
\b:删除键Backspace
2
3
4
5
6
7
public class TestEscapeCharacter {
public static void main(String[] args){
System.out.println("hello\tjava");
System.out.println("hello\rjava");
System.out.println("hello\njava");
System.out.println("hello\\world");
System.out.println("\"hello\"");
char shuang = '"';
System.out.println(shuang + "hello" + shuang);
System.out.println("'hello'");
char dan ='\'';
System.out.println(dan + "hello" + dan);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestTab {
public static void main(String[] args){
System.out.println("hello\tworld\tjava.");
System.out.println("chailinyan\tis\tbeautiful.");
System.out.println("姓名\t基本工资\t年龄");
System.out.println("张三\t10000.0\t23");
}
}
2
3
4
5
6
7
8
(3)用十进制的0~65535之间的Unicode编码值,表示一个字符
在JVM内存中,一个字符占2个字节,Java使用Unicode字符集来表示每一个字符,即每一个字符对应一个唯一的Unicode编码值。char类型的数值参与算术运算或比较大小时,都是用编码值进行计算的。
字符 | Unicode编码值 |
---|---|
'0' | 48 |
'1' | 49 |
'A' | 65 |
'B' | 66 |
'a' | 97 |
'b' | 98 |
'尚' | 23578 |
char c1 = 23578;
System.out.println(c1);//尚
char c2 = 97;
System.out.println(c2);//a
//如何查看某个字符的Unicode编码?
//将一个字符赋值给int类型的变量即可
int codeOfA = 'A';
System.out.println(codeOfA);
int codeOfShang = '尚';
System.out.println(codeOfShang);
int codeOfTab = '\t';
System.out.println(codeOfTab);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(4)\u字符的Unicode编码值的十六进制型
例如:'\u5c1a'代表'尚'
char c = '\u0041'; //十进制Unicode值65,对应十六进制是41,但是\u后面必须写4位
char c = '\u5c1a'; //十进制Unicode值23578,对应十六进制是5c1a
2
# 4.5 一个字符到底占几个字节?
在JVM内存中,一个字符占2个字节,Java使用Unicode字符集来表示每一个字符,即每一个字符对应一个唯一的Unicode编码值。char类型的数值参与算术运算或比较大小时,都是用编码值进行计算的。
在文件中保存或网络中传输时文本数据时,和环境编码有关。如果环境编码选择ISO8859-1(又名Latin),那么一个字符占一个字节;如果环境编码选择GBK,那么一个字符占1个或2个字节;如果环境编码选择UTF-8,那么一个字符占1-4个字节。(后面讲String类时再详细讲解)
以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是scholar,一个在互联网行业的小白,立志成为更好的自己。
如果你想了解更多关于scholar (opens new window) (opens new window),可以关注公众号-书生带你学编程,后面文章会首先同步至公众号。