一. 字符串相关:
String类
-
是final的(该有的功能都有了,不用、不可以再继承了)
-
位于java.lang包
-
实现了Serializable接口:表示字符串是支持序列化的;
实现了Comparable接口:(比较器)表示可以比较大小;
比较两个字符串:用equals比较;
直接的“ ”里面的字符串和new出来的字符串比较(地址比较:==)不同:地址不同。 -
内部定义了final char[] value 用于存储字符串数据(数组不可以重新赋值,数组元素也不可以在被修改了,只可以在新指定的内存区域赋值)
不可变字符序列。(所有的拼接、替换、去空格、截取等相应的操作,都是生成的新字符串,不会影响到原来的字符串) -
String常用方法:API文档
1.String类型与基本数据类型、包装类之间的转换
不可以直接强制转换的,父子类才可以强转。
- String - - >基本数据类型、包装类 :调用包装类的静态方法:parseXxx(str);
String str1 = "123";
int num = Integer.parseInt(str1);
- 基本数据类型、包装类 – >String类型:调用String重载的valueOf(xxx);
String str2 = String.valueOf(num); //str2为123了
2.String类型与char[ ]之间的转换
- String–>char[ ]: 调用String的toCharArray()方法:
public static void main(String[] args) {
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
}
- char[ ] -->String类:调用String构造器
public static void main(String[] args) {
char[] arr = new char[]{'h','e','l','l','o'};
String str = new String(arr);
System.out.println(str);
}
3.String类型与字节Byte[ ]之间的转换
- String --> Byte[ ]: 调用String的getBytes();- ->得到相应的ascll码(编码:字符串 转换成 看不懂的 字节)
public static void main(String[] args) {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes();//使用默认的字符集(UTF-8),进行转换
System.out.println(Arrays.toString(bytes));
}
- Byte[ ] 数组 --> String:调用String的构造器 (解码:看不懂的二进制字节 转换到 看得懂的 字符串)
(出现乱码的时候:很有可能是解码集不同造成的)
4.String对象的创建:
public static void main(String[] args) {
String str = "hello";
String str1 = new String();//本质:新建的char[0]
String str2 = new String("value");//新建一个长度是5的char型数组。
char[] value1 = {'a', 'b', 'c', 'd'};
String str3 = new String(value1); //相当于String str4 = new String("abcd");
char[] value2 = {'a', 'b', 'c', 'd'};
String str4 = new String(value2, 1, 2); //相当于String str5 = new String("bc");
System.out.println(str+"-"+str1+"-"+str2+"-"+str3+"-"+str4);
}
Q & A 1:
str:字面量定义的方式 VS str2:通过new+构造器的方式有什么区别?
1. str1数据在方法区中的字符常量池中,而new+构造器保存的地址值是:在堆空间中开辟空间之后,再对应的值。
2. 两个字面上定义的相同字符串是可以相等的(因为常量池中是不可以有相同的内容的),但是两个new+构造器出来的字符串不能相等(两个都是新的)。
3. 加上final之后可能就看为常量了,结果可能为true。
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1 == s4);
System.out.println(s3 == s4);
}
得出结果:
true
false
false
false
Q & A 2:
new+构造器的方法如:String s = new String(“abc”);
创建对象,在内存中创建了几个对象?
两个:一个是堆空间中的new结构创建的,另一个是char[]对应的常量池中的数据”abc”,而常量池中又不会存在两个相同的,所以如果常量池中先声明过了要用的那个,可以直接拿来用。
Q & A 3:
判断是否相等:(地址)
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld"; //简单字面量连接
String s4 = "hello"+"world"; //简单字面量连接
String s5 = "hello"+s2; //变量名出现,在堆中开辟空间(相当于new)
String s6 = s1 + "world";
String s7 = s1 + s2;
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);
System.out.println(s3 == s7);
System.out.println(s5 == s6);
System.out.println(s6 == s7);
}
输出结果:拼接结果是在常量池中操作,常量池中也不会有相同的常量; 只要有变量存在的,都会又多一个堆中的空间,即不相等。
true
false
false
false
false
false
但是,字符串调用intern()方法,返回值会返回到常量池中:
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
String s4 = "hello"+"world";
String s5 = s1+"world";
String s6 = s5.intern();
System.out.println(s3 == s6);
}
返回true。
String类的常用方法
public class StringTest {
public static void main(String[] args) {
String s1 = "Hello";
System.out.println(s1.length()); //1. 数组的返回长度:5
System.out.println(s1.charAt(2)); //2. 取指定位置上的字符:e;范围满足0~length-1
System.out.println(s1.isEmpty()); //3. 数组是否为空:false(判断的是数组的长度)
System.out.println(s1.toLowerCase(Locale.ROOT)); //4. 所有的转换为小写的字母
System.out.println(s1.toUpperCase(Locale.ROOT)); //大写
String s2 = s1.toLowerCase(Locale.ROOT);
System.out.println(s1); //5. s1没有改变,用new的String类是赋值,是赋给的新的空间给到的s2
System.out.println(s2); //s2改变了,新的
String s3 = " h el lo wor ld ";
String s4 = s3.trim(); //去除掉首位空格,中间的空格还是有的
System.out.println(s4);
String s5 = "helloworld";
String s6 = "HelloWorld";
System.out.println(s5.equals(s6)); //字符串匹配,不忽略大小写的情况
System.out.println(s5.equalsIgnoreCase(s6)); //字符串忽略大小写的比较(==是地址比较)
String s7 = "abc";
String s8 = s7.concat("def"); //连接
System.out.println(s8);
String s9 = "abc";
String s10 = new String("abe"); //ascll码相比较。(字符串排序)
System.out.println(s9.compareTo(s10));
String s11 = "好妹妹乐队";
String s12 = s11.substring(3); //取子串,下标从0开始
System.out.println(s11);
System.out.println(s12);
String s13 = s11.substring(1, 3); //左闭右开区间的取子串
System.out.println(s13);
}
}
测试结果:
5
l
false
hello
HELLO
Hello
hello
h el lo wor ld
false
true
abcdef
-2
好妹妹乐队
乐队
妹妹
String常用方法2:
找字符串:
public class StringTest2 {
public static void main(String[] args) {
String str1 = "helloworld";
boolean b1 = str1.endsWith("rld"); //查看是否以指定的字符串后缀结束
boolean b2 = str1.startsWith("hels"); //前缀是否相同(boolean类型)
boolean b3 = str1.startsWith("ll",2); //是不是以“**字符”在某号位置开头
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
String str2 = "wo";
System.out.println(str1.contains(str2)); //str1是否包含str2的字符串(字符串匹配)
System.out.println(str1.indexOf("o")); //首次重写的位置,没有的时候返回-1(从a开始的,后面都没有,于是返回了a-1的位置)
System.out.println(str1.indexOf("o", 5));
System.out.println(str1.lastIndexOf("o")); //从后往前的第一个字符串(返回的位置还是从前往后的位置
System.out.println(str1.lastIndexOf("o", 5));
}
}
测试结果:
true
false
true
true
4
6
6
4
Q & A:indexOf(str)与lastIndexOf(str)何时找的是一样的?
只存在唯一的str,或者不存在str。
String常用方法3:
public class StringTest3 {
public static void main(String[] args) {
String str1 = "少年先锋队少年";
System.out.println(str1.replace("少", "老")); //返回新的字符串
System.out.println(str1.replace('少', '老'));
String str2 = "123he938llo883wo44rl99384d038";
//第一次replace把所有的数字替换成逗号,第二次replace正则表达式,把首尾的逗号用空格替换。
System.out.println(str2.replaceAll("\\d+", ",").replaceAll("^,|,$",""));
}
}
测试结果:
老年先锋队老年
老年先锋队老年
he,llo,wo,rl,d
StringBuffer和StringBuilder
- 都是String的子类。
String 和StringBuilder 和 StringBuffer三者的异同有哪些?
- String :不可变字符序列:自身不可变,都是新生成的,所以产生一堆新的对象。
- StringBuffer:可变字符序列 ,是线程安全的,多线程数据量较大,效率低。(多线程 效率低)
- StringBuilder:(jdk1.5新增)可变字符序列 线程不安全,不做线程同步检查,因此效率高。 单线程数据量较大。
自身也是可变的,并且返回自身,所以从头到尾就一个变化的对象,最后返回变回自己。 - 相同点:他们三个底层使用的都是char[ ]数组存储。
源码分析:
public static void main(String[] args) {
//new char [0];
String str = new String();
//new char[]{'a','b','c'};
String str1 = new String("abc");
//Char value = new char[16];相当于创建了一个长度是16的字符数组
StringBuffer sb1 = new StringBuffer();
sb1.append('a'); //value[0] = 'a';
sb1.append('b'); //value[1] = 'b';
// Char value = new Char ["abc".length() + 16];
StringBuffer sb2 = new StringBuffer("abc");//(额外空出来16个大小)
System.out.println(sb2.length()); //length()返回的是:return count;所以结果是3
}
- 扩容问题:如果要添加的数据底层数组盛不了,那就需要扩容底层数组。默认情况下,扩容的大小是原来的2倍+2;同时将原有的数组中的元素复制到新的数组中。
- 指导意义:建议我们在开发过程中,使用StringBuffer(int capacity) 或者 StringBuilder(int capacity),具体用哪个还要考虑安不安全。
- 选择的问题:①是不是多线程的?不是多线程一定选StringBuilder;② 由于StringBuilder是新增的,更多的会选择StringBuilder。
StringBuffer用法
- StringBuilder也通用的。
- 常用方法列表:返回原来的,不是新的
- 重载的public StringBulider append(…)方法
append附加,添加新的字符序列,但是仍然返回对象自身
sb.append("aa").append("bb").append(123);
可以一直返回下去 - public StringBulider delete(int star,int end)
删除中间那一段,到end-1。返回自身。 - public StringBulider insert(…)
指定位置插入,返回自身。 - public StringBulider reverse()
逆序,返回自身。 - public String toString()
返回自身序列中字符串的表示形式。
- 具体用法:
sb.insert(0,"啊“).insert(0,"邓");
在0的位置先插入啊,再在新的0位置处插入邓。- 删除子字符串:
sb.delete(0,2);
删掉了0和1位置的字符。 - 删除单个字符:
sb.deleteCharAt(0).deleteCharAt(0);
删掉0号字符,再删掉0号字符。 - …
- 重载的public StringBulider append(…)方法
常见用法测试:
public static void main(String[] args) {
StringBuffer sb1 = new StringBuffer("abc");
sb1.append(1);
sb1.append('1');
System.out.println(sb1); //连接、类似于and
sb1.delete(2,4); //左闭右开原则
System.out.println(sb1); //可变的,直接修改了
sb1.replace(2,4,"hello"); //替换
System.out.println(sb1);
sb1.insert(2,false);
System.out.println(sb1); //插入,不是替换,前面的还在
System.out.println(sb1.length());
sb1.reverse();
System.out.println(sb1);
System.out.println(sb1.length()); //逆序
String sb2 = sb1.substring(1, 5); //返回的sb2,左闭右开原则
System.out.println(sb1);
System.out.println(sb2);
}
测试结果:
abc11
ab1
abhello
abfalsehello
12
olleheslafba
12
olleheslafba
lleh
重点关注:(StringBuffer和StringBuilder用法差不多)
- 增:append(xxx);
- 删:delete(int 开始的,int 结束位置);
- 改:setCharAt(int 数量,char 修改成什么字符);:修改某个字符; / replace(int 开始的位置,int结束的位置,修改的字符串);:替换成新的字符串
- 查:charAt(int n);
- 插入:insert(int offset,xxx);
- 长度:length();
- 遍历(不多):for+charAt();/ toString();
效率测试:
/*String效率测试*/
public void test{
String str8 = "";
long num1 = Runtime.getRuntime().freeMemory();// 获取系统剩余内存空间。
long time1 = System.currentTimeMillis();//获取系统的当前时间。
for (int i = 0; i < 5000; i++) {
str8 = str8 +i; //产生了5000个对象。
}
long num2 = Runtime.getRuntime().freeMemory();// 获取系统剩余内存空间。
long time2 = System.currentTimeMillis();//获取系统的当前时间。
System.out.println("String占用的内存空间为:"+(num1-num2));
System.out.println("String占用的时间为:"+(time2-time1));
}
/*Stringbuilder效率测试*/
public void test{
StringBuilder sb = new StringBuilder("");
long num3 = Runtime.getRuntime().freeMemory();
long time3 = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
sb.append(i); //只有一个对象。
}
long num4 = Runtime.getRuntime().freeMemory();
long time4 = System.currentTimeMillis();
System.out.println("StringBuilder所占的内存空间为:"+(num3-num4));
System.out.println("StringBuilder所占用的时间为:"+(time4-time3));
}
测试结果:
String占用的内存空间为:23167328
String占用的时间为:32
StringBuilder所占的内存空间为:0
StringBuilder所占用的时间为:1
三者效率比较:StringBuilder>StringBuffer>String
结论:所以在创建大量字符拼接,用String会产生大量无用对象,被GC掉,系统崩溃。
String和StringBuffer转换
String – >StringBuffer:调用StringBuffer/StringBuilder构造器
StringBuffer --> String:调用String构造器
方法②:调用公用的方法 toString();
一道面试算法题:
import org.junit.Test;
public class deBugTest {
@Test
public void testStringBuffer(){
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
System.out.println(sb.length());//4
System.out.println(sb);// "null"
StringBuffer sb1 = new StringBuffer(str);//抛异常:NullPointerException
System.out.println(sb1);
}
}
返回4的原因如下api:
rivate AbstractStringBuilder appendNull() {
ensureCapacityInternal(count + 4);
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
val[count++] = 'n';
val[count++] = 'u';
val[count++] = 'l';
val[count++] = 'l';
} else {
count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
}
this.count = count;
return this;
}
二、日期、时间相关类:
1. currentTimeMillis();
基准时间:1970年1月1日00:00:00 每个度量单位为1毫秒,0.001s (long类型)大约可以表示到±2.9亿年前后
long now = System.currentTimeMillis();
//返回的是当前时刻的毫秒数(从1970年01月01日00:00:00时刻到现在的毫秒数——时间戳:比如可以用在淘宝订单号的生成)
可以用两个currentTimeMillis()在代码头尾,测试代码效率。
2. Date类:
1.java.util.Date类(平时多用)
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
//构造器一:Date():创建一个对应当前时刻的Date对象
Date d1 = new Date();//需要导入包:alt+enter(因为不知是自动导入哪个类的date,所以要手动选择)
System.out.println(d1);
System.out.println(d1.toString());// 显示当前的时刻
//没有传参,表示当前时刻的时间,距离默认时刻的时间ms数(时间戳)。
System.out.println(d1.getTime());
//构造器二:创建指定时间戳的Date对象
//创建指定的日期: 传参的格式(加L;计算到毫秒)
Date d2 = new Date(1000L*3600*24*365*250);
System.out.println(d2); //返回到基准时间的时刻
}
}
返回结果:
Sun Mar 07 21:08:22 CST 2021
Sun Mar 07 21:08:22 CST 2021
1615122502935
Tue Nov 02 08:00:00 CST 2219
2. java.sql.Date类(数据库中的日期类型变量)
跟数据库交互的时候会涉及到的:
import java.sql.Date;
public class DateTest2 {
public static void main(String[] args) {
//构造器一: 造对象:如何实例化
Date date = new Date(352255552224L); //new java.sql.Date();+alt+enter
System.out.println(date);
//如何让util.Date(父类)对象和sql.Date(子类)对象相互转换?
//用getTime得到的时间戳进行转换
java.sql.Date date2 = new java.sql.Date(date.getTime());
}
}
3. DateFormat 和 SimpleDateFormat (简单)时间格式化类(最常用的):实现日期及时间ms的转换。
父子类:SimpleDateFormat是子类
- 使用:SimpleDateFormat 对日期Date类的格式化和解析
- "yyy-MM-dd hh:mm:ss"(年-大月-日 时-分-秒)只有月份M是大写的
(注意:这里的格式保持一致即可,可以同统一都写上面这个格式)
使用一:
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SimpleTimeZone;
public class test1 {
/*
SimpleDateFormat的使用: SimpleDateFormat 对日期Date类的格式化和解析
1. 两个操作
1.1 格式化:日期 --> 字符串
1.2 解析: 格式化逆过程,字符串 --> 日期
2. SimpleDateFormat实例化
*/
@Test
public void testSimpleDateFormat() throws ParseException {
//实例化:这里是默认的格式:
SimpleDateFormat sdf = new SimpleDateFormat();
//格式化:日期 转字符串
Date date = new Date();
System.out.println(date);
String format = sdf.format(date);
System.out.println(format);
//解析的过程:格式转化的逆过程,字符串 -->日期:
String str = "2021/3/8 下午8:15";
Date date1 = sdf.parse(str);
System.out.println(date1);
System.out.println("******************************************");
//默认行为--->指定方式进行格式化解析:调用带参数的构造器
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//格式化:
String format1 = sdf1.format(date);
System.out.println(format1);
//解析:
Date date2 = sdf1.parse("2021-03-08 08:32:04");
System.out.println(date2);
}
}
输出结果:
Mon Mar 08 20:55:53 CST 2021
2021/3/8 下午8:55
Mon Mar 08 20:15:00 CST 2021
******************************************
2021-03-08 08:55:53
Mon Mar 08 08:32:04 CST 2021
使用二:
//将字符串转换成date
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date d1 = df.parse("1971-3-10 10:40:52");
System.out.println(d1.getTime());
//将date转换成字符串
Date d2 = new Date();
//括号内可以写上具体的时间(ms格式)不写表示当下时刻
String str = df.format(d2);
System.out.println(str);
//今年第几周
DateFormat df2 = new SimpleDateFormat("今年第w周");
System.out.println(df2.format(d2));//找月份中的w周/年份中的D天
输出结果:
37420852000
2021-02-23 04:18:03
今年第9周
-
练习:“三天打鱼两天晒网” 给定的某天起开始打鱼,打三天鱼,晒两天网。 到任意一天的时候,是在打鱼还是在晒网?
-
分析:三天+两天=五天一个周期。
Date2-Date1为总天数:总天数%5 = 1,2,3时,是打鱼;
总天数%5 = 4、0(也就是5)是晒网。
总时间可以用getTime算出毫秒数:
(date2.getTime()-date1.getTime())/(1000L360024) +1
其他格式需求可以查下表:
3. Calendar日历类(简单理解即可)
jdk8以前的api:
- 表示日期和日期计算。
- 方式一:是一个抽象类,GregorianCalendar公历子类
(0到11表示12个月)
GregorianCalendar calendar = new GregorianCalendar(2999,10,9,22,10,50);
int year = calendar.get(Calendar.YEAR);//打印年
int month = calendar.get(Calendar.MONTH);//打印月
//DAY_OF_MONTH 和 DATE输出一样
int day = calendar.get(Calendar.DAY_OF_MONTH);
int day2 = calendar.get(Calendar.DATE);//打印几号
int date = calendar.get(Calendar.DAY_OF_WEEK);//打印星期几:1-7:周日到周六
System.out.println(year);
System.out.println(month);
System.out.println(day);
System.out.println(day2);
System.out.println(date);
// 设置日期
GregorianCalendar calendar1 = new GregorianCalendar();
calendar1.set(Calendar.YEAR,2999);
calendar1.set(Calendar.MONTH,Calendar.FEBRUARY);
calendar1.set(Calendar.DATE,3);
calendar1.set(Calendar.HOUR_OF_DAY,10);
calendar1.set(Calendar.MINUTE,20);
calendar1.set(Calendar.SECOND,23);
printCalendar(calendar1);
// 日期计算
GregorianCalendar calendar2 = new GregorianCalendar(2999,10,9,22,10,50);
calendar2.add(Calendar.MONTH,-7);//月份减少7
calendar2.add(Calendar.DATE,7);//日期增加7
printCalendar(calendar2);
方式二:Calendar调用棋静态方法getInstance
//1. 实例化:方法二:调用棋静态方法getInstance
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getClass());
//2.常用方法:
//get();操作:获取常用的一些属性信息:大写常量
int days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
System.out.println(Calendar.DAY_OF_YEAR);
//set();操作:修改:calendar可变的
calendar.set(Calendar.DAY_OF_MONTH,22);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
//add();操作:原有的基础上添加
calendar.add(Calendar.DAY_OF_MONTH,3); //可以加负数,就变成了减
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
//getTime();操作日历类 -->Date
Date date = calendar.getTime();
System.out.println(date);
//setTime();:Date -->日历类
Date date1 = new Date();
calendar.setTime(date1);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
- 出现新的时间日期API:
修改的原因:
- 以前的Calendar是可变的,但是Date这一类应是不可变的。
- Date的日期有一个偏移量1990年开始的,month从0月开始。
- 格式化:格式化只对Date有用,Calendar则不行。
- 他们也不是线程安全的;不能处理润表(地球自转不均匀、变慢)。
jdk8中新的日期时间API
只用到format、temporal两个,少数情况下会用到其他的包。
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* jdk8之后的API
*/
public class dateTest {
/**
* localDate\LocalTime\LocalDateTime使用
* 类似jdk8之前的calendar
*/
@Test
public void test(){
//实例化:获取当前时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now(); //使用频率高些
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);
//实例化:of();设置指定的年月日时分秒是没有偏移量的
LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 24, 13, 23, 43);
System.out.println(localDateTime1);
//getXxx();
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfYear());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getHour());
//withXxx();设置当前的特殊值
LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(22);
System.out.println(localDateTime2);//2021-03-22T09:20:38.886801400(设置了相关的时间)
System.out.println(localDateTime); //2021-03-09T09:20:38.886801400(当前的时间)
//plusXxx();加 minusXxx
LocalDateTime localDateTime3 = localDateTime.plusMonths(3);
System.out.println(localDateTime3);//也是不可变性的,从当前的时间开始变
}
}
4.瞬时:Instant:时间戳
起始点:1970年1月1日00:00:00,ms为单位
Instant使用:
@Test
public void test2(){
//实例化:now()获取的是本初子午线的时间
Instant instant = Instant.now();
System.out.println(instant);//2021-03-09T02:03:06.713429500Z
//添加时间偏移量,获取当地时间
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2021-03-09T10:03:06.713429500+08:00
//获取自1970年1月1日 00:00:00(UTC)开始的毫秒数
long milli = instant.toEpochMilli();
System.out.println(milli);
//ofEpochMilli():通过给定的毫秒数,获取I你Stance实例 -->Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1615255716319L);
System.out.println(instant1);
}
5.SimpleDateFormatter使用
类似于SimpleDateFormat
自定义使用(最常用的):
@Test
public void test(){
//自定义的格式:如ofPattern("yyyy-MM-dd hh:mm:ss E")
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化:
String format = dateTimeFormatter.format(LocalDateTime.now());
System.out.println(format);
//解析
TemporalAccessor accessor = dateTimeFormatter.parse("2021-03-09 10:30:47");
System.out.println(accessor);
}
测试结果:
2021-03-09 10:31:51
{MinuteOfHour=30, MicroOfSecond=0, MilliOfSecond=0, SecondOfMinute=47, NanoOfSecond=0, HourOfAmPm=10},ISO resolved to 2021-03-09
总结:java.util.Date 和 java.sql.Date → Instant
SimpleDateFormat → DateTimeFormatter
Calendar(get、set) → LocalDate、LocalTime、LocalDateTime(with)
三、※java比较器:(涉及到对象比较)(490)
说明:
java中的对象,一般只能进行比较:== 或者 !=。不能使用大小比较,但是在Java开发的场景中,我们需要对多个对象进行比较,言外之意,就需要比较对象的大小。通过Comparable或Comparator接口实现。
Comparable接口(自然排序)使用举例
- 像String、包装类等实现了 Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方式
- 重写compareTo()的规则:进行的是从小到大的排序
如果当前对象this大于形参对象obj,则返回正整数;小于,返回负整数;相等返回0。 - 对于自定义类,需要排序时,我们可以让自定义类实现comparable接口,重写compareTo接口。在compareTo(obj)方法中指明排序规则。(实现接口+重写方法+排序规则)
- 相同的名次,会默认按照二级排序来进行
@Override//指明商品比较大小的规则:这里按照价格从低到高排序,排序有重复会默认一个二级排序
public int compareTo(Object o) {
if(o instanceof Goods){
Goods goods = (Goods) o;
if(this.price > goods.price){
return 1;
}else if(this.price < goods.price){
return -1;
}else{
return 0;
}
// 方法二:return Double.compare(this.price,goods.price);
}
throw new RuntimeException("传入的数据类型不一致!");
}
测试:
@Test
public void test1(){
Goods[] arr = new Goods[5];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("microsoftMouse",43);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
测试结果:
[Goods{name='xiaomiMouse', price=12.0}, Goods{name='lenovoMouse', price=34.0}, Goods{name='dellMouse', price=43.0}, Goods{name='microsoftMouse', price=43.0}, Goods{name='huaweiMouse', price=65.0}]
Comparator接口(定制排序)的使用:
当元素类型没有实现Comparable接口又不方便修改代码,或是不合适当前的操作,这时考虑使用comparator接口:
@Test //(匿名类实现)
public void test(){
String[] strings = {"AA", "BB", "CC", "DD", "FF", "GG"};
Arrays.sort(strings, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
if(o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2);
}
throw new RuntimeException("输入的数据类型不一致!");
}
});
System.out.println(Arrays.toString(strings));
}
对比:Comparable接口永久的,在任何实现类的对象在任何位置都可以比较;Comparator接口:一次性的,临时使用,何时需要就创建。
四.System类
系统类:java.lang包;静态的;私有的
标准输入流、标准输出流、
成员方法:
- native long currentTimeMillis();当前时间毫秒数。
- void exit(int status);退出程序
- void gc():请求系统进行垃圾回收。但是会不会立刻回收看系统情况。
- String getProperty(String key);获取某个属性,对应系统某个属性值
public class SystemTest {
@Test
public void test1(){
String javaVersion = System.getProperty("java.version");
System.out.println("java的version" + javaVersion);
}
}
五.Math类
java.lang.Math:静态的方法,直接调用方法即可,不需要创造类。
- 初等数学里面那些常见的数学方法。
常见的常数:
System.out.println(Math.PI);
System.out.println(Math.E);
0到1之间随机数:[0,1)
System.out.println(Math.random());
....
Random类
生成随机数 UUID
System.out.println(Math.random());
[0,1)
Random rand = new Random();
System.out.println(rand.nextInt());//随机整数
System.out.println(rand.nextDouble());
System.out.println(rand.nextFloat());//随机浮点数float和double
System.out.println(rand.nextBoolean());//随机正误
System.out.println(rand.nextInt(10));//随机生成1~10的整数
BigInteger类(整型)
- Integer类作为int的包装类,能存储的最大整型值为2^31 -1 Long型 2^ 63 -1 。 更大的数字表示不出来,于是有了BigInteger。提供不可变的任意精度的整数。
- BigInteger除了包括那些Math操作,还有模算数、GCD计算、质数测试、素数生成、位操作等。
BigDecimal类(浮点型)
- 支持科学计算、工程计算等。
- 支持不可变的、任意精度的有符号十进制定点数。
六、File类
java.io.File
创建文件:.createNewFile(); 查看读写文件、修改文件、删除文件:.delete();
创建是否成功:Boolean类型的定义一个:
Boolean flag = f.mkdir();
创建目录:.mkdirs();中间缺失,可以自动补起来目录;.mkdir();少一个s,中间有缺失的部分,就不可以建起该目录。
可以代表一个文件或者一个目录。
- file类常见的构造类型:
项目路径:System.out.println(System.getProperty("user.dir"));
常见file的一些操作:
public static void main(String[] args) throws Exception{
File f = new File("d:/b.txt");
System.out.println("file是否存在:"+f.exists());
System.out.println("file是否存在目录:"+f.isDirectory());
System.out.println("file是否存在文件:"+f.isFile());
System.out.println("file最后修改时间:"+new Date(f.lastModified()));
System.out.println("file的大小:"+f.length());
System.out.println("file的文件名:"+f.getName());
System.out.println("file的目录路径:"+f.getPath());
}
递+归应用:打印目录、菜单:
自己调用自己:递归头 + 结束的条件:递归体
一般可以用递归实现的,循环都能实现。
七.java内部类:
- 类中的类
- 一个java类中可以有多个class类,但是只能有一个public class类
- 当外部类和内部类重名,可以用outer.this.成员名 来调用外部类。
- 局部内部类:方法内部定义的类。极其少用。作用域也就是只能在这个方法范围内。
- 非静态内部类:必须继承在一个outer外部对象里面。(现有外面才有里面);内部可以直接访问外部的,外部的不能直接访问内部的;非静态不能定义static的变量、方法、初始化块。
- 静态内部类:有static的类:可以访问外部类的静态成员,不能普通成员。
- 匿名内部类:只需要用一次。没有名字的初始化类,不用讲实例保存到变量中,直接new。(重点)