最近在做一些Java基础的练习OJ,其中大量涉及各种类型的混合计算,转换,精度计算以及日期推导。刷题的同时看看前辈们的讨论,在细节上感觉有许多新的认识。在此总结一下,以资备用。
#整型
整型,可以粗略的理解为整数,它又分为四种基本类型,byte,short,int,long。其基本数据长度与数值范围如下表。
类型 | 长度 | 取值范围 |
---|---|---|
byte | 1字节 | -128-127 |
short | 2字节 | − 2 − 15 − 2 15 − 1 -2^{-15}-2^{15}-1 −2−15−215−1 |
int | 4字节 | − 2 − 31 − 2 31 − 1 -2^{-31}-2^{31}-1 −2−31−231−1 |
long | 8字节 | − 2 − 63 − 2 63 − 1 -2^{-63}-2^{63}-1 −2−63−263−1 |
强化一下记忆,回顾一下最基本的知识,1byte=8bit,每个bit就是一个0,1,所以去掉一位作为符号位,每种类型能够表示的范围就很好算了,当他们前面注明unsigned时,变为无符号数,其范围为 0 − 2 ( l e n × 8 − 1 ) − 1 0-2^{(len\times8-1)}-1 0−2(len×8−1)−1
#浮点类型
浮点型,主要分为两类,float和double,他们分别是4字节和8字节。两者的区别在于长度和精度。double比float长了一倍,所以空间、处理速度什么的都要相应翻倍。使用时应尽量选择适当的。然而,我现在一般都只用double,这样好像不太好,我反省。
使用浮点型的数据类型时,还有个比较令人头痛的问题——精度,小数点前面的整数部分是用除余法获得的,而小数点后面的部分是用乘基数取整法得到的。如 0.2先0.2×2,得0.4取整数部分0作为小数的十分位,再0.4×2,得0.8,取整数0作为小数的百分位,一直重复上述步骤,直到所需的精度。故他的精度是令人捉急的,所以我们尽量不要用浮点数进行判断操作,即用“==”,这样可能永远都进不去这个if了。如果非要的话,比如在Junit里面做断言测试,那么可以采用精度范围来判断,一般可以采用“<10e-6”这种方式。
刚刚讨论了浮点数的精度问题,日常代码中我们最常做的就是把一个类型赋值给另一个类型,有些安全有些则不然,这就涉及到了各种类型间转换精度保证的问题。下图抄自《Java核心技术第一卷》,其中实线为精度安全的转换,虚线为精度丢失的转换。
然而工程中,很多时候需要精度有保障的浮点数计算,为了满足这个需求,BigDecimal和BigInteger类型就应运而生了,他们的加减乘除计算可以完美的保证运算精度,两个类型的用法一样,一个是针对小数的一个是处理整数的,其中BigDecimal类型的具体使用方式如下。
BigDecimal n1 = new BigDecimal("3.6");
double five=2;
BigDecimal n2 = new BigDecimal(five);
BigDecimal reslut = null;
reslut = n1.add(n2); //加法
System.out.println("3.6+2=" + reslut.doubleValue());
reslut = n1.subtract(n2); //减法
System.out.println("3.6-2=" + reslut.doubleValue());
reslut = n1.multiply(n2); //乘法
System.out.println("3.6*2=" + reslut.doubleValue());
reslut = n1.divide(n2); //除法
System.out.println("3.6/2=" +reslut.doubleValue());
BigDecimal n3 = new BigDecimal("-1.5");
reslut = n3.abs(); //绝对值
System.out.println("|-1.5|=" + reslut.doubleValue());
n1 = new BigDecimal("3.6");
n2 = new BigDecimal("1.2");
reslut = n1.divide(n2); //除法
System.out.println("3.6/1.2=" + reslut.doubleValue());
reslut = n1.divide(n2).stripTrailingZeros(); //识别小数点
System.out.println("3.6/1.2=" + reslut);
#时间
时间也是平时计算时用的较多的内容,某日十天前是周几?某年某月第一个周三是几号?这些计算我刚刚碰到时,略加思索便开始大展拳脚写闰年判断方法,月份、星期的枚举,忙的不亦乐乎,但往往写完后各种bug蹦出来,杀人的心都有了。后来,知道还有Date、Calendar等类可供使用。其中Date类多用于记录时间,而计算时间则交给日历Calendar类来完成,其具体用法如下。
Calendar cal=Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, 15);
String strDate=cal.get(Calendar.YEAR)+"年"+(cal.get(Calendar.MONTH)+1)+"月"+cal.get(Calendar.DATE)+"日";
System.out.println("15天后的日期为:"+strDate);
cal=Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -15);
strDate=cal.get(Calendar.YEAR)+"年"+(cal.get(Calendar.MONTH)+1)+"月"+cal.get(Calendar.DATE)+"日";
System.out.println("15天前的日期为:"+strDate);
![这里写图片描述](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwNDI4MDAyNzQzNDU5?x-oss-process=image/format,png)
上述是简单的计算,还可以深入精确的毫秒计算。另外需要注意的一点是,Calendar类把月定位0-11,使用时需注意转换。