Java-API,常用的API,涉及部分底层原理

悟已往之不谏,知来者之可追

在常用API中,只需记住类名、类的作用,会查API帮助文档

类Math:数学计算的工具类

final类,不可继承

字段:

static double E − 这是比任何其他值都更接近自然对数底 e 的双精度值。

static double PI − 这是比任何其他值都更接近 pi 的双精度值,pi 是圆的周长与其直径的比值。

原理:

private Math(){} 私有化构造方法,外部不能创建其对象。

静态方法:类名.方法名 调用

1
2
3
4
5
6
7
8
9
Math.abs(); //绝对值 JDK15之后有异常处理 Math.absExact();
Math.ceil(); //向上取整
Math.floor(); //向下取整
Math.round(); //四舍五入
Math.max(); //取最大值
Math.min(); //取最小值
Math.pow(a,b); //a^b
Math.sqrt(); //平方根
Math.random(); //随机数 范围[0-1)</code></pre></details>

类System:系统工具类

计算机的时间原点:1970.1.1 00:00:00

1
2
3
4
5
6
7
8
9
10
11
System.exit();//终止虚拟机 status:0 正常结束/ 1 异常结束 底层调用了Runtime类的exit()方法
System.currentTimeMillis();//到时间原点所过去的时间(ms),可用于判断程序运行时间
/*
数据拷贝
参数(数据源,数据源开始拷贝索引,目的地,目的地索引,拷贝个数)
细节:
1.拷贝基本数据类型,需要保证数据类型一致
2.需要考虑数组长度
3.引用数据类型,子类可以赋值给父类
*/
System.arraycopy();

类Runtime:允许应用程序与运行应用程序的环境进行交互。

原理:

使用Runtime类的实例化方法需要先获取对象,因为运行环境唯一,构造方法私有化,所以在Runtime类的内部自己创建了对象并赋值给了currentRuntime,且用final修饰,保证了地址值不会变化。再使用getRuntime()方法将对象currentRuntime进行返回,获取到了Runtime的对象,确保了在不同类中的何处运行都保证了获取到了同一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Runtime {
private static final Runtime currentRuntime = new Runtime();

private static Version version;

/**
* Returns the runtime objectassociated with the currentJava application.
* Mostof the methods of class {@code Runtime} are instance
* methods and mustbe invoked with respectto the currentruntime object.
*
* @return the {@code Runtime} objectassociated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}

/** Don'tletanyone else instantiate this class */
private Runtime() {}
}
1
2
3
4
5
6
7
8
9
10
//静态方法
Runtime.getRuntime();//获取当前系统运行环境的对象

//实例化方法
Runtime.getRuntime().exit()//停止虚拟机 status:0 正常结束/ 1 异常结束
Runtime.getRuntime().availableProcessors();//获取CPU线程数
Runtime.getRuntime().maxMemory();//JVM从系统中获得的总内存的大小
Runtime.getRuntime().totalMemory();//JVM已从系统中获得的内存大小
Runtime.getRuntime().freeMemory();//JVM中剩余内存
Runtime.getRuntime().exec("");//运行cmd命令

类Object:顶级父类,所有类直接或间接继承与Object类

因为类Object是顶级父类,所以没有成员变量,为空参构造。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
返回对象的地址,字符串表示形式:包+类@地址
System.out.println(obj);效果等同于toString();
默认情况下,返回地址值没有太大作用,一般会在子类中重写,用来拼接属性并打印
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

/*
类Object下的该方法是判断对象的地址值是否相等
而子类通常会重写该方法,用来比较对象内部的属性值是否相等:如String包下的equals()方法
*/
public boolean equals(Objectobj) {
return (this == obj);
}

/*
对象克隆:完全拷贝属性值,但该方法受保护,需要重写。
Cloneable接口:如果一个接口内没有抽象方法,说明该接口是标志性接口,Cloneable一旦被发现,
那么当前类就可以被克隆。
方法在底层会帮我们创建一个对象,并把源对象中的数据拷贝过去。
例如,学生类实现了Cloneable接口,该类就可以被克隆。
public class Clone {
public static void main(String[] args) throws CloneNotSupportedException {
Studentstu1 = new Student(11,"zhangsan",120,101);
Studentstu2 =(Student) stu1.clone(); //强转
System.out.println(stu1);
System.out.println(stu2);
}
}
步骤:
1.重写Object中的Clone()方法
2.让javabean类实现Cloneable接口
3.创建原对象,然后调用Clone()方法

注意:该方法是浅克隆
*/
protected native Objectclone() throws CloneNotSupportedException;

System.out.println(obj)原理解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
原理:
当打印一个对象时,底层会调用对象的toString方法,将对象变为字符串,打印到控制台
System:类名
out:静态变量
System.out:获取打印对象
println();方法
*/

//println源码
public void println(Objectx) {
String s = String.valueOf(x); //先通过String.valueOf()获取对象;
synchronized (this) {
print(s);
newLine();
}
}

//valueOf源码
public static String valueOf(Objectobj) {
return (obj == null) ? "null" : obj.toString(); //底层仍然是obj.toString()方法
}

