float 和 double 都是 Java 用来表示带有小数部分的数字(浮点数)的基本数据类型。double 的精度和范围是 float 的两倍,是 Java 中最常用的浮点类型。

基本定义与用途
| 特性 | float (单精度浮点数) |
double (双精度浮点数) |
|---|---|---|
| 类型名称 | float |
double |
| 内存占用 | 32位 (4字节) | 64位 (8字节) |
| 精度 | 大约 7 位十进制有效数字 | 大约 15-16 位十进制有效数字 |
| 表示范围 | 大约 ±3.4E-38 到 ±3.4E+38 | 大约 ±1.7E-308 到 ±1.7E+308 |
| 默认类型 | 不是默认类型 | 是默认类型 |
| 使用场景 | 对内存要求极其严格,且精度要求不高的场景(如:游戏中的坐标、图形学) | 科学计算、金融、大多数需要高精度的场景 |
精度和范围详解
这是理解 float 和 double 最关键的部分。
精度
精度指的是数字能够被准确表示的十进制位数。
float: 只能保证大约 7 位十进制数的准确性。90f是准确的。01f可能会被存储为0,小数点后的精度就丢失了。
double: 能保证大约 15-16 位十进制数的准确性。67这样的数字,double可以精确表示。- 只有当数字超过 16 位时,才会开始丢失精度。
代码示例:
public class PrecisionTest {
public static void main(String[] args) {
float f = 123456789.0f; // 9位数字
double d = 123456789.0;
System.out.println("Float value: " + f); // 输出可能不是 123456789.0
System.out.println("Double value: " + d); // 输出会是 123456789.0
// 一个更明显的例子
float f1 = 1.123456789f;
double d1 = 1.123456789;
System.out.println("Float f1: " + f1); // 输出可能是 1.1234568
System.out.println("Double d1: " + d1); // 输出是 1.123456789
}
}
范围
范围指的是数字可以表示的最大值和最小值(接近于零)。

double 的范围比 float 大得多,可以表示更大或更小的数字。
在 Java 代码中的使用(关键语法)
1 字面量
直接在代码中写一个数字,它默认是什么类型?
- 默认为
double:14,01,-9.8这些带小数点的数字,在 Java 中都被默认视为double类型。 - 如何表示
float字面量:在数字后面加上f或F。float pi = 3.14f;// 正确float pi = 3.14;// 编译错误! 因为 3.14 是 double,不能直接赋值给一个 float(会丢失精度),除非你进行强制类型转换。
2 声明和初始化
// 声明一个 float 变量 float myFloat; // 初始化 myFloat = 10.5f; // 必须带 f // 声明并初始化 double myDouble = 10.5; // 默认就是 double,不需要 d (但可以写 10.5d) // 科学计数法 float f2 = 1.23e5f; // 1.23 * 10^5 double d2 = 1.23E-5; // 1.23 * 10^-5
3 类型转换
由于 double 的精度更高,Java 的类型转换规则如下:
-
double->float: 这是缩小转换,会丢失精度,Java 编译器会报错,除非你使用强制类型转换。
(图片来源网络,侵删)double d = 9.78; // float f = d; // 编译错误: 不兼容的类型: 从double转换到float可能会有损失 float f = (float) d; // 正确,但精度可能丢失
-
float->double: 这是扩大转换,不会丢失信息,编译器会自动完成。float f = 3.14f; double d = f; // 正确,自动转换
-
int->float或double: 整数可以自动转换为浮点数,因为浮点数的范围通常比int大。int i = 100; float f = i; // 正确 double d = i; // 正确
何时选择 float,何时选择 float?
这是一个非常实际的问题。
优先选择 double (99% 的情况)
- 默认选择:除非你有非常充分的理由,否则在处理任何需要小数的计算时,都应该使用
double。 - 性能:在现代的 64 位处理器上,
double的计算速度通常和float一样快,甚至更快,因为硬件原生支持 64 位浮点运算。 - 精度:
double的高精度可以避免很多意想不到的精度问题,尤其是在金融、科学计算等关键领域。 - API 兼容性:Java 的大多数数学库函数(如
Math.sqrt())和System.out.println()在处理浮点数时,都默认使用double。
仅仅在以下情况考虑使用 float
- 内存敏感型应用:当你需要处理海量的浮点数数据,并且内存成为瓶颈时,在移动设备或嵌入式系统中处理大型 3D 模型的顶点坐标(数百万个点),使用
float可以节省一半的内存。 - 文件存储和网络传输:当需要将大量浮点数据写入文件或通过网络发送时,使用
float可以减少 I/O 带宽和存储空间。
重要的注意事项:浮点数不精确
这是所有使用浮点数的程序员必须了解的核心概念。
浮点数在计算机中是以二进制科学计数法存储的,而很多十进制小数在二进制中是无限循环的,无法精确表示。
经典示例:
public class FloatingPointTrap {
public static void main(String[] args) {
// 预期结果应该是 0.1
System.out.println(0.1 + 0.2); // 输出: 0.30000000000000004
// 预期结果应该是 false
System.out.println(0.1 + 0.2 == 0.3); // 输出: false
}
}
为什么会这样?
1 和 2 在二进制中都是无限循环小数,计算机只能存储它们的近似值,当这两个近似值相加时,结果也只是一个近似值,它不等于 3 的近似值。
如何正确比较浮点数? 不要使用 或 来直接比较浮点数,应该判断它们的差值是否在一个非常小的“误差范围”(epsilon)内。
public class FloatingPointComparison {
public static void main(String[] args) {
double a = 0.1 + 0.2;
double b = 0.3;
// 定义一个很小的误差范围
double epsilon = 0.000001;
// 判断 a 和 b 的差值是否在误差范围内
if (Math.abs(a - b) < epsilon) {
System.out.println("a 和 b 在误差范围内被认为是相等的。");
} else {
System.out.println("a 和 b 不相等。");
}
}
}
| 特性 | float |
double |
|---|---|---|
| 核心思想 | 32位单精度 | 64位双精度 |
| 何时用 | 内存极其紧张时 | 默认选择,绝大多数情况 |
| 精度 | ~7位 | ~15-16位 |
| 字面量 | 数字后加 f 或 F |
默认,数字后可加 d 或 D |
| 最大陷阱 | 精度不足 | 浮点数不精确,不能直接用 比较 |
记住这个黄金法则:除非你明确知道需要 float 并且有充分的理由(如内存限制),否则请始终使用 double。
