做笔试题的时候经常会遇到一些看起来比较简单,但是又比较考验基础的题目。
比如遇到的:
问输出结果
float f1=20f;
float f2=20.3f;
float f3=20.5f;
double d1=20;
double d2=20.3;
double d3=20.5;
// 问以下输出结果
System.out.println(f1==d1);
System.out.println(f2==d2);
System.out.println(f3==d3);
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b"; // ab 常量池
String s4 = s1 + s2; // new String("ab")
String s5 = "ab";
String s6 = s4.intern();
System.out.println(s3 == s4); // false
System.out.println(s3 == s5); // true
System.out.println(s3 == s6); // true
String x2 = new String("c") + new String("d");
x2.intern();
String x1 = "cd";
System.out.println(x1 == x2); //false
浮点数
先来第一部分浮点数。
我认为,如果对一个类型的问题需要犹豫很久,那么就是对这个问题的基础还认识不够深。
我们都知道,计算机存储小数的采用的是 浮点数。为什么叫浮点?顾名思义就是,表示小数点是可以浮动的。
比如 1000.001 这个二进制数,可以表示成 1.000001 x 2^3,类似于数学上的科学记数法。
计算机使用的浮点数,一般采用的是 IEEE 754 制定的国际标准。
无论是32位的float,还是64位的 double,根据文档可以分为三部分:
- 符号位:表示数字是正数还是负数,为 0 表示正数,为 1 表示负数;
- 指数位:指定了小数点在数据中的位置,指数可以是负数,也可以是正数。
- 尾数位:小数点右侧的数字,也就是小数部分,比如二进制 1.0001 x 2^(-2),尾数部分就是 0001
根据位数就可以知道,float 指数部分的最大有效值为254(有一个为特殊值), 小数部分最小为2的-23次方
double 的尾数部分是 52 位, 指数是11位,double 相比 float 能表示更大的数值范围。
要深刻了解题目的答案,我们需要了解转换截止。
那二进制小数,是如何转换成二进制浮点数的呢?
- 把小数点,移动到第一个有效数字后面,即将 1010.101 右移 3 位成 1.010101,右移 3 位就代表 +3,左移 3 位就是 -3。
- 指数位为把移动的位数再加上偏移量,float 的话偏移量是 127,相加后就是指数位的值
- 1.010101 这个数的小数点右侧的数字就是 float 里的尾数」,由于尾数位是 23 位,则后面要补充 0,所以最终尾数位存储的数字是 01010100000000000000000。
为什么要加上偏移量?
最根本的原因是因为计算机计算有符号数比无符号数麻烦。
IEEE 标准规定单精度浮点的指数取值范围是 -126 ~ +127,为了把指数转换成无符号整数,就要加个偏移量,这样指数就不会出现负数了。
比如,指数如果是 8,则实际存储的指数是 8 + 127(偏移量)= 135,即把 135 转换为二进制之后再存储,而当我们需要计算实际的十进制数的时候,再把指数减去 偏移量。
而我们从浮点数转化为十进制,也很简单, 以float为例。
符号位 ✖️ (1 + 尾数位) ✖️ 2的(指数- 127)次方
二进制转换
而当二进制都无法表示完一个小数时,计算机只能以最逼近的小数表示,
比如十进制 0.1 在转换成二进制小数的时候,是一串无限循环的二进制数,计算机是无法表达无限循环的二进制数的,毕竟计算机的资源是有限。
比如我们可以利用这个网站: 二进制计算
可以简单的帮我们计算浮点数
我们可以来看一下题目的问题
float f1=20f;
float f2=20.3f;
float f3=20.5f;
double d1=20;
double d2=20.3;
double d3=20.5;
// 问以下输出结果
System.out.println(f1==d1); //true
System.out.println(f2==d2); //false
System.out.println(f3==d3); // true
输入进去, float 的 20.5, 和 double 的 20.5
float:
Double:
我们可以看到,除去double的小数点后很多的0,其实它们的数值是一样的。
所以我们可以很自然的联想到,循环的或者位数过长的小数,float和double的值是不一样的,因为double会多出来几十位的小数
20.3的double
20.3的float
同样的,在计算机中 0.1 + 0.2 并不等于完整的 0.3, 因为 0.1 和 0.2 都不是能用有限二进制位表达的数,那两个近似数相加,得到的必然也是一个近似数。
比如我们在浏览器的控制台中输入如下就可以看到,
字符串
只需记住几点
- 直接声明的字符串在jvm的常量池中
- intern可以放进常量池中
- new String在对象堆中
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b"; // ab 常量池
String s4 = s1 + s2; // new String("ab")
String s5 = "ab";
String s6 = s4.intern();
System.out.println(s3 == s4); // false
System.out.println(s3 == s5); // true
System.out.println(s3 == s6); // true
String x2 = new String("c") + new String("d");
x2.intern();
String x1 = "cd";
System.out.println(x1 == x2); //true
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。