所以println();方法先调用了String.valueOf();valueOf()的底层又调用了String包下的obj.toSting()方法

String包下的equals方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
源码
String 类中重写了 equals() 方法用于比较两个字符串的内容是否相等。
先判断两个串的地址是否相同,相同则返回true,不同则进行比较内容
*/
public boolean equals(ObjectanObject) {
if (this == anObject) {
return true;
}
if (anObjectinstanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}

/*
代码举例
*/
String s1 = "Hello"; // String 直接创建
String s2 = "Hello"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Hello"); // String 对象创建
String s5 = new String("Hello"); // String 对象创建

s1 == s1; // true, 相同引用
s1 == s2; // true, s1 和 s2 都在公共池中,引用相同
s1 == s3; // true, s3 与 s1 引用相同
s1 == s4; // false, 不同引用地址
s4 == s5; // false, 堆中不同引用地址

s1.equals(s3); // true, 相同内容
s1.equals(s4); // true, 相同内容
s4.equals(s5); // true, 相同内容

浅克隆、深克隆的区别

需注意克隆是指克隆对象整体以及内部的属性

浅克隆:我们这里说的浅拷贝是指我们拷贝出来的对象内部的引用类型变量和原来对象内部引用类型变量是同一引用(指向同一对象)。但是我们拷贝出来的对象和新对象不是同一对象。基本数据类型直接拷贝数据值(开辟新空间),引用数据类型会直接拷贝地址,但字符串会复用串池,有final修饰的存在


深克隆:全部拷贝原对象的内容,包括内存的引用类型也进行拷贝,基本数据类型直接拷贝数据值(开辟新空间),引用数据类型会重新创建对象并赋值,但字符串会复用串池


浅克隆可以使用类Object下的Clone()方法

深克隆可以使用第三方工具:

原理:Gson可以将对象序列化成JSON,也可以将JSON反序列化成对象,所以我们可以用它进行深拷贝。

  1. 导入jar包

  2. 将对象变为字符串

  3. 将字符串变为对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public void gsonCopy() {

Address address = new Address("杭州", "中国");
User user = new User("大山", address);

// 使用Gson序列化进行深拷贝
Gson gson = new Gson();
User copyUser = gson.fromJson(gson.toJson(user), User.class);
/*
也可以写作
String s = gson.toJson(user);
User copyUser = gson.fromJson(s, User.class);
*/
// 修改源对象的值
user.getAddress().setCity("深圳");

// 检查两个对象的值不同
assertNotSame(user.getAddress().getCity(), copyUser.getAddress().getCity());
}

类Objects: Object的工具类,位于java.util包

静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
先做地址判等、非空判断、然后再调用Object的实例化equals()方法比较两个对象的地址值是否相等
细节:
如果重写了Object的实例化equals()方法,则会比较属性值,否则会做地址判等
*/
public static boolean equals(Objecta, Objectb) {
return (a == b) || (a != null &amp;&amp; a.equals(b));
}

//判断是否为空
public static boolean isNull(Objectobj) {
return obj == null;
}

//判断是否不空
public static boolean nonNull(Objectobj) {
return obj != null;
}

莫道桑榆晚,为霞尚满天

类BigInteger:不可变的任意精度整数

所有操作都表现得好像BigIntegers用二进制补码表示法表示(如Java的原始整数类型)。 BigInteger为所有Java的原始整数运算符以及java.lang.Math中的所有相关方法提供类似物。 此外,BigInteger还提供模块化算术,GCD计算,素性测试,素数生成,位操作以及一些其他杂项操作的操作。

构造方法

1
2
3
4
5
6
7
8
//构造一个随机生成的BigInteger,均匀分布在[0,2^numBits - 1]的范围内。
BigInteger(intnumBits, Random rnd)

//将BigInteger的十进制字符串表示形式转换为BigInteger。
BigInteger(String val)

//将指定基数中BigInteger的String表示形式转换为BigInteger。
BigInteger(String val, intradix)
1
2
3
4
5
6
7
8
9
静态方法	  
//返回一个BigInteger,其值等于指定的 long
//只能在long的范围内
/*
在内部对-16~16进行了优化,先创建好了-16~16的BigInteger对象,多次获取不会重新创建
对象一旦创建,内部的数据不会改变,不会改变参与计算的BigInteger对象中的值,而是产生一个
新的BigInteger对象记录新值。
*/
static BigInteger valueOf(long val)

BigInteger为什么能存这么大数?

BigInteger对象存数原理是
成员变量:final intsignum;是符号位 1:正数 ,0:符号位为0,-1:负数

final int[] mag; index=0是符号位,其他位置全用来分段存数,以二进制的补码方式存数

类BigDecimal:用于小数精确计算、表示很大的数

不变的,任意精度的带符号的十进制数字。

通过构造方法创建对象

1
2
3
4
5
6
7
8
9
10
11
//将 double转换为 BigDecimal ,它是 double的二进制浮点值的精确十进制表示。
//可能不精确,不建议使用
BigDecimal(double val)

/*将 BigDecimal的字符串表示 BigDecimal转换为 BigDecimal 。
对于float和double NaN和±Infinity之外的值,
此构造函数与Float.toString(float)和Double.toString(double)返回的值兼容。
这通常是将float或double转换为BigDecimal的首选方式,
因为它不会遭受BigDecimal(double)构造函数的不可预测性。
*/
BigDecimal(String val)

通过静态方法获取对象

1
2
3
4
5
6
/*
转换一个 double成 BigDecimal ,使用 double通过所提供的规范的字符串表示
Double.toString(double)方法。
*/
static BigDecimal valueOf(double val)

细节:

  1. 如果数字不大,没有超出double的范围,建议使用静态方法

  2. 如果数字很大,超出了double的范围,建议使用构造方法

  3. 如果我们传递的是[0-10]的整数,那么方法会返回已经创建好的对象,不会重新创建

BigDecimal的使用

1
2
3
4
5
6
7
8
9
10
public BigDecimal add(BigDecimal val) //加法

public BigDecimal subtract(BigDecimal val) //减法

public BigDecimal multiply(BigDecimal val) //乘法

public BigDecimal divide(BigDecimal val) //除法 除不尽时候不可用

public BigDecimal divide(BigDecimal val,精确几位,舍入模式) //除法

BigDecimal底层存储方法:

将小数每一位按照ASCII码表的值,对应存入到数组中

正则表达式:校验字符串是否满足一定的规则

正则表达式的作用:
  1. 校验字符串是否满足规则

  2. 在一段文本中查找满足要求的内容

字符串校验

字符类(只匹配一个字符)

[abc]

[^abc]

[a-zA-Z]

[a-d[m-p]]

[a-z&&[def]]

[a-z&&[^bc]]

[a-z&&[^m-p]]

只能是a||b||c

除了a,b,c之外的任何一个字符

只能是a-z||A-Z

只能是a-d||m-p 括起来也表示或者的意思

a-z与[def]的交集:只能是d,e,f

a-z与[^bc]的交集:只能是a,d-z

a-z与[^m-p]的交集:是a-l,q-z

预定义字符(只匹配一个字符)

.

\d

\D

\s

\S

\w

\W

任何字符

一个数字[0-9]

非数字[^0-9]

一个空白字符[\t\n\x0B\f\r]

非空白字符[^\s]

[a-zA-Z_0-9] 字母、数字、下划线

[^\W]

数量词

X?

X*

X+

X{n}

X{n,}

X{n,m}

X,一次或0次

X,零次或多次

X,一次或多次

X,正好n次

X,至少n次

X,至少n次但是不超过m次

1
2
3
4
5
6
7
8
手机号验证的正则表达式

//分成三部分理解:
//第一部分:手机号只能是1开头
//第二部分:手机号的第二位是3-9之间的任意数字
//第三部分:手机号第三位到最后一位的9位数字可以是任意数字
String regex = "1[3-9]\\d{9}";
System.out.printlf("15148877290".matches(regex));

座机号验证的正则表达式

1
2
3
4
5
6
//座机号分成三部分
//区号:一定是以0开头,区号从第二位开始可以是任意数字,可以出现2-3次
//-:可以出现0次或者1次
//号码:第一位不能0开头,其余可以是任意数字,号码总长度5-10位
String regex = "0\\d{2,3}-?[1-9]\\d{4,9}";
System.out.println("0478-1234567".matches(regex));

邮箱号验证的正则表达式

1
2
3
4
5
6
7
8
9
10
// 分为三部分:
// 第一部分@左:数字、字母、下划线,至少出现一次
// 第二部分@:只能出现一次
// 第三部分:分为三小部分
// .左:长度为2-6,不能出现下划线,可以是数字、字母
// .:出现一次
// .右:大写字母、小写字母均可,只能出现2-3次
// 将.和.右看为一个整体,该整体可以出现1-2次
// 如:dmk123@pci.com.cn
String regex = "\\w+@[\\w&amp;&amp;[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2}";

用户名验证的正则表达式

1
2
//大小写字母、数字、下划线,一共4-16位
String regex = "\\w{4,16}";

身份证号简单验证的正则表达式

1
2
3
4
//前17位任意数字,最后一位可以是X、x
String regex = "[1-9]\\d{16}[\\dXx]";
//忽略大小写 (?i)可以将后面的字母忽略大小写
String regex2 = "[1-9]\\d{16}(\\d|(?i)x);
正则表达式插件
在idea中,提供了正则表达式的插件,帮助我们去快速书写正则表达式—— any-rule

爬虫

在一段文本中,按照一定的字符串要求进行爬取。

爬虫举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//爬取的目标串
String str = Java自从95年问世以来,经历了很多版本,目前企业中用的最多是Java8和Java11,+
因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在不久的未来Java17也会逐渐登上历史的舞台;

/*
//Pattern:表示正则表达式
//Matcher:文本匹配器,按照正则表达式的规则去读取字符串,从头开始读取。在大串中匹配合适的子串

//获取正则表达式对象
Pattern p = new Pattern.compile("Java\\d{0,2}");

// 获取文本匹配器对象
// m:文本匹配器对象
// str:大串
// p:规则
// m要在str中寻找符合p规则的小串
Matcher m = p.matcher(str);

// 拿着文本匹配器从头开始读取,寻找是否有满足条件的子串
// 如果没有,方法返回false
// 如果有,返回true。在底层记录子串的起始索引和结束索引+1
boolean b = m.find();

// 方法底层会根据find方法记录的索引进行字符串的截取
// subString(起始索引,结束索引);包头不包尾,比如截取(0,4),截取的为0,1,2,3
String s1 = m.group();
system.out.println(s1);
*/

//1.获取正则表达式对象
Pattern p = Pattern.compile("Java\\d{0,2}");

//2.获取文本匹配器对象
// 拿着m去读取str,找到符合p规则的子串
Matcher m = p.matcher(str);

//3.利用循环获取
while(m.find()){
String s = m.group();
System.out.println(s);n
}

带条件的爬取:

代码块中的例子,只想爬取带版本号的Java,但是只要Java,不要版本号

带条件的爬取

1
2
3
4
5
//?理解为前面的数据Java
// =表示Java后面要跟随的数据
// 但是在获取的时候,只获取前半部分
String regex = "Java(?=8|11|17);

正则表达式在字符串中的应用

实例化方法

1
2
3
4
5
6
7
8
//判断字符串是否满足正则表达式的规则
public String[] matches(String regex);

//按照正则表达式的规则进行替换
public String replaceAll(String regex,String newStr);

//按照正则表达式的规则切割字符串
public String[] split(String regex);

分组

即正则表达式中的(),每组都有组号,也就是序号

规则1:从1开始,连续不间断

规则2:从左括号为基准,最左边的是第一组,其次是第二组,以此类推。

捕获分组:后续仍会继续使用到分组

在正则内部使用分组:\组号

在正则外部使用分组:$组号

非捕获分组:后续不会继续使用到分组,仅仅只是为了分组操作

(**?: ** )

特点:不占用分组

捕获分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//需求一:判断一个字符串的开始字符和结束字符是否一致
String regex = "(.).+\\1";
System.out.println("a13a".matches(regex));

//需求二:判断一个字符串的开始部分和结束部分是否一致,可以是多个字符
String regex = "(.+).+\\1";
System.out.println("abc13abc".matches(regex));

//需求三:判断一个字符串的开始部分和结束部分是否一致,开始部分内的每个字符都必须一致
String regex = "((.)\\2*).+\\1"; \\将首字母(.)看作一组,反复\\2出现*次
System.out.println("aaa13aaa".matches(regex));

//需求三:将字符串中的重复内容去重
String regex = (wyxxxxxbbbbbbbccccccc);
//将任意字符看为第一组,且重复出现至少一次,$1在正则表达式之外使用第一个分组
String result= str.replaceAll("(.)\\1+";,"$1");
System.out.println("wyxbc";);

JDK7之前的时间类

Date时间类

Date时间类是一个JDK写好的javabean类,用来表示时间,精确到秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
利用空参构造创建的对象,表示系统当前时间

利用有参构造创建的对象,表示指定时间

Date类的构造方法与实例化方法

public Date(){} //无参构造 表示当前时间
public Date(long date){}//有参构造,指定时间

public void setTime(long time) //设置、修改时间 (ms)
public long getTime() //获取时间对象的毫秒值

//需求一:打印时间原点一年之后时间
//1.创建一个时间对象,表示时间原点
Date d1 = new Date(0L);

// 2.获取d1时间的毫秒值
long time = d1.getTime();

//3.在这个基础上加一年的毫秒值即可
time = time + 1000L * 60 * 60 * 24 * 365;

//把计算之后的毫秒值,再设置回d1当中
d1.setTime(time);

//打印d1
System.out.printlf(d1);

// 需求二:定义任意两个Date对象,比较一下时间前后
// 创建随机数对象
Random r = new Random();
// 将随机数的绝对值传入时间对象参数
Date d1 = new Date(Math.abs(r.nextInt()));
Date d2 = new Date(Math.abs(r.nextInt()));
// 获取毫秒值
long time1 = d1.getTime();
long time2 = d2.getTime();

// 再进行时间比较,比较time1 和 time2值的大小

SimpleDateFormat类

格式化:把时间格式按需求更改

解析:将字符串表示的时间变成Date对象

1
2
public SimpleDateFormat() 	//使用默认格式构造
public SimpleDateFormat(String pattern) //使用指定格式构造
1
2
public final String format(Date date) //格式化(日期对象->字符串)
public Date parse(String source) //解析(字符串->日期对象)

格式化时间常用模式对应关系

y 年 H 时

M 月 m 分

d 日 s 秒

可查阅API文档

1
2
3
4
5
6
7
8
9
10
11
// 1.利用空参构造创建SimpleDateFormat对象,默认格式
SimpleDateFormatsdf1 = new SimpleDateFormat();
Data d1 = new Date();
String str1 = sdf1.format(d1);
System.out,println(str1);

//2.利用带参构造创建SimpleDateFormat对象,指定格式
SimpleDateFormatsdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EE");
Date d2 = new Date();
Stirng str2 = sdf2.format(d2);
System.out.println(str2);
1
2
3
4
5
6
7
String str = "2024-6-1 10:33:19";

// 创建DateSimpleFormat对象,格式与字符串中的格式必须一致
DateSimpleFormatdsf = new DateSimpleFormat("yyyy-MM-dd HH:mm:ss");
// 解析
Date date = sdf.parse(data);
System.out,println(date);

将一个格式的时间转换为另一个格式的时间

方法:

先将需要转换格式的时间,按照格式解析为时间对象,

再将时间对象转化为格式化为想要的格式。

Calendar类

是一个抽象类,不能直接创建对象

日历类获取到的月份是0-11,需要+1处理

在外国星期日是一周中的第一天,所以1对应的星期日

1
public static Calendar getInstance()  //获取当前时间的日历对象

Calendar 类常用方法的记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 获取时间
// 使用默认时区和语言环境获得一个日历
Calendar cal = Calendar.getInstance();
// 赋值时年月日时分秒常用的6个值,注意月份下标从0开始,所以取月份要+1
System.out.println("年:" + cal.get(Calendar.YEAR));
System.out.println("月:" + (cal.get(Calendar.MONTH) + 1));
System.out.println("日:" + cal.get(Calendar.DAY_OF_MONTH));
System.out.println("时:" + cal.get(Calendar.HOUR_OF_DAY));
System.out.println("分:" + cal.get(Calendar.MINUTE));
System.out.println("秒:" + cal.get(Calendar.SECOND));


// 设置时间
// 月份的下标从 0 开始,设置时同样需要注意,比如我们设置为 2 月 15 日除夕当晚的倒计时的最后一秒: 2018-02-15 23:59:59
//可以这样:
Calendar cal = Calendar.getInstance();
// 如果想设置为某个日期,可以一次设置年月日时分秒,由于月份下标从0开始赋值月份要-1
// cal.set(year, month, date, hourOfDay, minute, second);
cal.set(2018, 1, 15, 23, 59, 59);

//或者也可以单个字段一一设置:

// 或者6个字段分别进行设置,由于月份下标从0开始赋值月份要-1
cal.set(Calendar.YEAR, 2018);
cal.set(Calendar.MONTH, Calendar.FEBRUARY);
cal.set(Calendar.DAY_OF_MONTH, 15);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
System.out.println(cal.getTime());

时间计算

add方法:
比如在除夕当晚最后一秒,add 一秒:

1
2
3
4
5
Calendar cal = Calendar.getInstance();
System.out.println(cal.getTime());
cal.set(2018, 1, 15, 23, 59, 59);
cal.add(Calendar.SECOND, 1);
System.out.println(cal.getTime());

打印时间结果如下,日期会自动进入下一天:

1
2
Thu Feb 15 23:59:59 CST 2018
Fri Feb 16 00:00:00 CST 2018

JDK8新增的时间类

新增判断方法,计算时间间隔的方法

解决了多线程下会导致数据安全的问题

时间日期对象都是不可变的,解决了这个问题

ZoneId获取时区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
static Set<string> getAvailableZoneIds() 获取Java中支持的所有时区
static ZoneId systemDefault() 获取系统默认时区
static Zoneld of(string zoneld) 获取一个指定时区
*/

//1.获取所有的时区名称
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
System.out.println(zoneIds.size());//600
System.out.println(zoneIds);// Asia/Shanghai

//2.获取当前系统的默认时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);//Asia/Shanghai

//3.获取指定的时区
ZoneId zoneId1 = ZoneId.of("Asia/Pontianak");
System.out.println(zoneId1);//Asia/Pontianak

Instant时间戳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
static Instantnow() 获取当前时间的Instant对象(标准时间)
static InstantofXxxx(long epochMilli) 根据(秒/毫秒/纳秒)获取Instant对象
ZonedDateTime atZone(ZoneIdzone) 指定时区
boolean isxxx(InstantotherInstant) 判断系列的方法
InstantminusXxx(long millisToSubtract) 减少时间系列的方法
InstantplusXxx(long millisToSubtract) 增加时间系列的方法
*/
//1.获取当前时间的Instant对象(标准时间)
Instantnow = Instant.now();
System.out.println(now);

//2.根据(秒/毫秒/纳秒)获取Instant对象
Instantinstant1 = Instant.ofEpochMilli(0L);
System.out.println(instant1);//1970-01-01T00:00:00z

Instantinstant2 = Instant.ofEpochSecond(1L);
System.out.println(instant2);//1970-01-01T00:00:01Z

Instantinstant3 = Instant.ofEpochSecond(1L, 1000000000L);
System.out.println(instant3);//1970-01-01T00:00:027

//3. 指定时区
ZonedDateTime time = Instant.now().atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(time);


//4.isXxx 判断
Instantinstant4=Instant.ofEpochMilli(0L);
Instantinstant5 =Instant.ofEpochMilli(1000L);

//5.用于时间的判断
//isBefore:判断调用者代表的时间是否在参数表示时间的前面
boolean result1=instant4.isBefore(instant5);
System.out.println(result1);//true

//isAfter:判断调用者代表的时间是否在参数表示时间的后面
boolean result2 = instant4.isAfter(instant5);
System.out.println(result2);//false

//6.InstantminusXxx(long millisToSubtract) 减少时间系列的方法
Instantinstant6 =Instant.ofEpochMilli(3000L);
System.out.println(instant6);//1970-01-01T00:00:03Z

Instantinstant7 =instant6.minusSeconds(1);
System.out.println(instant7);//1970-01-01T00:00:02Z

ZoneDateTime带时区的时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
static ZonedDateTime now() 获取当前时间的ZonedDateTime对象
static ZonedDateTime ofXxxx(。。。) 获取指定时间的ZonedDateTime对象
ZonedDateTime withXxx(时间) 修改时间系列的方法
ZonedDateTime minusXxx(时间) 减少时间系列的方法
ZonedDateTime plusXxx(时间) 增加时间系列的方法
*/
//1.获取当前时间对象(带时区)
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);

