数据进制-数据类型转换20241220

类型转换 2024/12/20

进制:

  1. 二进制: 使用 0b0B 开头。
  2. 八进制: 使用 0 开头(Java 7 及之后版本)。
  3. 十进制: 直接使用数字(没有前缀)。
  4. 十六进制: 使用 0x0X 开头。

浮点数精度问题:

/**
     * 浮点数精度问题,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_5data_6 都表示 0.1,但由于精度差异0.1f0.1(或者 1.0 / 10)的表示方式是不同的。因此,data_5data_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_7data_8 的值实际上是相同的,因此 data_7 == data_8 输出 true

解决方案:

如果你需要表示更大的数字,应该使用 double 类型,它的有效数字约为 15~16 位,或者使用 BigDecimal 来进行高精度的浮点计算。

总结:

  • 浮点数比较: 浮点数存储可能会引起精度丢失,因此不要直接用 == 来比较。应使用误差范围(epsilon)来判断它们是否近似相等。
  • 浮点数的精度限制: float 类型精度有限,对于非常大的数值,它可能无法精确表示,导致精度丢失。此时可以使用 double 类型,或者在需要更高精度时,使用 BigDecimal
char数据扩展
 /**
     * 字符型本质还是数字,但是用的是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

原因:

第一部分:sasb 的比较

new String("hello\tworld"):当你通过 new 创建一个字符串对象时,Java 会在堆内存中创建一个新的字符串对象,而不是使用字符串常量池。这意味着 sasb 指向的是两个不同的对象。
sa == sb:这里的 == 比较的是 对象引用是否相同,也就是 sasb 是否指向同一个内存地址。因为 new String() 创建了两个不同的对象它们指向的内存地址不同,所以 sa == sb 的结果是 false

第二部分:scsd 的比较

字符串常量池:在 Java 中,所有的字符串字面量(即直接赋值的字符串)都会被放到 字符串常量池(String Pool)中。字符串常量池是一个缓存池,Java 会将重复的字符串字面量引用指向同一个内存位置避免了重复创建相同内容的字符串对象

scsd这里 scsd 都是通过字面量 "hello\tworld" 创建的字符串由于字符串字面量 "hello\tworld" 已经存在于字符串常量池中scsd 会指向同一个对象。也就是说,scsd 的引用是相同的,指向的是常量池中的同一个字符串对象。

sc == sd:这里的 == 比较的是 引用是否相同,因为 scsd 引用了同一个字符串常量池中的对象,所以 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]
posted @ 2024-12-20 16:05  panghuhu~  阅读(84)  评论(0)    收藏  举报