浮点数据类型的底层存储方式,char类型的底层处理,基本数据类型转换,String类型的转换,运算符,输出(三)

343 阅读14分钟

float和double在计算机中的存储

(1)一定是二进制存储 (2)最高位也是符号位 (3)float占4个字节,32位 double占8个字节,64位 (4)float来说,8位指数位 double来说,11位指数位 (5)float来说,23位尾数位 double来说,52位尾数位

结论(理解) (1)当小数的二进制尾数超过23或52之后,会截断,就会导致数据有差异,即不精确, 所以,我们把float和double称为浮点数。 (2)float和double类型能表示的数字范围比long类型等整数都要大 byte:1个字节 short:2个字节 int:4个字节 long:8个字节 float:4个字节 double:8个字节 (3)double类型比float类型精度相对要大一点 float类型,能表示到小数点7-8位,这里是十进制科学计数法的小数点右7-8位 double类型,能表示到小数点15-16位,这里是十进制科学计数法的小数点右7-8位

  • 例如:8.25 第一步:转为二进制 8-->1000 0.25-->0.01

结合起来:1000.01

  • 第二步:处理小数点 因为小数点很难表示,所以它干脆不表示

    对刚刚的二进制进行处理,把它用“科学计数法”表示。 以十进制的数字为例,科学计数法演示一下: 256.87564 --> 科学计数法 2.5687564 * 10的2次方 0.000675 --> 科学计数法 6.75 * 10的-4次方

二进制的科学计数法: 1000.01 --> 科学计数法 1.00001 * n的3次方 1010100.0011 --> 科学计数法 1.0101000011 * n的6次方

发现:用科学计数法表示之后,小数点的左边永远是1(因为科学计数法的整数部分必须非0,而且是1位)

所以,这个整数部分的1就不存了,小数点也不存了

  • 第三步:需要存储小数点右边的尾数 和 幂次方 对于float来说,8位用来存储幂次方,称为指数位 对于double来说,11位用来存储幂次方,称为指数位

对于float来说,32-1位符号位-8位指数位 = 23位的尾数位 对于double来说,64-1位符号位-11位指数位 = 52位的尾数位

8种基本数据类型: byte:1个字节 short:2个字节 int:4个字节 long:8个字节 float:4个字节 double:8个字节 char:2个字节 boolean:1个字节/1位 boolean在程序中只能表示为true或false,底层用1表示true,0表示false

由于小数是不能在计算机底层中准确表示的所以不能用==来判断两个浮点数类型相等。

double d1,d2;
//...
if(d1==d2){}//是错误的表达式,一定要避免

char类型底层怎么处理的?

(1)所有的字符都要转为二进制,即字符要用整数表示,这个整数就是字符的编码值 字符集:字符与整数编码对应的表格 最早的计算机只支持128个字符,有一个字符集称为ASCII码字符集。 欧洲等一些国家对ASCII码字符集进行扩展,扩展到256个。后面扩展的128个字符是不通用,在不同国家某个编码对应的字符是不同的。 亚洲等国家又扩展字符集,出现了很多很多不同的字符集。 例如: 中国,有GB2312(早期),GBK,Big5等字符集 现在默认用的是GBK。 后来,随着互联网的发展,一种更广的字符集应运而生,Unicode字符集,它支持全球所有的字符。

在Unicode字符集之前,字符集和编码方式是统一的, 例如:GBK既是字符集又是编码方式。 在Unicode字符集之后,要考虑很多因素,例如:一个二进制流到底要表示成几个字符等 Unicode字符集设定自己的几套解析的标准,称为编码方式。 有UTF-8,UTF-16等

二进制数据流: 11110101 10101100 10100010 10101111 01010100 ISO8859-1(ASCII的扩展版256位) 5个字符 GBK: 3个字符 UTF-8: 2个字符

(2)底层char类型是没有负数的,全部是正数 1个字节,能表示的编码值范围是:0-255(一共256) 2个字节,能表示的编码值范围是:0-65535 现在Java采用的就是Unicode字符集。

(3)所有的字符集都向下兼容ASCII码字符集 几个特殊的字符的编码大家需要掌握(必须记住) 'a'-->97, 'b'-->98 ... 'A'-->65, 'B'-->66 ... '0'-->48, '1'-->49 ... null-->0 TAB-->9

char类型在程序中如何表示?