//2.获取指定的时间对象(带时区)1/年月日时分秒纳秒方式指定
ZonedDateTime time1 = ZonedDateTime.of(2023, 10, 1,
11, 12, 12, 0, ZoneId.of("Asia/Shanghai"));
System.out.println(time1);

//通过Instant+ 时区的方式指定获取时间对象
Instantinstant= Instant.ofEpochMilli(0L);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime time2 = ZonedDateTime.ofInstant(instant, zoneId);
System.out.println(time2);


//3.withXxx 修改时间系列的方法
ZonedDateTime time3 = time2.withYear(2000);
System.out.println(time3);

//4. 减少时间
ZonedDateTime time4 = time3.minusYears(1);
System.out.println(time4);

//5.增加时间
ZonedDateTime time5 = time4.plusYears(1);
System.out.println(time5);

DateTimeFormatter时间的格式化和解析

1
2
3
4
5
6
7
8
9
10
11
/*
static DateTimeFormatter ofPattern(格式) 获取格式对象
String format(时间对象) 按照指定方式格式化
*/
//获取时间对象
ZonedDateTime time = Instant.now().atZone(ZoneId.of("Asia/Shanghai"));

// 解析/格式化器
DateTimeFormatter dtf1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm;ss EE a");
// 格式化
System.out.println(dtf1.format(time));

