JAVA中常用类型
一、包装类
1.1 包装类简介
java是面向对象的语言,但是八大基本数据类型不符合面向对象的特征。因此为了弥补这种缺点,为这八中基本数据类型专门设计了八中符合面向面向对象的特征的类型,这八种具有面向对象特征的类型,就叫做包装类,英文:wrapper class。
所有的基本数据类型和包装类型的对比如下图:
1.2 装箱和拆箱
-
装箱boxing : 由基本数据类型转型为包装类型。
-
调用包装类的构造器,进行装箱
-
调用valueOf()静态方法,进行装箱
-
-
拆箱 unboxing: 由包装类型转型为基本数据类型。
-
调用xxxValue()非静态方法,进行拆箱
-
public class Demo01 { public static void main(String[] args) { int age = 10; Integer a1 = new Integer(age);//用第一种方式进行装箱操作,由值转为了对象 Integer a2 = Integer.valueOf(100);//用第二种方式进项装箱操作 int s = a1.intValue();//拆箱操作,由对象转为了值 int s1=a2.intValue(); System.out.println(a1); System.out.println(a2); System.out.println(s+1);//打印结果是11,证明已经变回了值 System.out.println(s1+1);//打印结果是101,证明已经变回了值 } }
1.3 自动装箱和拆箱
为了方便获取包装类对象,从jdk1.5以后,提供了一个自动装箱的操作,也提供了一个包装类到基本数据类的自动拆箱操作。
自动装箱 : 直接使用一个基本数据类型的变量或字面值给一个包装类型的引用进行赋值即可; 省略掉的是 valueOf 方法
自动拆箱 : 直接使用一个包装类型的引用给一个基本数据类型的变量进行赋值即可;省略掉的是 xxValue 方法
Integer b=66;//实际上,底层直接帮我们调用了工具方法valueof()方法进行装箱 Short b1=new Short("20"); short b2=b1;//底层自动调用Shortvalue()自动拆箱
1.4 包装类的常量池
对于装箱操作后的包装类的对象,jvm在堆中,维护了一个常量池,该常量池适用于调用了valueOf()方法产生的包装类对象,以及自动装箱的包装类对象。不适用于new关键字创建的包装类对象。
Byte, Short, Integer, Long :创建了数值范围为[-127,128]的相应类型的缓存数据
Character :创建了数值在 [0, 127] 范围的缓存数据
Boolean 直接返回 true 或 false
两种浮点数类型的包装类 Float, Double 并没有实现常量池技术。
Integer b3=new Integer(11); Integer b4=Integer.valueOf(11); System.out.println(b3==b4);
证明b3和b4不是同一个对象,一个在包装常量池,一个在堆中
double d1 = 3.14;
Double d2 = Double.valueOf(d1);
Double d3 = Double.valueOf(d1);
System.out.println(d2==d3);
如何有常量池,那么d2和d3应该指向同一个地址,结果是true,但结果是false,证明没有常量池
1.5 包装类其他常用方法
工具方法:
static WrapperClassName valueOf(xxx value)
static WrapperClassName valueOf(String value)
static xxx parseXXX(String value)
static String toBinaryString(); 转成二进制
static String toHexString(); 转成16进制
static String toOctalString() 转成8进制
String line="123456"; int i=Integer.parseInt(line); System.out.println(i+1);//结果为123457,证明把字符串line转成了int类型的数字 int num = 1001; System.out.println(Integer.toBinaryString(num)); //1111101001 System.out.println(Integer.toOctalString(num)); // 1751 System.out.println(Integer.toHexString(num)); // 3e9
二、BigDecimal
提供该类的意图:就是为了更精确的运算。(double和float在运算时,有精度损失,科研中一般不用)
1.1 常用构造器
BigDecimal(String s): 推荐使用
BigDecimal(int v):
BigDecimal(long v):
BigDecimal(double v):
1.2 常用方法
BigDecimal add(BigDecimal other);
BigDecimal subtract(BigDecimal other);
BigDecimal multiply(BigDecimal other);
BigDecimal divide(BigDecimal other): 做除法时要注意,除数不能是0, 还有不能出现除不尽的情况,不然都会报异常。
public class Demo02 { public static void main(String[] args) { BigDecimal m =new BigDecimal("10"); BigDecimal n =new BigDecimal("20"); BigDecimal sum=m.add(n); System.out.println(sum);//调用了重写的toString,返回字符串样子。 BigDecimal c=n.subtract(m); System.out.println(c); BigDecimal c1=n.multiply(m); System.out.println(c1); BigDecimal c2=n.divide(m); System.out.println(c2); } }
1.3 常用的舍入模式
BigDecimal.setScale()方法用于格式化小数点
setScale(1)表示保留一位小数,默认用四舍五入方式
setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3
setScale(1,BigDecimal.ROUND_UP)进位处理,2.35变成2.4
setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35变成2.4
setScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入,2.35变成2.3,如果是5则向下舍
setScaler(1,BigDecimal.ROUND_CEILING)接近正无穷大的舍入
setScaler(1,BigDecimal.ROUND_FLOOR)接近负无穷大的舍入,数字>0和ROUND_UP作用一样,数字<0和ROUND_DOWN作用一样
setScaler(1,BigDecimal.ROUND_HALF_EVEN)向最接近的数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
1、ROUND_UP,向远离0的方向舍入,在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。
注意,此舍入模式始终不会减少计算值的大小。
eg: 保留1位小数 1.60->1.6 1.61->1.7 1.66->1.7 , -1.62->-1.7
2、ROUND_DOWN,向接近0的方向舍入,在丢弃某部分之前,始终不增加数据(即,截断),该方式是只减不加。
eg: 保留1位小数 1.60->1.6 1.61->1.6 1.66->1.6 , -1.62->-1.6
3、ROUND_CEILING,向正无穷方向舍入,如果数值为正,舍入方式与ROUND_UP一致,如果为负,舍入方式与ROUND_DOWN一致,该模式始终不会减少计算数值。
eg: 保留1位小数 1.60->1.6 1.61->1.7 1.66->1.7 , -1.62->-1.6
4、ROUND_FLOOR,向负无穷方向舍入,如果数值为正,舍入行为与 ROUND_DOWN 相同;如果为负,则舍入行为与 ROUND_UP 相同。该模式始终不会增加计算数值。
eg: 保留1位小数 1.60->1.6 1.61->1.6 1.66->1.6 , -1.62->-1.7
5、ROUND_HALF_UP,向“最接近的”数字舍入,也就是四舍五入。
eg: 保留1位小数 1.61->1.6 1.65->1.7 1.66->1.7 , -1.62->-1.6
6、ROUND_HALF_DOWN,向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式,也就是五舍六入。
eg: 保留1位小数 1.61->1.6 1.65->1.6 1.66->1.7 , -1.62->-1.6
7、ROUND_HALF_EVEN,向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。
eg. 1.15->1.2, 1.25->1.2
8、ROUND_UNNECESSARY,计算结果是精确的,不需要舍入模式。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。
1.4 BigDecimal常见问题
1、创建 BigDecimal精度丢失
在BigDecimal 中提供了多种创建方式,可以通过new 直接创建,也可以通过 BigDecimal.valueOf 创建。这两种方式使用不当,也会导致精度问题。
public static void main(String[] args) throws Exception {
BigDecimal b1= new BigDecimal(0.1);
System.out.println(b1);
BigDecimal b2= BigDecimal.valueOf(0.1);
System.out.println(b2);
BigDecimal b3= BigDecimal.valueOf(0.111111111111111111111111111234);
System.out.println(b3);}
上面示例中两个方法都传入了double类型的参数0.1但是 b1 还是出现了精度的问题。造成这种问题的原因是 0.1 这个数字计算机是无法精确表示的,送给 BigDecimal 的时候就已经丢精度了。
结论:
第一,在使用BigDecimal构造函数时,尽量传递字符串而非浮点类型;
第二,如果无法满足第一条,则可采用BigDecimal.valueOf方法来构造初始化值。但是valueOf受double类型精度影响,当传入参数小数点后的位数超过double允许的16位精度还是可能会出现问题的
2、等值比较的坑
一般在比较两个值是否相等时,都是用equals 方法,但是,在BigDecimal 中使用equals可能会导致结果错误,BigDecimal 中提供了 compareTo 方法,在很多时候需要使用compareTo 比较两个值。
public static void main(String[] args){
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("1.00");
System.out.println(b1.equals(b2));
System.out.println(b1.compareTo(b2));
}
出现此种结果的原因是,equals不仅比较了值是否相等,还比较了精度是否相同。示例中,由于两个值的精度不同,所有结果也就不相同。而 compareTo 是只比较值的大小。返回的值为-1(小于),0(等于),1(大于)。
3、无限精度的坑
BigDecimal 并不代表无限精度,当在两个数除不尽的时候,就会出现无限精度的坑,此种情况,只需要在使用 divide方法时指定结果的精度即可:
BigDecimal b3 = new BigDecimal("1"); BigDecimal b4 = new BigDecimal("3"); System.out.println(b3.divide(b4,2, RoundingMode.HALF_UP));//结果为0.33
在使用BigDecimal进行(所有)运算时,尽量指定精度和舍入模式。
三、Date日期类型
3.1 简介
1、是一个用来表示时间、日期的类,这个类在 java.util 包中,在使用 Date的时候,一定要注意 : 在 java.sql 包中,也有一个Date,千万不要导错包了。
2、 Date对象,用来表示一个时间点。是距离纪元时间点的总毫秒数。
3、纪元时间点: 1970年1月1日00:00:00(本初子午线处的时间点)
3.2 常用API
1)构造器
-
Date() :获取当前系统时间
-
Date(long time):设置一个距离固定点的指定毫秒数的时间点。
2)方法
-
long getTime()
-
void setTime(long time)
-
String toString() 格式: Thu May 24 19:32:14 CST 2018
Date now = new Date(); System.out.println(now); Date d = new Date(24*60*60*1000*2);//使用有参构造器,来获取距离纪元的2天后的时间 System.out.println(d);
四、SimpleDateFormat类型
4.1 简介
java.text.SimpleDateFormat是一个用来格式化和解析日期的具体类,它允许进行格式化(日期 ->文本)、解析(文本 -> 日期)和规范化
-
将一个Date对象转成一个指定格式的字符串
-
将一个自定格式的字符串转成一个Date对象
4.2 常用构造器和方法
1)构造器
- SimpleDateFormat()
- SimpleDateFormat(String pattern):指定一个日期格式符号来构造对象
2)方法
- final String format(Date date) Date
- Date parse(String source) throws ParseException String
3)日期模式匹配字符
字符 | 含义 | 案例 |
---|---|---|
y | 年 | yyyy年—2018年;yy-18年 |
M | 月 | MM月—05月;M月—5月 |
d | 日 | dd日—06日;d日—6日 |
E | 星期 | E-星期日(Sun) |
a | 上下午(AM、PM) | a—下午(PM) |
H | 24小时制 | a h时--------下午 10时HH:mm:ss------12:21:34hh(a):mm:ss------12(PM):21:34 |
h | 12小时制 | |
m | 分钟 | |
s | 秒 |
public class Date01 { public static void main(String[] args) throws ParseException { Date now = new Date(); System.out.println(now); Date d = new Date(24*60*60*1000*2);//使用有参构造器,来获取距离纪元的2天后的时间 System.out.println(d); //进行格式化 SimpleDateFormat a =new SimpleDateFormat("yyyy.MM.dd HH.mm.ss"); String str=a.format(now); System.out.println(str); String s1="2002年11月09日"; //字符串转日期时,SimpleDateFormat里的格式按照字符串来写 SimpleDateFormat date=new SimpleDateFormat("yyyy年MM月dd日"); Date date1=date.parse(s1); System.out.println(date1); }
五、Calendar类型
5.1 简介
1、日历类型,位于java.util包下,封装了日历信息,包括年月日时分秒这些时间分量。
2、Calendar是抽象类,有很多子类型,比如格力高日历类型。该格力高日历类型正是大多数国家通用的日历类型,即阳历。
3、 程序员不需要直接调用子类型的构造器来获取日历对象,Calendar类型里封装了一个工具方法getInstance(),来获取该地区的子类型对象。
5.2 常用方法
1)getInstance方法
Calendar提供了一个类方法getInstance,以获取此类型的一个通用的对象
此方法返回一个Calendar对象,其日历字段已经由当前日期和时间初始化
2)getActualMaximum方法
作用:指定一个时间常量,返回指定日历分量可能拥有的最大值
Date getTime();
get(int Field)
5.3 时间常量
Calendar.YEAR: 年
Calendar.MONTH: 月 注意 该值的范围是0~11,分别表示1月~12月。 因此表示月份时,要+1操作。
Calendar.DAY_OF_MONTH 日
Calendar.DATE 日
Calendar.HOUR_OF_DAY 24小时制的时
Calendar.HOUR 12小时制的时
Calendar.MINUTE 分钟
Calendar.SECOND 秒钟
Calendar.DAY_OF_WEEK: 星期几 范围1~7, 1表示周日, 7表示周六, 显示时要-1操作
Calendar.DAY_OF_YEAR: 一年中的第几天。
public class Calendar01 { public static void main(String[] args) { //想要获取一个日历对象 Calendar cal = Calendar.getInstance(); System.out.println(cal); Date time = cal.getTime(); System.out.println(time); System.out.println("------------设置时间分量------------------"); // 修改成北京奥运时间: 2008-8-8日 20:08:00 cal.set(Calendar.YEAR,2008); System.out.println(cal.getTime()); cal.set(Calendar.MONTH,8-1); cal.set(Calendar.DAY_OF_MONTH,8); cal.set(Calendar.HOUR_OF_DAY,20); cal.set(Calendar.MINUTE,8); System.out.println(cal.getTime()); } }