(1)用单引号将一个字符引起来 例如:'a'

(2)可以直接用十进制编码值表示 十进制编码值的范围是:0-65535

(3)可以用十六进制表示编码值,一般是ASCII以外的才会用这种方式 例如:'尚'对应的编码值是23578(十进制),十六进制值是5C1A '\u5C1A' (4)对于一些特殊字符,还可以使用转义的方式表示 例如: 换行 '\n' TAB '\t' 从下一个制表位开始输出,每一个制表位默认是8位 退格:'\b' 回车:'\r' 结束本行 单引号:''' 双引号:'"' \本身:'\'

注意:

char类型变量在计算时会转换为int类型,

但char类型的常量计算时只要不超出char值的范围就还是char类型。

基本数据类型转换

(1)自动类型转换

  • A:当存储范围小的变量/值等赋值给存储范围大的变量时,可以自动类型提升 byte-->short-->int-->long-->float-->double char--> B:当byte与byte,short与short,char与char,或者byte,short,char之间的运算,都会自动升级为int类型。 C:boolean不参与任何转换 D:当多种数据类型混合运算,按照它们当中最大的处理

(2)强制类型转换 格式:(最终要转为的数据类型)值/表达式

  • A:当我们把存储范围大的类型的变量/表达式等赋值给存储范围小的变量时,就需要强制类型转换 byte<--short<--int<--long<--float<--double char<-- 提示:这种情况强制类型转换有风险,可能会溢出或损失精度

  • B:当我们想要故意提示某个变量/值的数据类型,也可以使用强制类型转换 提示:这种情况强制类型转换没有风险

  • C:boolean不参与任何转换

String类型与基本数据类型的转换

(1)String类型与任意数据类型进行了“+”,结果都是字符串 (2)任何数据类型的值,只要加"",就是字符串 (3)String类型不能通过强制类型转换为基本数据类型

运算符

(1)分类

1.按照功能划分:

  • 算术运算符
  • 赋值运算符
  • 比较运算符/关系运算符
  • 逻辑运算符
  • 条件运算符:? :
  • 位运算符

2.按照需要的操作数的数量划分:

  • 一元运算符: +a,a++
  • 二元运算符: a+b, a>b, a = b
  • 三元运算符: ? :

算术运算符

加:+ (1)如果是基本数据类型(boolean除外),+求和 (2)如果是有字符串参与,+表示拼接 减:- 乘:* 除:/ 如果是两个整数类型相除,结果只保留整数部分 模:% (1)求余数 (2)余数的正负号,与被除数一样 正:+ 负:- 自增:++,自增1 自减:--,自减1

以自增为例: (1)当自增表达式是独立的一个语句,++在前在后没有区别,结果都一样,都是自增变量+1 例如: i++; ++i;

(2)当自增表达式不是独立的语句,它是其他运算或者是语句的一部分,那么++在前在后不一样。 ++a:++在前,先自增(+1),再取自增变量的值,参与其他运算 a++:++在后,先取自增变量的值,然后自增变量自增(+1),再用取出来的值参与其他运算

赋值运算符

最最基本的赋值运算符是= 作用:把=右边的值/表达式结果赋值给=左边的变量,即修改左边变量的值

(1)=左边一定是一个变量 (2)=的优先级是最低的,一定是最后算

赋值运算符还有扩展的系列: +=,-=,*=,/=,%=....

(1)把=右边看成一个整体,然后用=左边的变量与右边的值/表达式的结果做+,-等运算。 (2)+=,-=,*=,/=,%=....算完的结果类型的范围如果超过左边的变量,会隐含强制类型转换, 所以结果可能是错误的(溢出或损失精度)

关系运算符/比较运算符

大于:> 小于:< 等于:== 大于等于:>= 小于等于:<= 不等于:!=

(1)关系运算符通常用在条件判断中 (2)关系运算符的表达式结果只有两种:true/false

逻辑运算符

逻辑与:两个条件同时成立 & 只有&符号的两边都是true,结果才为true true & true 结果是true true & false 结果是false false & true 结果是false false & false 结果是false 逻辑或:| 只要|符号的两边有一边是true,结果就为true true | true 结果是true true | false 结果是true false | true 结果是true false | false 结果是false 逻辑异或:^ 只有^符号的两边一边是false,一边是true,结果才为true true ^ true 结果是false true ^ false 结果是true false ^ true 结果是true false ^ false 结果是false 逻辑非:! !true 变为false !false 变为true 短路与:&& 只有&&符号的两边都是true,结果才为true true && true 结果是true true && false 结果是false false && ? 结果是false &&的效率比&高,因为当&&的左边为false时,右边就不看了,结果直接是false 短路或 只要||符号的两边有一边是true,结果就为true true || ? 结果是true false || true 结果是true false || false 结果是false ||的效率比|高,因为当||的左边是true时,右边就不看了,结果直接是true

(1)逻辑运算符是用来表示两个条件之间的关系 (2)逻辑运算符表达式的结果仍然是true和false (3)逻辑运算符表达式仍然作为条件使用

条件运算符,唯一的三元运算符

格式: 条件表达式 ? 结果表达式1 : 结果表达式2 运算: 当条件表达式成立时,取结果表达式1的结果,否则取结果表达式2

位运算符(效率最高的运算符)

按位与:& 只有对应的二进制位都是1,结果才为1 1 & 1 结果是1 1 & 0 结果是0 0 & 1 结果是0 0 & 0 结果是0 按位或:| 只要对应的二进制位有1,结果就为1 1 | 1 结果是1 1 | 0 结果是1 0 | 1 结果是1 0 | 0 结果是0 按位异或:^ 只有对应的二进制位一个是1一个是0,结果才为1 1 ^ 1 结果是0 1 ^ 0 结果是1 0 ^ 1 结果是1 0 ^ 0 结果是0 按位取反:~ ~1:0 ~0:1

左移:<< (1)整体二进制左移,右边补0, (2)快速口诀,左移几位相当于乘以2的几次方 (3)当左移的位数超过 当前数据类型的总位数,那么要减去总位数 例如:int类型总位数是32,左移35位的话,相当于左移3位

只有左移<<会发生循环的现象,比如说左移越界的1,会在最右边出现

右移:>> (1)整体二进制右移,如果原来最高位是0,左边补0,原来最高位是1,左边补1 (2)快速口诀,右移几位相当于除以2的几次方,向下取整 (3)当右移的位数超过 当前数据类型的总位数,那么要减去总位数 例如:int类型总位数是32,右移35位的话,相当于右移3位 无符号右移:>>> (1)整体二进制右移,左边补0,不看符号位

class Test12BitOperator{
	public static void main(String[] args){
		System.out.println(1 & 2);
		/*
		1:0000 0000 0000 0000 0000 0000 0000 0001
		2:0000 0000 0000 0000 0000 0000 0000 0010
		&:0000 0000 0000 0000 0000 0000 0000 0000
		*/
		
		System.out.println(3 & 5);
		/*
		3:0000 0000 0000 0000 0000 0000 0000 0011
		5:0000 0000 0000 0000 0000 0000 0000 0101
		&:0000 0000 0000 0000 0000 0000 0000 0001
		*/
		
		System.out.println(-3 & 5);
		/*
		-3:
		  原码:1000 0000 0000 0000 0000 0000 0000 0011
		  反码:1111 1111 1111 1111 1111 1111 1111 1100
		  补码:1111 1111 1111 1111 1111 1111 1111 1101
		 5:    0000 0000 0000 0000 0000 0000 0000 0101
		 &:    0000 0000 0000 0000 0000 0000 0000 0101
		*/
		
		System.out.println(1 | 2);
		/*
		1:0000 0000 0000 0000 0000 0000 0000 0001
		2:0000 0000 0000 0000 0000 0000 0000 0010
		|:0000 0000 0000 0000 0000 0000 0000 0011
		*/
		
		System.out.println(-3 | 5);
		/*
		-3:
		  原码:1000 0000 0000 0000 0000 0000 0000 0011
		  反码:1111 1111 1111 1111 1111 1111 1111 1100
		  补码:1111 1111 1111 1111 1111 1111 1111 1101
		 5:    0000 0000 0000 0000 0000 0000 0000 0101
		 |:    1111 1111 1111 1111 1111 1111 1111 1101(补码)
		*/
		
		System.out.println(1 ^ 2);
		/*
		1:0000 0000 0000 0000 0000 0000 0000 0001
		2:0000 0000 0000 0000 0000 0000 0000 0010
		^:0000 0000 0000 0000 0000 0000 0000 0011
		*/
		
		System.out.println(-3 ^ 5);
		/*
		-3:
		  原码:1000 0000 0000 0000 0000 0000 0000 0011
		  反码:1111 1111 1111 1111 1111 1111 1111 1100
		  补码:1111 1111 1111 1111 1111 1111 1111 1101
		 5:    0000 0000 0000 0000 0000 0000 0000 0101
		 ^:    1111 1111 1111 1111 1111 1111 1111 1000(补码)
				1111 1111 1111 1111 1111 1111 1111 0111(反码)
				1000 0000 0000 0000 0000 0000 0000 1000(原码)-8
		*/
		
		System.out.println(~1);
		/*
		1: 0000 0000 0000 0000 0000 0000 0000 0001
		~1:1111 1111 1111 1111 1111 1111 1111 1110(补码)
			1111 1111 1111 1111 1111 1111 1111 1101(反码)
			1000 0000 0000 0000 0000 0000 0000 0010(原码)-2
		*/
		
		System.out.println(1 << 5);
		/*
		1: 	0000 0000 0000 0000 0000 0000 0000 0001
		1<<5    0000 0000 0000 0000 0000 0000 0010 0000
		
		*/
		
		System.out.println(11 << 2); //44
		/*
		11:	0000 0000 0000 0000 0000 0000 0000 1011
		11<<2: 0000 0000 0000 0000 0000 0000 0010 1100
		*/
		
		System.out.println(1 << 35);//8  等价于1<<(35-32) 本来应该消失的1,在右侧移动回来了
		
		System.out.println(1 >> 5);
		/*
		1: 	0000 0000 0000 0000 0000 0000 0000 0001
		1>>5    0000 0000 0000 0000 0000 0000 0000 0000
		*/
		
		System.out.println(100 >> 5);//3  100/2的5次=100/32  只保留整数部分,向下取整
		/*
		100: 	0000 0000 0000 0000 0000 0000 0110 0100
		100>>5:0000 0000 0000 0000 0000 0000 0000 0011
		*/
		
		System.out.println(-1 >> 5);
		/*
		-1:原码:1000 0000 0000 0000 0000 0000 0000 0001
		    反码:1111 1111 1111 1111 1111 1111 1111 1110
			补码:1111 1111 1111 1111 1111 1111 1111 1111
		-1>>5:   1111 1111 1111 1111 1111 1111 1111 1111(补码)
		*/
		
		System.out.println(-100 >> 35); //-100/2的3次=  -100/8 -13 向下取整
		/*
		-100:
			原码:1000 0000 0000 0000 0000 0000 0110 0100
			反码:1111 1111 1111 1111 1111 1111 1001 1011
			补码:1111 1111 1111 1111 1111 1111 1001 1100
		-100>>35等价于-100>>3
				  1111111 1111 1111 1111 1111 1111 1001 1(补码)
				  1111111 1111 1111 1111 1111 1111 10010(反码)
				  1000000 0000 0000 0000 0000 0000 01101(原码)
		*/
		
		System.out.println(-1 >>> 5);
		/*
		-1:原码:1000 0000 0000 0000 0000 0000 0000 0001
		    反码:1111 1111 1111 1111 1111 1111 1111 1110
			补码:1111 1111 1111 1111 1111 1111 1111 1111
		-1>>>5:  0000 01111 1111 1111 1111 1111 1111 111  (134217727)
		*/
	}
}

输出

(1)System.out.println(xxx); 输出xxx之后换行 (2)System.out.print(xxx); 输出xxx之后不换行 (3)System.out.printf("格式符号" , 变量列表); 了解,看看就完了,是兼容C语言的输出习惯,Java基本上不用格式化输出 小数:%f,如果要保留小数点后几个 %.几位f

仅了解即可,如有保留小数点后几位的需求,最好不要使用这种方法,开发过程中也不会在控制台进行输出

整数:%d 字符串:%s boolean:%b char:%c

class Test13Out{
	public static void main(String[] args){
		System.out.println("hello");
		System.out.println("world");
		
		System.out.println("-----");
		System.out.print("atguigu");
		System.out.print("java");
		
		System.out.println("-----");
		System.out.print("atguigu\n");
		System.out.print("java");
		System.out.println("-----");
		
		double d = 13.45623;
		System.out.printf("%.2f\n", d);
		
		char c = 'a';
		System.out.printf("%c" , c);
	}
}