LocalDate年、月、日

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//1.获取当前时间的日历对象(包含 年月日)
LocalDate nowDate = LocalDate.now();
//System.out.println("今天的日期:" + nowDate);
//2.获取指定的时间的日历对象
LocalDate ldDate = LocalDate.of(2023, 1, 1);
System.out.println("指定日期:" + ldDate);

System.out.println("=============================");

//3.get系列方法获取日历中的每一个属性值//获取年
intyear = ldDate.getYear();
System.out.println("year: " + year);
//获取月//方式一:
Month m = ldDate.getMonth();
System.out.println(m);
System.out.println(m.getValue());

//方式二:
intmonth = ldDate.getMonthValue();
System.out.println("month: " + month);


//获取日
intday = ldDate.getDayOfMonth();
System.out.println("day:" + day);

//获取一年的第几天
intdayofYear = ldDate.getDayOfYear();
System.out.println("dayOfYear:" + dayofYear);

//获取星期
DayOfWeek dayOfWeek = ldDate.getDayOfWeek();
System.out.println(dayOfWeek);
System.out.println(dayOfWeek.getValue());

//is开头的方法表示判断
System.out.println(ldDate.isBefore(ldDate));
System.out.println(ldDate.isAfter(ldDate));

//with开头的方法表示修改,只能修改年月日
LocalDate withLocalDate = ldDate.withYear(2000);
System.out.println(withLocalDate);

