一、计算机存储数据的原理(理解)
1.1 存储单位是什么
1、最小单位:比特,bit,1个二进制位
例如:boolean值就可以用1个比特位来表示,true用1表示,false用0表示。
2、最基本单位:字节,byte,1个字节有8个二进制位
-
1B=8位
-
1KB=1024B
-
1MB=1024KB
-
1GB=1024MB
-
1TB = 1024GB
-
1PB = 1024TB
10月24日:程序员节
扩展:网络带宽:100Mb,此时的b是bit。
1.2 Java的8种基本数据类型的宽度(要记几个字节)
1.3 符号位、原码、反码、补码(理解)
1、符号位
是指二进制序列的最高位,最左边的位。0表示正数,1表示负数。
2、原码、反码、补码
为了让符号位也参与运算,负数就必须要转为补码表示。
正数:原码、反码、补码都一样,不区分。
例如:25 以1个字节的宽度为例 原码:00011001 反码:00011001 补码:00011001
负数:原码、反码、补码都不一样。
例如 -25 原码:10011001 反码:11100110 在原码基础上,符号位不变,其余位取反,1变0,0变1 补码:11100111 在反码基础上+1
计算机底层的存储和计算都是基于补码计算的。
3、练习
列出如下几个数字的原码、反码、补码,统一用4个字节(int)
160, -250, 1024, -963 160: 正数:原码、反码、补码都一样 原码:00000000 00000000 00000000 10100000 反码:00000000 00000000 00000000 10100000 补码:00000000 00000000 00000000 10100000 -250: 负数:原码、反码、补码都不同 补码:11111111 11111111 11111111 00000110 反码:11111111 11111111 11111111 00000101 在补码基础上-1得到反码 原码:10000000 00000000 00000000 11111010 符号位不变,其余位取反 如果要人工算 二进制->十进制, 一定要基于原码算。 (1)最高位是符号位,1是负数的意思 (2)其余位加权值 128 + 64 + 32 + 16 + 8 + 2 = 250 如果要计算器算 二进制->十进制, 一定要基于补码算。
4、练习
将如下二进制补码对应的十进制算出来。
11100111
00000000 00000000 00000011 01010010
01100110
11111111 11111111 11111111 11111011
答案:-25,850,102,-5
1.4 1个字节如果用来存储整数的多大值(-128~127)
1个字节: 符号位是0的时候: 最小的二进制补码:00000001 十进制:1 最大的二进制补码:01111111 十进制:127 符号位是1的时候: 最小的二进制补码:10000001 十进值:-127 如果用计算器算,粘的是补码 反码:10000000 原码:11111111 如果是人工口头算,用原码算,最高位代表负数,其余位权值相加:64+32+16+8+4+2+1 特殊的两个值: 00000000 十进制:0 10000000 十进制:-0没有意义,不用它来表示负0 用它来表示-128 首先,最高位是1,代表是负数。 其次,需要满足计算规则 -127-1 = 用补码算 -127的补码:10000001 1的补码: 00000001 相减----------------- 10000000 数学中它是-128,计算器算出来也得是-128
1.5 char类型的数据怎么存储呢(char有编码值,有几种表示方式)
为了在计算机底层也能存储字符:包括字母、标点符号、汉字等,那么一些协会在一起指定了一些标准,最早生成了一个ASCII字符集。这个字符集中为每一个字符规定了一个整数值,它被称为编码值。例如:'0'的编码值是48,'1'的编码值是49,依次类推。'A'的编码值是65,'B'的编码值是66,依次类推。'a'的编码值是97,'b'的编码值是98,依次类推。
ASCII不支持中文等其他字符。计算机要流传到其他国家时,就无法表示其他国家的字符了。
后来逐步延后,到了今天有一个万国码字符集,就是Unicode字符集,它里面包含了所有国家的常用字符,一共65536个字符,编码值范围是[0,65535]。Unicode字符集是兼容ASCII字符集。
char类型的数据在程序中的表示方式有如下几种:
-
单引号,里面直接写字符本身
-
用十进制的Unicode编码值
-
单引号,里面写\u4位的十六进制编码值
public class CharDemo{ public static void main(String[] args){ /* System.out.println('0' + 1 );//49 //char + int System.out.println(0 + 1 );//1 //int + int */ char aLetter1 = 'a'; char aLetter2 = 97; //十进制编码值 char aLetter3 = '\u0061'; //十六进制编码值 \u,表示是Unicode编码值 System.out.println(aLetter1); System.out.println(aLetter2); System.out.println(aLetter3); } }
还有几个特殊的char,它们需要转义:
-
\t:制表符,键盘上的Tab
-
\n:换行符
-
\r:回车符,本行结束符
-
\b:退格键,键盘上Backspace
-
\\:斜杆本身
-
\":双引号
-
\':单引号
public class CharDemo2{ public static void main(String[] args){ char c1 = '\''; System.out.println(c1); char c2 = '"'; System.out.println(c2); String s1 = "\""; System.out.println(s1); String s2 = "'"; System.out.println(s2); char c3 = '\\'; System.out.println(c3); String s3 = "\\"; System.out.println(s3); } }
public class CharDemo3{ public static void main(String[] args){ System.out.println("hello\tworld\tjava"); System.out.println("hello\b\bworld\b\bjava"); System.out.println("hello\rworld\rjava"); System.out.println("hello\nworld\njava"); } }
public class CharDemo4{ 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"); } }
1.6 小数类型的数据怎么存储(记3个结论)
小数类型的存储比前面那些类型都复杂,大家不用过多的研究。下面先抛出结论,再做简单的简绍:
-
无论是float还是double都是==不精确==,因为不是每一个小数都有一个唯一的二进制来表示它的
-
float类型虽然是4个字节,double类型是8个字节,它们都==比long类型的存储范围要大==。因为小数的底层会存储符号位、指数位、尾数位。
-
==double类型比float类型的精度范围更大一些==
-
double类型大约能表示到科学记数法的小数点后15~16位
-
float类型大约能表示到科学记数法的小数点后6~7位
-
后面会学习BigDecimal类型,处理任意精度的小数
-
public class FloatDoubleDemo{ public static void main(String[] args){ float f = 3.14159265685781234F; double d = 3.14159265685781234; System.out.println(f);//3.1415927 System.out.println(d);//3.1415926568578123 } }
以:8.2为例说明它的存储原理
第一步:8.2转为二进制
整数部分8:除2倒取余,得到1000 小数部分0.2:乘2取整数 得到: 00110011........
第二步:把上述二进制值转为科学计数法
科学计数法:整数部分只有1位非零的数字,其余都挪到小数点后面。
8.2 的二进制 1000.00110011........ 科学计数法: 1.00000110011........ * 2的3次方
这么挪的原因是因为底层不想保存和处理小数点。
所有二进制用科学计数法表示之后,有一个共同特点:整数部分都是1,这样的话,就不用表示小数点了,也不用表示整数部分了。
第三步:需要表示符号位、指数位、尾数位
-
符号位:最高位,0是正数,1是负数
-
指数位:本例中指数值是3,3可以用二进制表示 00000011
-
float类型的指数位占8位
-
double类型的指数位占11位
-
-
尾数位:小数点后面的所有二进制位就是尾数位
二、基本数据类型的转换问题(掌握)
boolean不参与任何转换。
1、自动类型转换
-
方向:
-
byte->short->int->long->float->double
-
char->
-
-
当把存储范围小的类型的值 赋值 给存储范围大的类型的变量时,会自动类型提升。
public class DataTypeChangeDemo1{ public static void main(String[] args){ int num = 'a'; System.out.println(num); /* 'a'是char类型,num是int类型,把char类型转为int类型 */ double d = 5; System.out.println(d); /* 5是int类型,d是double,把int类型转为double类型 */ double d2 = 'a'; System.out.println(d2); } }
-
当byte与byte,short与short,char与char,或者它们3个之间的计算,会自动升级为int(特殊)
public class DataTypeChangeDemo2{ public static void main(String[] args){ byte b1 = 1; byte b2 = 2; //byte b3 = b1 + b2; /* b1 + b2结果3已经是int类型 int类型存储范围 > byte类型存储范围 */ //System.out.println(b3); System.out.println(b1+b2); short s1 = 1; short s2 = 2; //short s3 = s1 + s2; System.out.println(s1+s2); char c1 = '0'; char c2 = '1'; System.out.println(c1+c2); //char c3 = c1+c2; } }
-
当多种类型混合运算时,结果是它们中最大的类型
public class DataTypeChangeDemo3{ public static void main(String[] args){ System.out.println(1 + 'a' + 15L + 1.0); // int + char + long + double 结果是double } }
2、强制类型转换
方向:
-
double->float->long->int->short->byte
-
->char
-
当把存储范围大的类型的值 赋值给存储范围小的类型的变量时,就必须使用强制类型转换。这种转换有风险,可能损失精度,可能溢出。
public class DataTypeChangeDemo4{ public static void main(String[] args){ double d = 1.5; int i = (int)d;//当把d里面的1.5赋值给i时,强制把1.5转为int类型 System.out.println(i);//损失精度 int x = 1; int y = 2; System.out.println(x/y);//按照数学是0.5,强制把0.5转为int类型,结果是0 System.out.println((double)x/y); /* 这里先把x强制升级为double 1变为1.0, 然后再计算 1.0 / 2 ,混合运算都升级为double 1.0 / 2.0 结果是0.5 */ byte b1 = 127; byte b2 = 2; byte b3 = (byte)(b1 + b2); System.out.println(b3);//-127 /* 127+2的结果129 129是int类型的话 00000000 00000000 00000000 10000001(补码) 强制转为byte类型 截断,只留下最后一个字节 10000001(补码) */ } }
3、练习题
1、练习题:判断如下代码是否编译通过,如果能,结果是多少? short s1 = 120; short s2 = 8; short s3 = s1 + s2; s1+s2是short+short,结果自动升级为int, int比short大,编译失败 2、练习题:判断如下代码是否编译通过,如果能,结果是多少? short b1 = 120; short b2 = 8; byte b3 = (byte)(b1 + b2);//-128 b1 + b2得到int的结果是128,然后强制类型转换 int类型的128的二进制 00000000 00000000 00000000 10000000 补码 然后强制类型转换,发生截断,只保留1个字节 10000000 补码 对应-128 3、练习题:判断如下代码是否编译通过,如果能,结果是多少? char c1 = '0'; char c2 = '1'; char c3 = c1 + c2; c1+c2是char+char,,结果自动升级为int, int比char大,编译失败 4、练习题:判断如下代码是否编译通过,如果能,结果是多少? char c1 = '0'; char c2 = '1'; System.out.println(c1 + c2); c1+c2是char+char,,结果自动升级为int. println可以支持各种类型的数据的输出,可以输出int值,结果是97 '0'的编码值是48,'1'的编码值是49 5、练习题:判断如下代码是否编译通过,如果能,结果是多少? int i = 4; long j = 120; double d = 34; float f = 1.2; System.out.println(i + j + d + f); float f = 1.2;报错,因为1.2是double类型,要表示float类型必须加F或f 6、练习题:判断如下代码是否编译通过,如果能,结果是多少? int a = 1; int b = 2; double result = a/b; System.out.println(result); a/b是int/int,结果是0 0又赋值给double,又升级为0.0