数据进制-数据类型转换20241220
类型转换 2024/12/20
进制:
- 二进制: 使用
0b或0B开头。- 八进制: 使用
0开头(Java 7 及之后版本)。- 十进制: 直接使用数字(没有前缀)。
- 十六进制: 使用
0x或0X开头。浮点数精度问题:
/** * 浮点数精度问题,float:4字节 double:8字节 * */ float data_5=0.1f; double data_6=1.0/10; System.out.println(data_5==data_6); //输出false float data_7=12321321312321321321f; float data_8=data_7+1; System.out.println(data_7==data_8);//输出true第一个false原因分析:
虽然
data_5和data_6都表示0.1,但由于精度差异,0.1f和0.1(或者1.0 / 10)的表示方式是不同的。因此,data_5和data_6的值可能会略有不同,导致data_5 == data_6的结果为false。
data_5 = 0.1f是单精度浮点数,表示的0.1精度不够,不能精确表示。
data_6 = 1.0 / 10是双精度浮点数,表示的0.1更加精确。
这两者在存储时会有微小的差异,所以即使在数学上0.1是相等的,在计算机的浮点数表示中它们的存储值并不完全相同。解决方案:
在浮点数的比较中,如果你需要判断两个浮点数是否接近,可以使用一个 容差(epsilon)值,而不是直接使用
==来比较。例如:float data_5 = 0.1f; double data_6 = 1.0 / 10; System.out.println(Math.abs(data_5 - data_6) < 1e-6); // 判断差异是否小于某个阈值第二个true的原因分析:
一个非常大的数字
12321321312321321321存储到float类型中。float类型的最大精度约为 7 位有效数字。因此,当你存储12321321312321321321f时,它的值会被截断或舍入,从而失去精度。
float类型的有效数字有限。它能够表示的最大整数范围大致为2^24,也就是16777216。超过这个范围的整数将会丢失精度。你在代码中尝试存储的数字12321321312321321321超出了这个范围,因此它被四舍五入或截断,导致data_7和data_8的值实际上是相同的,因此data_7 == data_8输出true。解决方案:
如果你需要表示更大的数字,应该使用
double类型,它的有效数字约为 15~16 位,或者使用BigDecimal来进行高精度的浮点计算。总结:
- 浮点数比较: 浮点数存储可能会引起精度丢失,因此不要直接用
==来比较。应使用误差范围(epsilon)来判断它们是否近似相等。- 浮点数的精度限制:
float类型精度有限,对于非常大的数值,它可能无法精确表示,导致精度丢失。此时可以使用double类型,或者在需要更高精度时,使用BigDecimalchar数据扩展
/** * 字符型本质还是数字,但是用的是unicode编码 * a对应的就是uincode是\u0061 对应的ASCl码表int值是97 * cha有转义字符 * */ char data_9='a'; char data_10='\u0061'; System.out.println(data_9); System.out.println(data_10); System.out.println("hello\n\tworld!");输出结果:
a a hello world!字符串比较和字符串常量池的问题
String sa = new String("hello\tworld"); String sb = new String("hello\tworld"); System.out.println(sa); // 输出 "hello world" System.out.println(sb); // 输出 "hello world" System.out.println(sa == sb); // 输出 false String sc = "hello\tworld"; String sd = "hello\tworld"; System.out.println(sc); // 输出 "hello world" System.out.println(sd); // 输出 "hello world" System.out.println(sc == sd); // 输出 true原因:
第一部分:
sa和sb的比较
new String("hello\tworld"):当你通过new创建一个字符串对象时,Java 会在堆内存中创建一个新的字符串对象,而不是使用字符串常量池。这意味着sa和sb指向的是两个不同的对象。
sa == sb:这里的==比较的是 对象引用是否相同,也就是sa和sb是否指向同一个内存地址。因为new String()创建了两个不同的对象,它们指向的内存地址不同,所以sa == sb的结果是false。第二部分:
sc和sd的比较字符串常量池:在 Java 中,所有的字符串字面量(即直接赋值的字符串)都会被放到 字符串常量池(String Pool)中。字符串常量池是一个缓存池,Java 会将重复的字符串字面量引用指向同一个内存位置,避免了重复创建相同内容的字符串对象。
sc和sd:这里sc和sd都是通过字面量"hello\tworld"创建的字符串。由于字符串字面量"hello\tworld"已经存在于字符串常量池中,sc和sd会指向同一个对象。也就是说,sc和sd的引用是相同的,指向的是常量池中的同一个字符串对象。
sc == sd:这里的==比较的是 引用是否相同,因为sc和sd引用了同一个字符串常量池中的对象,所以sc == sd的结果是true。其他需要注意的点:
equals()方法:即使两个字符串对象是通过不同的方式创建的,只要它们的内容相同,equals()方法也会返回true。比如:System.out.println(sa.equals(sb)); // 输出 true System.out.println(sc.equals(sd)); // 输出 true字符串常量池的优势:字符串常量池能够节省内存,因为重复的字符串字面量不会被重复创建,所有引用相同内容的字面量会指向同一个对象。
类型转换
/** * 类型转换: * 1.自动转换,小转大 * 2.强制转换:大转小:但是可能出现内存溢出、精度缺失等问题 * byte char short < int < long < float < double * boolean 不涉及转换 * */ char data_11=128; int data_12=data_11;//没有问题,自动转换的 但是反过来就会出问题 System.out.println(data_11);//对应unicode 第128 \u0080 位字符 换成97 就是a System.out.println((int)data_11); System.out.println(data_11==data_12); /***********************/ int data_13=128; byte data_14=(byte)data_13;//首先这里不加强制类型转换会报错。其次这里强制类型转换,大转小,出现内存溢出 System.out.println(data_13); System.out.println(data_14);//这里byte -128~127,转换过来,内存溢出输出结果:
===================================================== //未知字符,打印不出来 换成97 就是a 128 true 128 -128类型转换图:一句话:小转大没问题,大转小须强制且要考虑精度缺失、内存溢出。
graph LR A[byte]==>D[int] B[short]==>D[int] C[char]-->D[int] D-->E[long] E-->F[float] F-->G[double]

浙公网安备 33010602011771号