//minus开头的方法表示减少,只能减少年月日
LocalDate minusLocalDate = ldDate.minusYears(1);
System.out.println(minusLocalDate);


//plus开头的方法表示增加,只能增加年月日
LocalDate plusLocalDate = ldDate.plusDays(1);
System.out.println(plusLocalDate);

//-------------
// 判断今天是否是你的生日
LocalDate birDate = LocalDate.of(2000, 1, 1);
LocalDate nowDate1 = LocalDate.now();

MonthDay birMd = MonthDay.of(birDate.getMonthValue(), birDate.getDayOfMonth());
MonthDay nowMd = MonthDay.from(nowDate1);

System.out.println("今天是你的生日吗? " + birMd.equals(nowMd));//今天是你的生日吗?

LocalTime 时、分、秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 获取本地时间的日历对象。(包含 时分秒)
LocalTime nowTime = LocalTime.now();
System.out.println("今天的时间:" + nowTime);

inthour = nowTime.getHour();//时
System.out.println("hour: " + hour);

intminute = nowTime.getMinute();//分
System.out.println("minute: " + minute);

intsecond = nowTime.getSecond();//秒
System.out.println("second:" + second);

intnano = nowTime.getNano();//纳秒
System.out.println("nano:" + nano);
System.out.println("------------------------------------");
System.out.println(LocalTime.of(8, 20));//时分
System.out.println(LocalTime.of(8, 20, 30));//时分秒
System.out.println(LocalTime.of(8, 20, 30, 150));//时分秒纳秒
LocalTime mTime = LocalTime.of(8, 20, 30, 150);

