目录
4、StringBuilder类、StringBuffer类
1、LocalDate类、LocalTime类、LocalDateTime类
2、ZoneId类(时区)、ZonedDateTime类(带时区的时间)
一、常用API
1、Object类
Object类是java中所有类的祖宗类,java中所有类的对象都可以直接使用Object类中提供的一些方法。
(1)toString方法
一般需要对Object类中的toString方法进行重写:(重写也很方便输入toS + 回车)或右键点击toString:
在次执行Test:
Object类中toString方法存在的意义就是便于子类去重写,输出有意义的东西。
(2)equals方法
这个equals方法默认是判断两个对象的地址是否相等。
显然“==”也是比较地址,那equals存在的意义是什么呢?同toString方法一样,也是便于子类去重写equals方法,实现两个对象内容的比较,重写也很方便输入eq + 回车 + 回车 + .....,系统自动重写。
再次运行Test返回true。s2.equals(s1)其中s2传给了this接收,s1传给了o。
思考:Objects是什么东西呢,我只听过Object呀?(age是int类型,name是String类型)为什么不使用String.equals方法比较内容而使用Objects的equals方法比较内容呢?(在下文将详细说明)
(3)clone方法
当某个对象调用这个方法时,这个方法会复制一个一模一样的新对象返回。
显然User类是Object类的子类,按理说应该可以调用Object类的clone方法,但是这里为什么报错呢?因为Object类中的clone方法是protected修饰的。protected修饰的方法只能在Object类里面、同包下的其他类里面(java.lang包下)、以及Object的子类里面使用了。父类的protected成员是包内可见的,并且对子类可见。若子类与父类不在同一包下,那么子类的实例可以访问从父类继承而来的protected静态方法,但是不能访问父类实例的protected方法,此时需要对该方法进行重写,输入clone + 回车即可自动重写。
此时需要让User类实现Cloneable接口,该接口内部没有任何东西,相当于做了一个标记,让别人知道当前的User类的clone方法重写了,可以直接使用。
clone()出来的对象是一个Object类型,需要强转为User类型:
注意克隆在java中分为浅克隆和深克隆,上述的克隆是浅克隆。浅克隆就是拷贝出的新对象,与原对象中的数据一模一样(引用类型拷贝的只是地址)(基本数据类型的数据有两份,引用类型的数据还是原来的1份)
深拷贝:对象中基本类型的数据直接拷贝,对象中字符串数据拷贝的还是地址,对象中还包含的其他对象不会拷贝地址,会创建新对象。(深拷贝与浅拷贝的唯一区别就是除了字符串以外的其他对象拷贝方式不同)
再次执行测试类:
2、Objects类
Objects类是一个工具类,提供了很多操作对象的静态方法给我们使用。
(1)equals方法
显然这两种方法都可以比较字符串的内容是否相等,为什么java官方使用Objects中的方法呢?因为s1.equals(s2)当s1是null时(调用方法的对象是null),会报空指针异常的错误:
而Objects类中的equals方法可以很好的处理这种情况,输出false。因此使用Objects中的equals方法更安全更好!!!
(2)isNull方法--等价于==
(3)nonNull--等价于!=
3、包装类
(1)什么是包装类
前面我们学过泛型不支持基本数据类型,只能支持对象类型。那ArrayList身为集合无法存储基本数据类型吗?显然不是,ArrayList可以存储基本数据类型,只是必须将基本数据类型包装成对象。
java的核心理念是万物皆对象,但是像byte,short,int,long,char,float,double,boolean基本数据类型就不是对象,此时包装类就产生了,包装类就是把基本类型的数据包装成对象,以实现万物皆对象。
(2)Integer包装类
我们以Integer包装类为例讲解,其他包装类都一样。以下的两种方法实现了将int类型的数据转换为Integer类型的对象。
除了valueOf方法之外,Integer包装类还提供了很多其他方法供我们使用:
public static String toString(int/Integer):把int或Integer类型的数据转换为String类型
public String toString()重写Object类中的toString方法,是实例方法。将Integer类型的数据转换为String类型。
public static int parseInt(String s):将字符串类型数值转换为int类型
public static Integer valueOf(String s):将字符串类型数值转换为Integer类型
4、StringBuilder类、StringBuffer类
(1)StringBuilder类
StringBuilder表示可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的。StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁。String的对象是不可变的:
StringBuilder类中常用的构造器和方法:
s默认存储的是地址,但是输出结果却返回真实结果,说明StringBuilder类中已经重写了toString方法。注意重写的toString方法会将StringBuilder对象转换为String对象,然后在输出内容。
思考:相比于String,StringBuilder的好处是什么呢?怎么体现StringBuilder对字符串的操作比String效率高呢?
使用String需要消耗很长很长时间,使用StringBuilder只需消耗1-2s即可完成同样的操作。使用String频繁的修改字符串会有不断创建新字符串的过程,很耗时。而StringBuilder是可变字符串不会生成新字符串,只是在原有字符串中修改。因此,对于字符串相关的操作,如频繁的拼接、修改等,建议使用StringBuilder。如果操作字符串较少,或者不需要对字符串进行操作建议用String。
(2)StringBuffer类
StringBuffer(可变字符串对象)的用法与StringBuilder一模一样。即API都相同,StringBuilder有的API方法,StringBuffer都有。唯一的区别是StringBuilder是线程不安全的,StringBuffer是线程安全的。(当很多用户一起来使用StringBuilder对象做一些字符串操作时,可能出bug,而StringBuffer不会出现bug)
(3)案例-返回任意整型数组的内容
package com.zxy.staticlearning;
public class Staticlearning{
public static void main(String[] args) {
int[] array = {11,2,3,4,5};
String s = printArray(array);
System.out.println(s);
}
public static String printArray(int[] array){
if (array == null) return null;
// 中间的拼接使用StringBuilder
StringBuilder s1 = new StringBuilder();
s1.append("[");
for (int i = 0; i < array.length; i++) {
if (i == array.length - 1){
s1.append(array[i]);
}else {
s1.append(array[i]).append(", ");
}
}
s1.append("]");
return s1.toString();
}
}
5、StringJoiner类
使用StringBuilder进行字符串的拼接,尽管效率得到极大的提高,但是在某些场景下代码写起来比较麻烦。比如上述字符串拼接代码需要使用if来实现。有没有一种方法可以既实现效率高,又实现方便的字符串拼接呢?StringJoiner类就出现了。
StringJoiner类在JDK8开始才有,跟StringBuilder一样也是用来操作字符串的,也可以看作是一个容器,创建后里面的内容是可变的(保证了字符串操作的效率)。使用StringJoiner不仅可以提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更加简洁。
StringJoiner的常见构造器和方法:
注意:add方法只能传入字符串
简化4-(3)的代码:
6、Math类、System类、Runtime类
(1)Math类
代表数学,是一个工具类,里面提供的都是对数据进行数学运算的一些静态方法。
public static double abs(double a)
(2)System类
System代表程序所在的系统,也是一个工具类,常见方法如下:
currentTimeMillis方法一般用于计算程序执行的时间:
(3)Runtime类
代表程序所在的运行环境。Runtime是一个单例类,只对外提供一个对象(因为程序的运行环境只有一个)
如何关闭程序呢?
7、BigDecimal类
用于解决浮点型运算时,可能出现结果失真的问题。(有些时候会失真,有些时候不会)
上述代码可以简化:
valueOf方法(推荐使用)本质还是先转换为String类型,然后调用构造器实现转换:
显然,BigDecimal也重写了Object类中的toString方法。注意在做除法时例如0.1/0.3,结果本身肯定不能精确。而BigDecimal是为了解决浮点数计算不精确问题的,所以它强迫计算必须要得到精确的结果,因此BigDecimal遇到本身不精确的浮点数计算就崩了。
当完全不知道怎么写代码时Ctrl + Alt + 空格可以进行智能提示。
把BigDecimal对象转换成double类型数据:
二、传统时间API--了解不推荐使用
1、Date类
代表日期和时间,常见构造器和方法如下:
2、SimpleDateFormat类-简单日期格式化
上述直接输出Date类对象的时间是下面的格式,给用户看不是太友好。
给用户看的时间应该是”年月日时分秒“这种友好的格式:
那如何将不友好的时间格式转化为友好的时间格式呢?需要用到SimpleDateFormat类,它代表简单日期格式化,可以用来把日期对象、时间毫秒值格式化为我们想要的形式。
SimpleDateFormat还可以将字符串时间在回过头来解析成日期对象:
案例---秒杀活动
3、Calendar类
从上述可以看出没有Calendar我们想要进行日期的计算必须经过时间毫秒值进行,特别麻烦。Calendar代表系统此刻时间对应的日历,通过它可以单独获取、修改时间中的年,月,日,时,分,秒等。Calendar是一个抽象类,无法创建对象,需要通过其直接子类GregorianCalendar来使用(不推荐)。同时Calendar中提供了静态方法getInstance()可以直接创建出Calendar对象。
注意月份是0-11,分别表示1-12月
从上述可见Calendar是一个可变对象,一旦修改后其对象本身表示的时间将产生变化。
三、JDK8开始新增的时间API--推荐使用
1、LocalDate类、LocalTime类、LocalDateTime类
LocalDate:代表本地日期(年,月,日,星期)
LocalTime:代表本地时间(时、分、秒、纳秒)
LocalDateTime:代表本地日期时间(年,月,日,星期、时、分、秒、纳秒)使用最多
LocalDate类:
注意新时间API都是不可变对象,对原时间的修改会新生成一个对象,源对象不会发生改变:
public static LocalDate of(int year, int month, int dayOfMonth):将指定日期转换为LocalDate对象。
LocalTime类:
LocalDateTime类:
可以把LocalDateTime对象转换成LocalDate和LocalTime对象,同时LocalDate对象和LocalTime对象可以合并为LocalDateTime对象:
2、ZoneId类(时区)、ZonedDateTime类(带时区的时间)
上述API只能获取本国的时间,无法获取其他国家的时间。需要借助时区。由于世界各个国家和地区的经度不同,时间也不同,因此会划分为不同的时区。整个世界共划分为24个时区
ZoneId:代表时区Id,为了方便记忆,时区Id一般都是该时区内有名的城市名(ZoneId类主要用于获取时区Id)
通过ZoneId获取到时区后,我们就能通过ZonedDateTime来得到某个时区的当前时间了。
ZonedDateTime代表带时区的时间:
同时ZonedDateTime对象与上述的LocalDate,...一样,也有getYear.....withMonth.....等等方法。
3、Instant类
代表时间线上的某个时刻/时间戳。通过获取Instant的对象可以拿到此刻的时间,该时间两部分组成:从1970-01-01 00:00:00开始走到此时的总秒数 + 不够1s的纳秒数。
Instant类的常见方法:
同理:plus是加操作,minus是减操作。equals判断两个Instant对象是否相等,isAfter,isBefore判断时间在前还是在后。
Instant的作用是什么?由于Instant可以精确到纳秒级,因此Instant通常用于程序的性能分析
相比与LocalDateTime,Instant可以获取此刻的总秒数,而LDT无法直接获得,因此在某些场景下Instant更加适用,但总体上来说LDT用的多。
4、DateTimeFormatter类
代表日期时间格式化器,用于时间的格式化、解析。将对用户不友好时间显示方法格式化为友好的方式。DateTimeFormatter类是传统SimpleDateFormat类的替代品,传统的SimpleDateFormat类是线程不安全的,DateTimeFormatter类是线程安全的(多个用户同时访问该类的对象不会出bug)。
5、Period类,Duration类
Period用于计算两个LocalDate对象相差的年数,月数,天数。Period类常见方法如下:
Duration用于计算两个时间对象相差的天数,小时数,分数,秒数,纳秒数;支持LocalTime、LocalDateTime、Instant等时间对象。Duration的常见方法如下:
补充知识:
(1)小技巧
(2)LocalDate,LocalTime,LocalDateTime类,ZoneId类,ZonedDateTime类方法总结