Java源码分析(二)Double

本篇是源码分析的第二篇,上篇我们一起分析了Integer类的源码,本篇一起学习下Double类的源码,看下其实现。

一、Double类图

首先,相比Integer,Double类的源码只有1000+行代码。如下是Integer及其关联类/接口的类图:

通过Integer类的类图,我们总结下它的特点:

  • Double类继承自抽象类Number
  • Double类实现了Comparable接口
  • Double类使用final修饰,因此不可以有子类(不能被继承)

二、String转Double

同Integer类似,在实际工作中,我们用的比较多的,仍然是String转Double。Java也是给我们提供了两个方法:

1、Double.parseDouble

java 复制代码
    public static double parseDouble(String s) throws NumberFormatException {
        return FloatingDecimal.parseDouble(s);
    }

可以看到,parseDouble并非在Double类中实现的,而是借助FloatingDecimal类去实现:

java 复制代码
    public static double parseDouble(String s) throws NumberFormatException {
        return readJavaFormatString(s).doubleValue();
    }

readJavaFormatString方法返回ASCIIToBinaryConverter:

java 复制代码
static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {...}

而ASCIIToBinaryConverter接口有两个方法,分别是doubleValue()和floatValue(),显而易见,分别是转double和转float的方法:

java 复制代码
   interface ASCIIToBinaryConverter {

        double doubleValue();

        float floatValue();

    }

2、Double.valueOf

另一种方法是Double.valueOf,需要注意的是,valueOf每次都是new一个Double,也就是一个新的对象。

java 复制代码
    public static Double valueOf(String s) throws NumberFormatException {
        return new Double(parseDouble(s));
    }

为什么Double不像Integer搞个缓存呢?浮点数不像整型,比如1和2之间就有无数个浮点数,那么又如何去实现类似IntegerCache的缓存呢?显然是不现实的!

三、isNaN

需要注意的一点,Double内部定义了一个非法的double值,即NaN:

java 复制代码
    /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code double}. It is equivalent to the value returned by
     * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
     */
    public static final double NaN = 0.0d / 0.0;

相应的,在很多情况下,确实会产生NaN的double值,因此在使用一个double值做一些运算时,记得使用Double.isNaN去判断下该非法值并做相应的异常处理:

java 复制代码
    /**
     * Returns {@code true} if the specified number is a
     * Not-a-Number (NaN) value, {@code false} otherwise.
     *
     * @param   v   the value to be tested.
     * @return  {@code true} if the value of the argument is NaN;
     *          {@code false} otherwise.
     */
    public static boolean isNaN(double v) {
        return (v != v);
    }

如下代码示例:

java 复制代码
    public static void main(String[] args) {
        String s = "NaN";
        double d = 0d;
        try {
            d = Double.parseDouble(s);
        } catch (NumberFormatException e) {
            System.out.println(e.getMessage());
            return;
        }
        if (Double.isNaN(d)) {
            System.out.println(d);
            return;
        }
        d = d * 2.0d;
        System.out.println(d);
    }

四、一道题目

那么,看下这道题目输出是什么呢?

java 复制代码
public class DoubleTest {
    public static void main(String[] args) {
        Double d1 = 100d;
        Double d2 = 100d;
        System.out.println(d1 == d2);
    }
}

答案是false。原因则是上面提到的,valueOf每次都是new一个Double对象。

相比Integer的源码,Double源码相对简单一些。但是需要特别注意使用double时isNaN的判断,否则程序可能产生意想不到的错误。

相关推荐
循着风几秒前
多种二分查找
java
努力也学不会java3 分钟前
【Java并发】深入理解synchronized
java·开发语言·人工智能·juc
TDengine (老段)3 分钟前
TDengine 数学函数 CEIL 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
LB211225 分钟前
Redis 黑马skyout
java·数据库·redis
豐儀麟阁贵31 分钟前
Java知识点储备
java·开发语言
hrrrrb38 分钟前
【Spring Security】Spring Security 密码编辑器
java·hive·spring
豐儀麟阁贵40 分钟前
2.3变量与常量
java·开发语言
兮动人2 小时前
Eureka注册中心通用写法和配置
java·云原生·eureka
爱编程的小白L4 小时前
基于springboot志愿服务管理系统设计与实现(附源码)
java·spring boot·后端
聪明的笨猪猪6 小时前
Java Redis “持久化”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试