//is系列的方法
System.out.println(nowTime.isBefore(mTime));
System.out.println(nowTime.isAfter(mTime));

//with系列的方法,只能修改时、分、秒
System.out.println(nowTime.withHour(10));

//plus系列的方法,只能修改时、分、秒
System.out.println(nowTime.plusHours(10));

LocalDateTime 年、月、日、时、分、秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 当前时间的的日历对象(包含年月日时分秒)
LocalDateTime nowDateTime = LocalDateTime.now();

System.out.println("今天是:" + nowDateTime);//今天是:
System.out.println(nowDateTime.getYear());//年
System.out.println(nowDateTime.getMonthValue());//月
System.out.println(nowDateTime.getDayOfMonth());//日
System.out.println(nowDateTime.getHour());//时
System.out.println(nowDateTime.getMinute());//分
System.out.println(nowDateTime.getSecond());//秒
System.out.println(nowDateTime.getNano());//纳秒
// 日:当年的第几天
System.out.println("dayofYear:" + nowDateTime.getDayOfYear());
//星期
System.out.println(nowDateTime.getDayOfWeek());
System.out.println(nowDateTime.getDayOfWeek().getValue());
//月份
System.out.println(nowDateTime.getMonth());
System.out.println(nowDateTime.getMonth().getValue());

