9 - 1 字符串相关的类:String
一、String的特性
1.String声明为final的,不可被继承
2.String实现了Serializable接口(可序列化接口):
表示字符串是支持序列化的。
String实现了Comparable接口:
String可以比较大小
3.String在内部定义了final char[] value用于存储字符串数据
4.String:代表不可变的字符序列。简称:不可变性。
体现:1、当字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的内存区域赋值
2、当对现有的字符串进行连接操作时,也需要指定内存区域赋值,不能对原有的内存区域赋值
3、当调用String的replace()方法修改指定的字符或字符串时,也需要重新指定内存区域。
5.通过字面量的方式给字符串赋值:此时的字符串值声明在字符串常量池中
6.字符串常量池中是不会存储相同内容的字符串的
二、String对象的创建
面试题(两种赋值方式):
通过字面量给String赋值和通过new实例对象给String赋值的区别
@Test public void test2(){ //通过字面量定义的方式:此时的s1和s2的数据javaee声明在方法区中的字符串常量池中。 String s1 = "javaEE"; String s2 = "javaEE"; //通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。 String s3 = new String("javaEE"); String s4 = new String("javaEE"); System.out.println(s1==s2);//true System.out.println(s3==s4);//false System.out.println("**********************"); Person p1 = new Person("Tom",12); Person p2 = new Person("Tom",12); System.out.println(p1.name.equals(p2.name));//true System.out.println(p1.name == p2.name);//true }
String对象的存储
面试题(对象内存解析):
String s = new String("abc");方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc”
String不同拼接操作的对比:
@Test public void test3(){ String s1 = "javaEE"; String s2 = "hadoop"; String s3 = "javaEEhadoop"; String s4 = "javaEE" + "hadoop"; String s5 = s1 + "hadoop"; String s6 = "javaEE" + s2; String s7 = s1 + s2; System.out.println(s3==s4);//true System.out.println(s3==s5);//false System.out.println(s3==s6);//false System.out.println(s3==s7);//false System.out.println(s5==s6);//false System.out.println(s5==s7);//false }
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
- 只要其中有一个是变量,结果就在堆中 。
- 如果拼接的结果调用intern()方法,返回值就在常量池。
面试题(对String对象的理解):
public class StringTest { String str = "good"; char[] ch = { 't', 'e', 's', 't' }; public void change(String str, char ch[]) { str = "test ok"; ch[0] = 'b'; } public static void main(String[] args) { StringTest ex = new StringTest(); ex.change(ex.str, ex.ch); System.out.print(ex.str + " and ");//good System.out.println(ex.ch);//best } }
本题中,str属性的地址先赋值给了方法的形参,然后形参的地址又由str的地址转变为"test ok"方法区中字符串常量池的地址(字符串的不可变性),所以整个过程并没有修改属性值,只是对形参的地址值进行了修改
三、String常用方法:
package com.atguigu.java; import org.junit.Test; /** * @author 张丁野 * @version v1.0 * @time 2022-05-13-21:42 * @Description * int length():返回字符串的长度: return value.length * char charAt(int index): 返回某索引处的字符return value[index] * boolean isEmpty():判断是否是空字符串:return value.length == 0 * String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写 * String toUpperCase():使用默认语 言环境,将 String 中的所有字符转换为大写 * String trim():返回字符串的副本,忽略前导空白和尾部空白 * boolean equals(Object obj):比较字符串的内容是否相同 * boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大 小写 * String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+” * int compareTo(String anotherString):比较两个字符串的大小 * String substring(int beginIndex):返回一个新的字符串,它是此字符串的从 beginIndex开始截取到最后的一个子字符串。 * String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字 符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。 * * boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束 * boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始 * boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始 * boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true * int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引 * int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 * int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引 * int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 * 注:indexOf和lastIndexOf方法如果未找到都是返回-1 * String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 * String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。 * String replaceAll(String regex, String replacement) : 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 * String replaceFirst(String regex, String replacement) : 使 用 给 定 的 * replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 * boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。 * String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。 * String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。 */ public class StringMethodTest { /** int length():返回字符串的长度: return value.length * char charAt(int index): 返回某索引处的字符return value[index] * boolean isEmpty():判断是否是空字符串:return value.length == 0 * String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写 * String toUpperCase():使用默认语 言环境,将 String 中的所有字符转换为大写 * String trim():返回字符串的副本,忽略前导空白和尾部空白 */ @Test public void test1(){ String s1 = "HelloWorld"; System.out.println(s1.length()); System.out.println(s1.charAt(0)); System.out.println(s1.charAt(9)); // System.out.println(s1.charAt(10)); System.out.println(s1.isEmpty()); String s2 = s1.toLowerCase(); System.out.println(s1);//s1是不可变的,仍然为原来的字符串 System.out.println(s2);//改成小写以后的字符串 String s3 = " he llo world "; String s4 = s3.trim(); System.out.println("----" + s3 +"----"); System.out.println("----" + s4 +"----"); } /** * boolean equals(Object obj):比较字符串的内容是否相同 * boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大 小写 * String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+” * int compareTo(String anotherString):比较两个字符串的大小 * String substring(int beginIndex):返回一个新的字符串,它是此字符串的从 beginIndex开始截取到最后的一个子字符串 * String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字 符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。 */ @Test public void test2(){ String s1 = "HelloWorld"; String s2 = "helloworld"; System.out.println(s1.equals(s2)); System.out.println(s1.equalsIgnoreCase(s2)); String s3 = "abc"; String s4 = s3.concat("def"); System.out.println(s4); String s5 = "abc"; String s6 = new String("ab"); System.out.println(s5.compareTo(s6));//涉及到字符串排序 原数小返回负数 相等返回0 大返回正数 String s7 = "重邮张丁野牛逼"; String s8 = s7.substring(2); System.out.println(s8); s8 = s7.substring(2,5); System.out.println(s8); } /** boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束 * boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始 * boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始 * */ @Test public void test3(){ String str1 = "helloworld"; boolean b1 = str1.endsWith("ld"); System.out.println(b1); boolean b2 = str1.startsWith("He"); System.out.println(b2); boolean b3 = str1.startsWith("ll",2); System.out.println(b3); String str2 = "wor"; System.out.println(str1.contains(str2)); System.out.println(str1.indexOf("lo")); System.out.println(str1.indexOf("lo",5)); String str3 = "hellorworld"; System.out.println(str3.lastIndexOf("or")); System.out.println(str3.lastIndexOf("or",6)); //什么情况下:indexOf(str)和lastIndexOf(str)返回值相同? //情况一:存在唯一的str //情况二:不存在str } @Test public void test4(){ String str1 = "重庆重邮张丁野牛逼"; String str2 = str1.replace('重', '北'); System.out.println(str1); System.out.println(str2); System.out.println("************************"); String str = "123hello34world5java7891mysql456"; //把字符串中的数字替换成',',如果结果中开头和结尾有,的话就去掉 String string = str.replaceAll("\\d+",",").replaceAll("^,|,$",""); System.out.println(string); } }
四、String与基本数据类型转换
1. String 与包装类
/* * 复习: * String 与基本数据类型、包装类之间的转换 * String --> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)(包装类的静态方法) * 基本数据类型、包装类 --> String:调用String重载的valueOf(xxx)(String的静态方法) * */ @Test public void test1(){ String str1 = "123"; int num = Integer.parseInt(str1); String str2 = String.valueOf(num); String str3 = num + ""; System.out.println(str1 == str3); }
2.String 与字符数组(char[])
/* * String 与 char[] 之间的转换 * * String --> char[]:调用String的toCharArray() * char[] --> String:调用String的构造器 * */ @Test public void test2(){ String str1="abc123"; //题目: a21cb3 char[] charArray = str1.toCharArray(); for (int i = 0; i < charArray.length; i++) { System.out.println(charArray[i]); } char[] arr = new char[]{'h','e','l','l','o'}; String str2 = new String(arr); System.out.println(str2); }
3. String与字节数组(byte[])
/* * String 与 byte[]之间的转换 * * 编码:字符串 --> 字节(看得懂 --> 看不懂的二进制数据) * 解码:编码的你过程:字节 ---> 字符串 * */ @Test public void test3() throws UnsupportedEncodingException { String str1 = "abc123中国";//使用默认的字符集进行转换 byte[] bytes = str1.getBytes();//编码 System.out.println(Arrays.toString(bytes)); byte[] gbks = str1.getBytes("gbk");//使用gbk字符集编码 System.out.println(Arrays.toString(gbks)); System.out.println("***********************"); String str2 = new String(bytes);//使用默认的字符集进行解码 System.out.println(str2); String str3 = new String(gbks); System.out.println(gbks);//出现乱码。原因:编码集和解码集不一致! String str4 = new String(gbks,"gbk"); System.out.println(str4); //说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致 }
五、String常见的算法题目
//1. 模拟一个trim方法,去除字符串两端的空格。 public String overrideTrim(String str){ char[] charArray = str.toCharArray(); int flag1 = 0; int flag2 = 0; for (int i = 0; i < charArray.length; i++) { if (charArray[i] != ' '){ flag1 = i; break; }else{ continue; } } for (int i = charArray.length - 1; i >= 0 ; i--) { if (charArray[i] != ' '){ flag2 = i; break; }else{ continue; } } return str.substring(flag1,flag2 + 1); }
//2. 将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为”abfedcg” public String reverseArray(String str,int beginIndex, int endIndex){ char[] charArray = str.toCharArray(); //reverse exist array for (int i = beginIndex,j = endIndex; i <= beginIndex + ((endIndex - beginIndex - 1) / 2); i++,j--) { char temp; temp = charArray[i]; charArray[i] = charArray[j]; charArray[j] = temp; } String str1 = new String(charArray); return str1; }
//3. 获取一个字符串在另一个字符串中出现的次数。 public int getEmergeTimes(String newString,String inString){ int count = 0; int i = 0; int j = 0; //判断该字符串是否以子字符串开头,若是,则改变indexOf方法的索引开头 if (inString.startsWith(newString)){ j = 1; count++; } while(true){ i = inString.indexOf(newString,j); if (i != j){ count++; j = i + 1; }else{ break; } } return count; }
六、字符串相关的类:StringBuffer
源码分析:
String str = new String();//new char[0]
String str1 = new String("abc")//new char[]{'a','b','c'}
StringBuffer sb1 = new StringBuffer();//new char[16]
sb1.append('a');//value[0] = 'a';
sb2.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length + 16];
//问题1:System.out.println(sb2.length())//3
//问题2:扩容问题:
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的值复制到扩容数组中
开发中建议使用StringBuffer(int capacity)或StringBuider(int capacity)
常用方法:
package com.atguigu.java; import org.junit.Test; /** * @author 张丁野 * @version v1.0 * @time 2022-05-22-14:08 * @Description * 关于StringBuffer和StringBuilder的使用 * */ public class StringBufferBuilderTest { //StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接 //StringBuffer delete(int start,int end):删除指定位置的内容 //StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str //StringBuffer insert(int offset, xxx):在指定位置插入xxx //StringBuffer reverse() :把当前字符序列逆转 //public int indexOf(String str) //public String substring(int start,int end) //public int length() //public char charAt(int n ) //public void setCharAt(int n ,char ch) /*总结: 增:apend(xxx) 删:delete(int start,char ch) 改:setCharAt(int n) 查:charAt(int n) 插:insert(int offset,xxx) 长度:length() 遍历:for + charAt(int n) */ @Test public void test2(){ StringBuffer s1 = new StringBuffer("abc"); s1.append(1); s1.append('1'); System.out.println(s1); // s1.delete(2,4); // System.out.println(s1); s1.replace(2,4,"hello"); System.out.println(s1); s1.insert(2,false); System.out.println(s1); s1.reverse(); System.out.println(s1); } /* * String、StringBuffer、StringBuilder的异同: * * */ @Test public void test1(){ // StringBuffer sb1 = new StringBuffer(); // sb1.setCharAt(0,'m'); // System.out.println(sb1); StringBuffer sb2 = new StringBuffer(); System.out.println(sb2.length()); } }
七、 字符串相关的类:StringBuilder
八、面试题(三个类的比较)
String、StringBuffer、StringBuilder的异同:
String:不可变的字符序列:底层使用char[]存储
StringBuffer:可变的字符序列:线程安全的,效率偏低:
StringBuilder:可变的字符序列:jdk5.0新增,线程不安全的,效率高:
运行效率:StringBuilder > StringBuffer >String
9 - 2 JDK8之前日期时间API
一 、java.lang.System类
System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
计算世界时间的主要标准有:
UTC(Coordinated Universal Time)
GMT(Greenwich Mean Time)
CST(Central Standard Time
二 、java.util.Date类
public class DateTimeTest {
/*
* java.util.Date类
* ----java.sql.Date类
*
* 1.两个构造器的使用
*
* 2.两个方法的使用
* >toString():显示当前的年、月、日、时、分、秒
* >getTime():获取当前Date对象对应的毫秒数。(时间戳)
*
* 3.java.sql.Date对应着数据库中的日期类型的变量
* >如何实例化
* >如何将java.util.Date转化为java.sql.Date的对象
* */
@Test
public void test2(){
//构造器一:Date():创建一个对应当前时间的
Date date1 = new Date();
System.out.println(date1.toString());//Tue May 24 22:39:13 CST 2022
System.out.println(date1.getTime());//1653403153747
//构造器二:创建指定毫秒数的Date对象
Date date2 = new Date(1653403153747L);
System.out.println(date2.toString());
java.sql.Date date3 = new java.sql.Date(1653403153747L);
System.out.println(date3);//2022-05-24
//如何将java.util.Date转化为java.sql.Date的对象
//情况一:
Date date4 = new java.sql.Date(1653403153747L);
java.sql.Date date5 = (java.sql.Date)date4;
//情况二:
Date data6 = new Date();
java.sql.Date date7 = new java.sql.Date(data6.getTime());
}
//1.System类中的currentTimeMillis()
@Test
public void test1(){
long time = System.currentTimeMillis();
//返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
//成为时间戳
System.out.println(time);
}
}
三 、java.text.SimpleDateFormat类
SimpleDateFormat的使用:SimpleDateFormat对日期和Date类的格式化和解析
*
* 1.两个操作:
* 1.1格式化:日期 --> 字符串
* 1.2解析:格式化的逆过程,字符串 --> 日期
*
* 2.SimpleDateFormat的实例化
/* * SimpleDateFormat的使用:SimpleDateFormat对日期和Date类的格式化和解析 * * 1.两个操作: * 1.1格式化:日期 --> 字符串 * 1.2解析:格式化的逆过程,字符串 --> 日期 * * 2.SimpleDateFormat的实例化 * */ @Test public void test1() throws ParseException { //实例化SimpleDateFormat SimpleDateFormat sdf = new SimpleDateFormat(); //格式化:日期 --> 字符串 Date date = new Date(); System.out.println(date); String format = sdf.format(date); System.out.println(format); //解析:格式化的逆过程,字符串 --> 日期 String str = "22-2-25 下午4:13"; try { Date date1 = sdf.parse(str); System.out.println(date1); } catch (ParseException e) { e.printStackTrace(); } System.out.println("************按照指定的方式进行过格式化和解析,调用带参的构造器***********"); // SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa"); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String format1 = sdf1.format(date);//2022-05-25 04:22:30 System.out.println(format1); //解析:要求字符串符合构造器形参的格式 Date date2 = sdf1.parse("2022-05-25 04:22:30"); System.out.println("2022-05-25 04:22:30"); } /* * 练习一:字符串"2020-09-08"转化为java.sql.Date * */ @Test public void test2() throws ParseException { SimpleDateFormat std1 = new SimpleDateFormat("yyyy-MM-dd"); String str = "2020-09-08"; Date date = std1.parse(str); java.sql.Date date1 = new java.sql.Date(date.getTime()); System.out.println(date1); }
四 、java.util.Calendar(日历)类
/*
* Calendar日历类(抽象类)的使用
* */
@Test
public void testCalendar(){
//1.实例化
//方式一:创建其子类(GregorianCalendar)的对象
//方式二:调用其静态方法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.get(Calendar.DAY_OF_YEAR));
//set()
calendar.set(Calendar.DAY_OF_MONTH,22);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);//set()是String.replace()的结果,只是days的值发生改变,String并未改变
//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);
}
9 - 3 JDK 8中新日期时间API
思考:为什么要引入新的API?
新时间API介绍:
一、 LocalDate、LocalTime、LocalDateTime
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例 是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。 它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区 相关的信息。
LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。 LocalTime表示一个时间,而不是日期。
LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示 法,也就是公历。
说明:
1.LocalDateTime相较于LocalDate,LocalTime,使用频率更高
2.类似于Calendar
/* * LocalDate、LocalTime、LocalDateTime * * */ @Test public void test1(){ //now():获取当前的日期,时间,时期+时间 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(2022,5,26,15,10,56); System.out.println(localDateTime1); //getXxx() System.out.println(localDateTime.getDayOfMonth()); System.out.println(localDateTime.getYear()); System.out.println(localDateTime.getDayOfYear()); System.out.println(localDateTime.getMinute()); //体现不可变性 //withXxx():设置相关的属性 LocalDate localDate1 = localDate.withDayOfMonth(11); System.out.println(localDate); System.out.println(localDate1); // LocalDateTime localDateTime2 = localDateTime.plusMonths(3); System.out.println(localDateTime); System.out.println(localDateTime2); }
二、瞬时:instant
/* * Instant的使用 * * */ @Test public void test2(){ //now():获取本初子午线对应的标准时间 Instant instant = Instant.now(); System.out.println(instant); //添加时间的偏移量 OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8)); System.out.println(offsetDateTime);//2022-05-26T20:03:57.756+08:00 //toEpochMilli():获取从起始时间1970开始的毫秒数 long milli = instant.toEpochMilli(); System.out.println(milli);//1653566854690L //ofEpochMilli():通过给定的毫秒数,获取Instant实例 Instant instant1 = Instant.ofEpochMilli(1653566854690L); System.out.println(instant1); }
三 、格式化或解析日期或时间
/* *DataTimeFormatter“格式化或解析日期、时间 * 类似于SimpleDateFormat * * */ @Test public void test3(){ //方式一:预定义的标准格式 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; //格式化 LocalDateTime localDateTime = LocalDateTime.now(); String str1 = formatter.format(localDateTime); System.out.println(localDateTime); System.out.println(str1);//2022-05-26T20:23:52.693 //解析:字符串 --> 日期 TemporalAccessor parse = formatter.parse("2022-05-26T20:23:52.693"); System.out.println(parse); System.out.println("******************"); //方式二: // 本地化相关的格式。如:oflocalLizedDateTime() //FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT; DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); //格式化 String str2 = formatter1.format(localDateTime); System.out.println(str2); // 本地化相关的格式。如:oflocalLizedDate() //FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT; DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); String str3 = formatter2.format(LocalDate.now()); System.out.println(str3); TemporalAccessor parse1 = formatter2.parse("2022-5-30"); System.out.println(parse1); //方式三:自定义的格式。 DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd-hh:mm:ss"); String str4 = formatter3.format(LocalDateTime.now()); System.out.println(str4); //解析: TemporalAccessor parse2 = formatter3.parse("2022-05-30-06:30:25"); System.out.println(parse2); }
四、其他API
9 - 4 Java比较器
一、概念引进:
一、说明:java中的对象正常情况下,只能进行比较 == 或 != 。不能使用 > 或 < 的。
但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。
如何实现?使用两个接口中的任何一个:Comparable 或 Comparator
二、java.lang.Comparable
Comparable接口的使用举例:
1.像String、包装类等实现了Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方法
2.像String、包装类重写compareTo()方法后,进行了从小到大的排列
3.重写compareTo()的规则:
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即 通过 compareTo(Object obj) 方法的返回值来比较大小。
如果当前对象this大于形参对象obj,则返回正整数;
如果当前对象this小于形参对象obj,则返回负整数;
如果当前对象this等于形参对象obj,则返回零。
4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写CompareTo()方法,在CompareTo()方法中指明如何排序
/* * Comparable接口的使用举例 * */ @Test public void test1(){ String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); } @Test public void test2(){ 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",65); Arrays.sort(arr); System.out.println(Arrays.toString(arr)); }
三、java.lang.Comparator
Comparable接口的使用举例:定制排序
1.背景: 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码, 或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那 么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排 序的比较。
2. 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返 回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示 o1小于o2。
@Test public void test4(){ 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",65); Arrays.sort(arr, new Comparator() { //指明商品比较大小的方式:严格按照产品名称从低到高排序,再按照价格从高到低排序 @Override public int compare(Object o1, Object o2) { if (o1 instanceof Goods && o2 instanceof Goods){ Goods g1 = (Goods)o1; Goods g2 = (Goods)o2; if (g1.getName().equals(g2.getName())){ return -Double.compare(g1.getPrice(),g2.getPrice()); }else{ return g1.getName().compareTo(g2.toString()); } } throw new RuntimeException("输入格式错误"); } }); }
*.区别:
Comparable接口的方式一旦指定,保证Comparable接口实现类的对象在任何情况下都能比较。
Comparator接口属于临时性的比较
9 - 5 System类
9 - 6 Math类
9 - 7 BigInteger与BigDecimal
一、BigInteger
二、BigDecimal
di