## 日期时间相关
### 时间戳
从 1970.01.01 00:00:00 至今的**毫秒数**,通常用来做差计算程序执行耗时
* System 类中的 public static long currentTimeMillis() 方法可以返回时间戳
### Date 类
Date类有两个,一个是 java.util.Date,一个是其子类,java.sql.Date(对应数据库中的日期变量)
* 构造器
```java
Date()
// 创建一个对应当前时间的 Date 对象
Date(long time)
// 创建一个对应指定 time 时间戳的 Date 对象 或 java.sql.Date 类的对象
```
* 方法
```java
String toString();
// 显示当前 Date 对象的年、月、日、时、分、秒、星期、时区等信息
long getTime();
// 获取当前 Date 对象对应的时间戳
```
### SimpleDateFormat 类
* java.text.SimpleDateFormat 类是一个格式化和解析日期的类,其格式化与解析过程与语言环境无关
* 格式化即将日期转成字符串,解析即将字符串转成日期
```java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatTest {
public static void main(String[] args) {
// 使用默认空参构造器
SimpleDateFormat sdf1 = new SimpleDateFormat();
// 格式化
String str1 = sdf1.format(new Date());
System.out.println(str1);
// 解析字符串
String str2 = "2020/02/01 下午04:20";
try {
//要求字符串必须是符合 SimpleDateFormat 识别的格式(通过构造器参数体现)
Date date = sdf1.parse(str2);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
// 在构造器指定进行格式化和解析的日期的格式
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
// 格式化
String str3 = sdf2.format(new Date());
System.out.println(str3);
// 解析
String str4 = "2020-02-01 15:20:30";
try {
Date date = sdf2.parse(str4);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
```
### java.time 包下的 LocalDateTime 等
java.time 包提供了 LocalDate 本地日期、LocalTime 本地时间、LocalDateTime 本地日期时间、ZonedDateTime 时区、Duration 持续时间
```java
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public class LocalDateTimeTest {
public static void main(String[] args) {
// 对象实例化
// 获取表示当前时间的对象
LocalDateTime localDateTime1 = LocalDateTime.now();
// 获取表示某个时间的对象
LocalDateTime localDateTime2 = LocalDateTime.of(2020,2,1,16,35,10,340);
// 日期
LocalDate localDate = LocalDate.now();
// 时间
LocalTime localTime = LocalTime.now();
System.out.println(localDateTime1);
System.out.println(localDateTime2);
System.out.println(localDate);
System.out.println(localTime);
// 获取:get 方法
System.out.println(localDate.getDayOfMonth());
System.out.println(localDate.getDayOfYear());
System.out.println(localDate.getMonth());
System.out.println(localDate.getMonthValue());
System.out.println(localDateTime1.getMinute());
// 设置:with 方法
// 修改日期,并返回新的 LocalDateTime 对象
LocalDateTime localDateTime3 = localDateTime1.withDayOfMonth(5);
LocalDateTime localDateTime4 = localDateTime1.withMonth(1);
System.out.println(localDateTime3);
System.out.println(localDateTime4);
// 原来的对象并未改变
System.out.println(localDateTime1);
// 增加时间 plus 方法,减少时间 minus 方法
System.out.println(localDateTime1.plusMinutes(20));
System.out.println(localDateTime1.minusHours(2));
}
}
```
### DateTimeFormatter
* 用于格式化或解析日期、时间,类似于 SimpleDateFormat
* 使用 LocalDateTime 时,如果要进行格式化显示,就要使用 DateTimeFormatter
* 和 SimpleDateFormat 不同的是,DateTimeFormatter 不但是不变对象,它还是线程安全的
```java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterTest {
public static void main(String[] args) {
// 创建一个 DateTimeFormatter 对象,并指定格式化、解析的日期时间格式
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm");
// 将日期时间格式化为字符串
String str = dtf.format(LocalDateTime.now());
System.out.println(str);
// 将字符串按照 DateTimeFormatter 对象指定的格式解析为时间
System.out.println(dtf.parse(str));
// 不按指定格式,会报java.time.format.DateTimeParseException异常
System.out.println(dtf.parse("2020/3/15 18:20"));
}
}
```
## Java 比较器
如果要实现对象之间的比较,需要实现 Comparable 或 Comparator 接口
* **自然排序** java.lang.Comparable
* **定制排序** java.util.Comparator
* Comparable 接口的方式一旦确定,保证 Comparable 接口实现类的对象在任何位置都可以比较大小。
* Comparator 接口常用于临时性的比较
### Comparable 接口
* 实现了 Comparable 接口并且重写 comparaTo(Object obj) 方法的类的对象可以进行比较,例如 String、包装类等
* 重写 comparaTo(Object obj) 方法的规则
* 如果当前对象 this 大于形参对象 obj,返回正整数
* 如果当前对象 this 小于形参对象 obj,返回负整数
* 如果当前对象 this 等于形参对象 obj,返回零
* 对于自定义的类,如果需要排序,例如存储自定义类对象的**数组或集合**要调用 Arrays.sort() 或 Collections.sort(),则必须实现 Comparable 接口,并在 comparaTo() 方法中指明如何排序
```java
import java.util.Arrays;
public class ComparableTest {
public static void main(String[] args) {
Goods[] goods = new Goods[5];
goods[0] = new Goods(40,"huawei");
goods[1] = new Goods(35,"xiaomi");
goods[2] = new Goods(43,"oppo");
goods[3] = new Goods(20,"vivo");
goods[4] = new Goods(43,"apple");
System.out.println(Arrays.toString(goods));
Arrays.sort(goods);
System.out.println(Arrays.toString(goods));
}
}
class Goods implements Comparable{
double price;
String name;
Goods(){}
Goods(double price,String name) {
this.price = price;
this.name = name;
}
@Override
public String toString() {
return "Goods{" +
"price=" + price +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Object o) {
if(o instanceof Goods) {
Goods anotherGoods = (Goods)o;
if(this.price > anotherGoods.price) {
return 1;
}else if(this.price < anotherGoods.price) {
return -1;
}else {
// return 0;
// 二级排序
return this.name.compareTo(anotherGoods.name);
}
// 比较数值也可以使用包装类的compara方法
// return Double.compare(this.price,anotherGoods.price);
}
throw new RuntimeException("传入类型不正确");
}
}
```
### Comparator 接口
* 当元素的类型没实现 java.lang.Comparable 接口而又不方便修改代码,或者实现了 java.lang.Comparable 接口的排序规则不适合当前的操作,那么可以考虑使用 java.util.Comparator 的对象来排序
* 重写 compare(Object o1,Object o2) 方法,比较o1和o2的大小:
* 如果方法返回正整数,则表示o1大于o2
* 如果返回0,表示相等
* 返回负整数,表示o1小于o2
```java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class ComparatorTest {
public static void main(String[] args) {
ArrayList phone = new ArrayList<>();
phone.add(new Phone(100,"huawei"));
phone.add(new Phone(99,"xiaomi"));
phone.add(new Phone(90,"oppo"));
phone.add(new Phone(90,"apple"));
System.out.println(phone);
// 匿名内部类的方式使用 Comparator 接口
Collections.sort(phone, new Comparator() {
@Override
public int compare(Phone o1, Phone o2) {
if(o1.price!=o2.price) {
return Double.compare(o1.price,o2.price);
}else {
return o1.name.compareTo(o2.name);
}
}
});
System.out.println(phone);
}
}
class Phone {
double price;
String name;
public Phone() {
}
public Phone(double price, String name) {
this.price = price;
this.name = name;
}
@Override
public String toString() {
return "Phone{" +
"price=" + price +
", name='" + name + '\'' +
'}';
}
}
```
## System 类
* java.lang.System 类代表系统,系统级的很多属性和控制方法都放置在该类的内部
该类的构造器是 private 的,无法实例化,其成员变量和成员方法都是 static 的,方便进行调用。
* 常用方法
```java
// 获取时间戳
long currentTimeMillis()
// 推出程序
void exit(int status)
// 通知 JVM 进行垃圾回收
void gc()
// 将数组中指定的数据拷贝到另一个数组中
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
/*
src - 源数组。
srcPos - 源数组中的起始位置,(起始索引)
dest - 目标数组。
destPos - 目的地数据中的起始位置
length - 要复制的数组元素的数量
*/
```
## Math 类
java.lang.Math 类提供了一系列静态方法用于数值计算,如指数、对数、平方根、三角函数等
```java
// 求绝对值
Math.abs(-7.8); // 7.8
// 求较大、较小值
Math.max(100, 99); // 100
Math.min(1.2, 2.3); // 1.2
// 乘方
Math.pow(2, 10); // 2的10次方=1024
// 开方
Math.sqrt(2); // 1.414...
// e 的多少次方
Math.exp(2); // 7.389...
// 以 e 为底的对数
Math.log(4); // 1.386...
// 计算以10为底的对数
Math.log10(100); // 2
// 三角函数
Math.sin(3.14); // 0.00159...
Math.cos(3.14); // -0.9999...
Math.tan(3.14); // -0.0015...
Math.asin(1.0); // 1.57079...
Math.acos(1.0); // 0.0
// 数学常量
double pi = Math.PI; // 3.14159...
double e = Math.E; // 2.7182818...
// 生成一个随机数x,x的范围是0 <= x < 1:
Math.random();
```
## BigInteger 和 BigDecimal
#### BigInteger
* 由 CPU 原生提供的整型最大范围是 64 位 long 型整数,使用 long 型整数可以直接通过CPU指令进行计算,速度非常快
* 如果需要的整数大小超过了 long 的范围,可以使用 BigInteger。java.math.BigInteger 可以表示不可变的任意精度的整数,其内部用一个 int[] 数组来模拟一个非常大的整数
* 对 BigInteger 对象进行运算必须调用对应的实例方法
```java
// 返回两个大整数的和
BigInteger add(BigInteger val)
// 返回两个大整数的差
BigInteger subtract(BigInteger val)
// 返回两个大整数的积
BigInteger multiply(BigInteger val)
// 返回两个大整数的商
BigInteger divide(BigInteger val)
// 用当前大整数对val求模
BigInteger mod(BigInteger val)
// 返回两个大整数的最大者
BigInteger max(BigInteger val)
// 返回两个大整数的最小者
BigInteger min(BigInteger val)
// 返回绝对值
BigInteger abs()
// 返回相反数
BigInteger negate()
// 返回大整数的double类型的值
double doubleValue()
// 返回大整数的float类型的值
float floatValue()
// 返回大整数的整型值
int intValue()
// 返回大整数的long型值
long longValue()
```
* 可以调用相应的方法将 BigInteger 转换成基本数据类型
* 如果 BigInteger 表示的范围超过了基本类型的范围,转换时将丢失高位信息,即结果不一定是准确的
* 如果需要准确地转换成基本类型,可以使用 intValueExact()、longValueExact() 等方法,在转换时如果超出范围,将抛出 ArithmeticException 异常
```java
BigInteger i = new BigInteger("123456789000");
System.out.println(i.longValue()); // 123456789000
System.out.println(i.multiply(i).longValueExact()); // java.lang.ArithmeticException: BigInteger out of long range
```
### BigDecimal
* 和 BigInteger 类似,BigDecimal 可以表示一个任意大小且精度完全准确的浮点数
```java
// 返回 BigDecimal 的小数位数,如果返回负数,表示此 BigDecimal 为正数,该负数的绝对值为 BigDeceimal 结尾的 0 的个数
int scale()
// 格式化为一个相等的,但去掉了末尾0的BigDecimal
BigDecimal stripTrailingZeros()
```
* 总是使用 compareTo() 比较两个 BigDecimal 的值是否相同,不要使用 equals()

Java基础 | 常用类