LocalDate ld = nowDateTime.toLocalDate();
System.out.println(ld);

LocalTime lt= nowDateTime.toLocalTime();
System.out.println(lt.getHour());
System.out.println(lt.getMinute());
System.out.println(lt.getSecond());

Duration 时间间隔(秒,纳,秒)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 本地日期时间对象。
LocalDateTime today = LocalDateTime.now();
System.out.println(today);

// 出生的日期时间对象
LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
System.out.println(birthDate);

Duration duration = Duration.between(birthDate, today);//第二个参数减第一个参数
System.out.println("相差的时间间隔对象:" + duration);

System.out.println("============================================");
System.out.println(duration.toDays());//两个时间差的天数
System.out.println(duration.toHours());//两个时间差的小时数
System.out.println(duration.toMinutes());//两个时间差的分钟数
System.out.println(duration.toMillis());//两个时间差的毫秒数
System.out.println(duration.toNanos());//两个时间差的纳秒数

Period 时间间隔(年,月,日)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 当前本地 年月日
LocalDate today = LocalDate.now();
System.out.println(today);

// 生日的 年月日
LocalDate birthDate = LocalDate.of(2000, 1, 1);
System.out.println(birthDate);

Period period = Period.between(birthDate, today);//第二个参数减第一个参数

System.out.println("相差的时间间隔对象:" + period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());

System.out.println(period.toTotalMonths());

ChronoUnit 时间间隔(所有单位)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 当前时间
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
// 生日时间
LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1,0, 0, 0);
System.out.println(birthDate);

System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthDate, today));
System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthDate, today));
System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthDate, today));
System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthDate, today));
System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthDate, today));
System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthDate, today));
System.out.println("相差的秒数:" + ChronoUnit.SECONDS.between(birthDate, today));
System.out.println("相差的毫秒数:" + ChronoUnit.MILLIS.between(birthDate, today));
System.out.println("相差的微秒数:" + ChronoUnit.MICROS.between(birthDate, today));
System.out.println("相差的纳秒数:" + ChronoUnit.NANOS.between(birthDate, today));
System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthDate, today));
System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthDate, today));
System.out.println("相差的世纪(百年)数:" + ChronoUnit.CENTURIES.between(birthDate, today));
System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthDate, today));
System.out.println("相差的纪元数:" + ChronoUnit.ERAS.between(birthDate, today));

包装类

包装类的本质是创建了一个对象,用一个对象把基本数据类型包装起来。
集合中不能存储基本数据类型,只能存储对象,需要用到包装类。
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类,如下:

基本类型 对应的包装类(位于java.lang包中)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

自动装箱与自动拆箱

自动装箱:把基本数据类型自动转换为其对应的包装类

自动拆箱:把包装类自动转换为其对应的基本数据类型

Integer类

包装一个对象中的原始类型 int的值

Integer类构造方法及静态方法

方法名 说明
public Integer(int  value) 有参构造,根据 int值创建 Integer 对象(过时)
public Integer(String s) 有参构造,根据 String 值创建 Integer 对象(过时)
public static Integer valueOf(inti) 返回表示指定的 int值的 Integer实例
public static Integer valueOf(String s) 返回保存指定String值的 Integer 对象
static string tobinarystring(inti) 得到二进制
static string tooctalstring(inti) 得到八进制
static string toHexstring(inti) 得到十六进制
static intparseInt(string s) 将字符串类型的整数转成int类型的整数
两种方式获取对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// //public Integer(intvalue):根据 int值创建 Integer 对象(过时)
// Integer i1 = new Integer(100);
// System.out.println(i1);

