本篇是源码分析的第二篇,上篇我们一起分析了Integer类的源码,本篇一起学习下Double类的源码,看下其实现。
一、Double类图
首先,相比Integer,Double类的源码只有1000+行代码。如下是Integer及其关联类/接口的类图:
通过Integer类的类图,我们总结下它的特点:
- Double类继承自抽象类Number
- Double类实现了Comparable接口
- Double类使用final修饰,因此不可以有子类(不能被继承)
二、String转Double
同Integer类似,在实际工作中,我们用的比较多的,仍然是String转Double。Java也是给我们提供了两个方法:
1、Double.parseDouble
public static double parseDouble(String s) throws NumberFormatException {return FloatingDecimal.parseDouble(s);}
可以看到,parseDouble并非在Double类中实现的,而是借助FloatingDecimal类去实现:
public static double parseDouble(String s) throws NumberFormatException {return readJavaFormatString(s).doubleValue();}
readJavaFormatString方法返回ASCIIToBinaryConverter:
static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {...}
而ASCIIToBinaryConverter接口有两个方法,分别是doubleValue()和floatValue(),显而易见,分别是转double和转float的方法:
interface ASCIIToBinaryConverter {double doubleValue();float floatValue();}
2、Double.valueOf
另一种方法是Double.valueOf,需要注意的是,valueOf每次都是new一个Double,也就是一个新的对象。
public static Double valueOf(String s) throws NumberFormatException {return new Double(parseDouble(s));}
为什么Double不像Integer搞个缓存呢?浮点数不像整型,比如1和2之间就有无数个浮点数,那么又如何去实现类似IntegerCache的缓存呢?显然是不现实的!
三、isNaN
需要注意的一点,Double内部定义了一个非法的double值,即NaN:
/*** 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去判断下该非法值并做相应的异常处理:
/*** 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);}
如下代码示例:
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);}
四、一道题目
那么,看下这道题目输出是什么呢?
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的判断,否则程序可能产生意想不到的错误。