java.lang.Double
是 Java 中用于封装基本类型 double
的包装类(Wrapper Class),属于 Java 基本数据类型包装体系的一部分。它不仅提供了 double
类型的面向对象表示,还包含丰富的工具方法用于字符串转换、数值比较、特殊值判断等操作。
📚 一、核心概念
1. 基本信息
- 类名:
java.lang.Double
- 所属包:
java.lang
(自动导入) - 继承关系:
public final class Double extends Number implements Comparable<Double>
- 不可变性:
Double
是不可变对象,一旦创建其值不能更改。 - 默认值:在对象字段中未初始化时为
null
(区别于基本类型double
的默认值0.0
)。
2. 数据范围与精度
double
是 64 位双精度浮点数(IEEE 754 标准)- 最大值:
Double.MAX_VALUE ≈ 1.7976931348623157E308
- 最小正数:
Double.MIN_VALUE ≈ 4.9E-324
- 精度:约 15-17 位有效数字
- 特殊值:
Double.POSITIVE_INFINITY
(正无穷)Double.NEGATIVE_INFINITY
(负无穷)Double.NaN
(Not-a-Number,非数字)
3. 自动装箱与拆箱(Autoboxing/Unboxing)
从 Java 5 开始支持:
Double d1 = 3.14; // 自动装箱:double → Double
double d2 = d1; // 自动拆箱:Double → double
⚠️ 注意:
Double
的构造函数在 Java 9 中已标记为 @Deprecated,应避免使用。
🛠️ 二、操作步骤(非常详细)
✅ 步骤 1:创建 Double 对象
方法 1:使用静态工厂方法 valueOf()
(推荐)
Double d1 = Double.valueOf(3.14); // double → Double
Double d2 = Double.valueOf("3.14"); // String → Double
// 示例:解析科学计数法
Double sci = Double.valueOf("1.23E4"); // 12300.0
✅ 推荐理由:
valueOf()
可能使用缓存(虽然Double
缓存不如Integer
明显),且是标准做法。
方法 2:自动装箱(简洁写法)
Double d = 3.14; // 推荐,简洁
❌ 不推荐:使用构造函数
@Deprecated(since="9")
Double d = new Double(3.14); // 已过时,避免使用
✅ 步骤 2:将 Double 转换为基本类型 double
Double d = Double.valueOf(3.14);
double primitive = d.doubleValue(); // 显式拆箱
double autoUnbox = d; // 自动拆箱(推荐简洁写法)
⚠️ 若
d == null
,调用.doubleValue()
或自动拆箱会抛出NullPointerException
✅ 步骤 3:字符串 ↔ Double 相互转换
将字符串解析为 Double
try {
Double d1 = Double.parseDouble("3.14"); // 返回 double(基本类型)
Double d2 = Double.valueOf("3.14"); // 返回 Double(对象)
Double inf = Double.valueOf("Infinity"); // 正无穷
Double negInf = Double.valueOf("-Infinity"); // 负无穷
Double nan = Double.valueOf("NaN"); // NaN
} catch (NumberFormatException e) {
System.err.println("字符串格式错误:" + e.getMessage());
}
将 Double 转为字符串
Double d = 3.14;
String s1 = d.toString(); // "3.14"
String s2 = String.valueOf(d); // 同上
String s3 = "" + d; // 隐式调用 toString()
// 特殊值字符串表示
System.out.println(Double.POSITIVE_INFINITY); // "Infinity"
System.out.println(Double.NEGATIVE_INFINITY); // "-Infinity"
System.out.println(Double.NaN); // "NaN"
✅ 步骤 4:比较两个 Double 值
方法 1:使用 compareTo()
Double a = 3.14;
Double b = 2.71;
int result = a.compareTo(b);
// result < 0 → a < b
// result = 0 → a == b
// result > 0 → a > b
// 特殊值比较规则:
// NaN > 任何值(包括自己)
// 正无穷 > 任何有限值
// 负无穷 < 任何有限值
方法 2:使用 equals()
(注意自动拆箱陷阱)
Double a = 3.14;
Double b = 3.14;
System.out.println(a == b); // false(对象引用不同)
System.out.println(a.equals(b)); // true(值相等)
// 特殊:Double.NaN.equals(Double.NaN) → true
// 但:Double.NaN == Double.NaN → false(JVM 层面)
方法 3:使用 Double.compare(double x, double y)
int cmp = Double.compare(a, b); // 返回 -1, 0, 1
// 推荐:避免自动拆箱 null 问题
✅ 步骤 5:判断特殊值
Double d = getSomeValue();
if (d.isInfinite()) {
System.out.println("无穷大");
} else if (d.isNaN()) {
System.out.println("非数字");
} else if (d.isFinite()) {
System.out.println("有限值");
}
d.isInfinite()
:判断是否为±Infinity
d.isNaN()
:判断是否为NaN
Double.isFinite(d)
:Java 8+,判断是否为有限值
❌ 三、常见错误
错误 | 描述 | 修复方式 |
---|---|---|
NullPointerException |
对 null 的 Double 调用 .doubleValue() |
使用前判空或用 Optional<Double> |
NumberFormatException |
解析非法字符串如 "abc" 、"3.14.15" |
使用 try-catch 包裹 parseDouble |
浮点数精度误差 | 0.1 + 0.2 != 0.3 |
使用 BigDecimal 或误差比较 |
== 比较浮点数 |
d1 == d2 可能因精度失败 |
改用 equals() 或误差范围比较 |
NaN 比较陷阱 |
d == Double.NaN 永远为 false |
使用 d.isNaN() 判断 |
⚠️ 四、注意事项
浮点数精度问题:
double a = 0.1 + 0.2; double b = 0.3; System.out.println(a == b); // false!
✅ 正确比较方式:
double epsilon = 1e-10; if (Math.abs(a - b) < epsilon) { ... }
null 安全性:
Double
可为null
,而double
不能。在数据库映射、JSON 反序列化中常见。
自动拆箱风险:
Double d = null; double x = d; // 运行时抛出 NullPointerException
NaN 的特殊性:
NaN != NaN
(JVM 层面)- 但
Double.NaN.equals(Double.NaN)
返回true
- 所有涉及
NaN
的算术运算结果为NaN
线程安全:
Double
对象本身是不可变的,因此是线程安全的。
💡 五、使用技巧
技巧 | 说明 |
---|---|
✅ 优先使用 valueOf() |
标准做法,避免构造函数 |
✅ 使用 Optional<Double> 防 null |
函数式编程中推荐 |
✅ 用 Double.compare() 替代减法比较 |
避免溢出和精度问题 |
✅ 使用 isInfinite() / isNaN() 判断特殊值 |
比字符串比较更高效 |
✅ 使用 strictfp 关键字保证跨平台浮点一致性 |
在类或方法上声明 |
✅ 高精度计算用 BigDecimal |
避免 double 精度问题 |
// 示例:安全比较两个 Double(含 null 处理)
int safeCompare(Double a, Double b) {
return Double.compare(
a != null ? a : 0.0,
b != null ? b : 0.0
);
}
🏆 六、最佳实践与性能优化
实践 | 说明 |
---|---|
✅ 使用 Double.valueOf() 创建实例 |
避免构造函数 |
✅ 避免频繁装箱拆箱 | 在循环中尽量使用 double 而非 Double |
✅ 在集合中谨慎使用 Double |
List<Double> 比 double[] 占用更多内存和 GC 压力 |
✅ 使用 Double.compare() 进行安全比较 |
比 a - b 更安全 |
✅ 使用 Objects.equals(a, b) 安全比较 Double |
自动处理 null |
✅ 高频计算使用原生 double |
提升性能,减少 GC |
✅ 金融/高精度场景使用 BigDecimal |
避免浮点误差 |
📊 性能对比示例
// 慢:频繁装箱
List<Double> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(Double.valueOf(i * 0.1)); // 创建对象,GC 压力大
}
// 快:使用原生数组
double[] arr = new double[100000];
for (int i = 0; i < 100000; i++) {
arr[i] = i * 0.1;
}
📝 七、总结
项目 | 内容 |
---|---|
核心作用 | 包装 double 类型,支持对象操作、泛型、null 值、特殊值处理 |
创建方式 | 推荐 Double.valueOf(x) 或自动装箱 |
字符串转换 | parseDouble() / valueOf(String) + try-catch |
比较方法 | compareTo() 、equals() 、Double.compare() |
特殊值处理 | isInfinite() 、isNaN() 、POSITIVE_INFINITY 等 |
注意事项 | null 安全、自动拆箱陷阱、浮点精度误差、NaN 特性 |
最佳实践 | 少装箱、多用原生、null 防护、精度敏感用 BigDecimal |
性能建议 | 循环/高频计算用 double ;集合中权衡内存与功能 |
✅ 一句话掌握精髓:
用
Double.valueOf()
创建,用parseDouble()
解析,用.equals()
和compareTo()
比较,警惕null
和自动拆箱,浮点比较用误差范围,高精度计算用BigDecimal
。
📌 适用场景速查:
场景 | 推荐用法 |
---|---|
JSON/数据库字段映射 | Double (支持 null) |
集合存储(如 List<Double> ) |
可用,但注意性能 |
高频数学计算 | 使用 double 原生类型 |
比较大小 | Double.compare(a, b) |
字符串转数字 | Double.parseDouble(str) 或 valueOf(str) |
处理无穷大/NaN | 使用 isInfinite() / isNaN() |
金融计算 | 使用 BigDecimal ,避免 Double |
掌握 Double
类,是 Java 开发中处理浮点数、解析字符串、与数据库交互的基础技能。正确使用,可避免 NullPointerException
、NumberFormatException
、浮点精度误差等常见问题,提升代码健壮性与准确性。