// //public Integer(String s):根据 String 值创建 Integer 对象(过时)
// Integer i2 = new Integer("100");
// //Integer i2 = new Integer("abc"); //NumberFormatException
// System.out.println(i2);
// System.out.println("--------");



//public static Integer valueOf(inti):返回表示指定的 int值的 Integer 实例
Integer i3 = Integer.valueOf(100);
System.out.println(i3);

//public static Integer valueOf(String s):返回保存指定String值的Integer对象
Integer i4 = Integer.valueOf("100");
System.out.println(i4);

建议:获取Integer对象的时候不要自己new,而是采取直接赋值或者静态方法valueOf的方式。

因为在实际开发中,-128~127之间的数据,用的比较多。如果每次使用都是new对象,那么太浪费内存了。

所以,提前把这个范围之内的每一个数据都创建好对象,如果要用到了不会创建新的,而是返回已经创建好的对象。

两种方式获取对象的区别
底层原理:

Integer.valueOf()对-128~127 之间的256个数进行了优化,提前创建好了对象,只需要使用静态方法返回对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//因为在实际开发中,-128~127之间的数据,用的比较多。
//如果每次使用都是new对象,那么太浪费内存了
//所以,提前把这个范围之内的每一个数据都创建好对象
//如果要用到了不会创建新的,而是返回已经创建好的对象。
Integer i6 = Integer.valueOf(127);
Integer i7 = Integer.valueOf(127);
System.out.println(i6 == i7);//true

Integer i8 = Integer.valueOf(128);
Integer i9 = Integer.valueOf(128);
System.out.println(i8 == i9);//false

//因为看到了new关键字,在Java中,每一次new都是创建了一个新的对象
//所以下面的两个对象都是new出来,地址值不一样。
/* Integer i10 = new Integer(127);
Integer i11 = new Integer(127);
System.out.println(i10 == i11);

Integer i12 = new Integer(128);
Integer i13 = new Integer(128);
System.out.println(i12 == i13);*/

源码:

1
2
3
4
5
6
7
8
9
10
/*当调用valueOf的方法是先会对传入的参数进行判断,然后根据判断情况返回相应的对象
public static Integer valueOf(inti) {
//在此范围内返回一个对象
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)]; //cache为数组
return new Integer(i);
}

//Integer类型的数组
static final Integer[] cache;
常用静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
public static string tobinarystring(inti) 得到二进制
public static string tooctalstring(inti) 得到八进制
public static string toHexstring(inti) 得到十六进制
public static intparseInt(string s) 将字符串类型的整数转成int类型的整数
*/

//1.把整数转成二进制,十六进制
String str1 = Integer.toBinaryString(100);
System.out.println(str1);//1100100

//2.把整数转成八进制
String str2 = Integer.toOctalString(100);
System.out.println(str2);//144

//3.把整数转成十六进制
String str3 = Integer.toHexString(100);
System.out.println(str3);//64

//4.将字符串类型的整数转成int类型的整数
//强类型语言:每种数据在java中都有各自的数据类型
//在计算的时候,如果不是同一种数据类型,是无法直接计算的。
inti = Integer.parseInt("123");
System.out.println(i);
System.out.println(i + 1);//124
//细节1:
//在类型转换的时候,括号中的参数只能是数字不能是其他,否则代码会报错
//细节2:
//8种包装类当中,除了Character都有对应的parseXxx的方法,进行类型转换
String str = "true";
boolean b = Boolean.parseBoolean(str);
System.out.println(b);
// 除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型:

// `public static byte parseByte(String s)`:将字符串参数转换为对应的byte基本类型。
// `public static shortparseShort(String s)`:将字符串参数转换为对应的short基本类型。
// **`public static intparseInt(String s)`:将字符串参数转换为对应的int基本类型。**
// **`public static long parseLong(String s)`:将字符串参数转换为对应的long基本类型。**
// `public static floatparseFloat(String s)`:将字符串参数转换为对应的float基本类型。
// `public static double parseDouble(String s)`:将字符串参数转换为对应的double基本类型。
// `public static boolean parseBoolean(String s)`:将字符串参数转换为对应的boolean基本类型。
包装类计算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 在以前 包装类进行计算
Integer i1 = new Integer(1);
Integer i2 = new Integer(2);

// 步骤:
// 1.先将对象进行拆箱
// 2.相加
// 3.将结果再次装箱

intresult= i1.intValue() + i2.intValue();
Integer i3 = new Integer(result);
System.out.println(i3);

// 在JDK5的时候提出了一个机制,自动装箱和自动拆箱
Integer i = 4;//自动装 箱。相当于Integer i = Integer.valueOf(4);
i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
//加法运算完成后,再次装箱,把基本数值转成对象。
键盘录入
1
2
3
4
5
6
7
8
9
Scanner sc = new Scanner(System.in);
String str = sc.next();
System.out.println(str);
/*
弊端:
当使用next、nextInt、nextLine接收数据的时候,遇到空格、制表符、回车都会停止
约定:使用nextLine来录入数据
再根据需要的数据类型进行数据转换
*/