String类

java.lang.String类的使用

1.概述

String:字符串,使用一对“”引起了表示 1.String声明为final的,不可被继承
2.String实现了Serializable接口:表示字符串是支持序列化的
实现了Comparable接口:表示String可以比较大小
3.String内部定义了final byte[] value用于存储字符串数据
4.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串声明在字符串常量池中
5.字符串常量池中是不会存储相同内容(使用String类的equals()比较,返回true)的字符串的


2.String的不可变性
2.1说明

1.当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值
2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
3.当调用String的replace()方法修改指定字符串或字符时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值


2.2代码举例

  1. java.lang.String s1 = "abc";//字面量的定义方式
  2. java.lang.String s2 = "abc";
  3. // s1 = "hello";
  4. System.out.println(s1 == s2);//比较s1和s2的地址值
  5. System.out.println(s1);
  6. System.out.println(s2);
  7. System.out.println("**********************************");
  8. String s3 = "abc";
  9. s3 += "def";
  10. System.out.println(s3);//abcdef
  11. System.out.println(s2);
  12. System.out.println("**********************************");
  13. String s4 = "abc";
  14. String s5 = s4.replace('a', 'm');
  15. System.out.println(s4);//abc
  16. System.out.println(s5);//mbc

2.3图示
image.png

3.String实例化的不同方式
3.1方式说明

方式一:通过字面量定义的方式
方式二:通过new + 构造器的方式

3.2代码举例

  1. //通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中
  2. String s1 = "javaEE";
  3. String s2 = "javaEE";
  4. //通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值
  5. String s3 = new String("javaEE");
  6. String s4 = new String("javaEE");
  7. System.out.println(s1 == s2);//true
  8. System.out.println(s1 == s3);//false
  9. System.out.println(s1 == s4);//false
  10. System.out.println(s3 == s4);//false


3.3面试题

  1. String s = new String("abc");方式创建对象,在内存中创建了几个对象?<br /> 两个:一个是堆空间中new结构,另一个是byte[]对应的常量池中的数据:"abc"


3.4图示
image.png

4.字符串拼接方式赋值的对比
4.1说明

  • 1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量
  • 2.只要有一个是变量,结果就在堆中
  • 3.如果拼接的结果调用intern()方法,返回值就在常量池中

4.2代码举例

  1. String s1 = "javaEE";
  2. String s2 = "Hadoop";
  3. String s3 = "javaEEHadoop";
  4. String s4 = "javaEE" + "Hadoop";
  5. String s5 = s1 + "Hadoop";
  6. String s6 = "javaEE" + s2;
  7. String s7 = s1 + s2;
  8. System.out.println(s3 == s4);//true
  9. System.out.println(s3 == s5);//false
  10. System.out.println(s3 == s6);//false
  11. System.out.println(s3 == s7);//false
  12. System.out.println(s5 == s6);//false
  13. System.out.println(s5 == s6);//false
  14. System.out.println(s6 == s7);//false
  15. String s8 = s5.intern();//返回值得到的s8是使用的常量池中已经存在的“javaEEHadoop”
  16. System.out.println(s3 == s8);//true
  17. String s1 = "javaEEhadoop";
  18. String s2 = "javaEE";
  19. String s3 = s2 + "hadoop";
  20. System.out.println(s1 == s3);//false
  21. final String s4 = "javaEE";//s4:常量
  22. String s5 = s4 + "hadoop";
  23. System.out.println(s1 == s5);//true


5.常用方法:

  • 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 endWith(String suffix):测试此字符串是否以指定的后缀结束
  • boolean startWith(String prefix):测试此字符串是否以指定的前缀开始
  • boolean startWith(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个,如果超过了剩下全部都放到最后一个元素中


6.String与其他结构的转换
6.1与基本数据类型、包装类的转换

  • String —> 基本数据类型、包装类:调用包装类的静态方法: parseInt(str)
  • 基本数据类型、包装类 —> String:调用String重载的ValueOf(xxx)
  1. public void test1(){
  2. String str1 = "123";
  3. int num = Integer.parseInt(str1);
  4. // String str2 = String.valueOf(num);//"123"
  5. String str3 = num + "";
  6. System.out.println(str1 == str3);
  7. }

6.2与字符数组之间的转换

  • String —> char[]:调用String的toCharArray()
  • char[] —> String:调用String构造器
  1. public void test2(){
  2. String str1 = "abc123";
  3. char[] charArray = str1.toCharArray();
  4. for (int i = 0; i < charArray.length; i++) {
  5. System.out.println(charArray[i]);
  6. }
  7. char[] arr = new char[]{'h','e','l','l','o'};
  8. String str2 = new String(arr);
  9. System.out.println(str2);
  10. }

6.3与字节数组之间的转换

  • 编码:String —> byte[]:调用String的getBytes()
  • 解码:byte[] —> String:调用String的构造器

  • 编码:字符串 —> 字节(看得懂 —> 看不懂的二进制数据)

  • 解码:编码的逆过程,字节 —> 字符串

(看不懂的二进制数据 —> 看得懂)

  • 说明:解码时,要求解码使用的字符集必须与解码时使用的字符集一致,否则会出现乱码
  1. public void test3() throws UnsupportedEncodingException {
  2. String str1 = "abc123中国";
  3. byte[] bytes = str1.getBytes();//使用默认的字符集,进行编码
  4. System.out.println(Arrays.toString(bytes));
  5. byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码
  6. System.out.println(Arrays.toString(gbks));
  7. System.out.println("***************************");
  8. String str2 = new String(bytes);//使用默认的字符集,进行解码
  9. System.out.println(str2);
  10. String str3 = new String(gbks);
  11. System.out.println(str3);//出现乱码。原因:编码集和解码集不一致
  12. String str4 = new String(gbks, "gbk");
  13. System.out.println(str4);//没有出现乱码。原因:编码集和解码集一致
  14. }


6.4与StringBuffer、StringBuilder之间的转换

String —> StringBuffer、StringBuilder:调用StringBuffer、StringBuilder构造器
StringBuffer、StringBuilder —> String:① 调用String构造器;② StringBuffer、StringBuilder的toString()


7.JVM中字符串常量池存放位置说明:

JDK1.6(JDK6.0,Java6.0):字符串常量池存储在方法区(永久区)
JDK1.7:字符串常量池存储在堆空间
JDK1.8:字符串常量池存储在方法区(元空间)


8.常见算法题目考查:

  1. 模拟一个trim方法,去除字符串两端的空格
  2. 将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为“abfedcg”
  3. 获取一个字符串在另一个字符串中出现的次数。比如:获取“ab”在“abkkcadkabkebfkabkskab”中出现的次数
  4. 获取两个字符串中最大相同子串。
    比如:str1 = “abcwerthelloyuiodef”,str2 = “cvhellobnm”
    提示:将短的那个串进行长度依次递减的子串与较长的串比较
  5. 对字符串中字符进行自然排序
    提示:1.字符串变成字符数组
    2.对数组排序,择,冒泡,Arrays.sort();
    3.将排序后的数组变成字符串

StringBuffer、StringBuilder


1.String、StringBuffer、StringBuilder三者的对比

  • String:不可变的字符序列;底层结构使用char[]存储
  • StringBuffer:可变的字符序列;线程安全的,效率低;底层结构使用char[]存储
  • StringBuilder:可变的字符序列;JDK5.0新增的,线程不安全,效率高;底层结构使用char[]存储
  1. StringBuffer与StringBuilder的内存解析
    以StringBuffer为例: ```java //char[] value = new char[0]; String str = new String; //char[] value = new char[]{‘a’,’b’,’c’}; String str1 = new String(“abc”);

//char[] value = new char[16];底层创建了一个长度是16的数组 StringBuffer sb1 = new StringBuffer(); System.out.println(sb1.length());//0 sb1.append(‘a’);//value[0] = ‘a’; sb1.append(‘b’);//value[1] = ‘b’;

//char[] value = new char[“abc”.length() + 16]; StringBuffer sb2 = new StringBuffer(“abc”);

  1. > - 问题一:System.out.println(sb2.length());//3
  2. > - 问题二:扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组
  3. >
  4. 默认情况下,扩容为原来容量的2 + 2,同时将原有数组中的元素复制到新的数组中
  5. >
  6. > - 指导意义:开发中建议大家使用:StringBuffer(int capacity)或StringBuilder(int capacity)
  7. <br />**3.对比StringStringBufferStringBuilder三者的执行效率**
  8. > 从高到低排列:StringBuilder > StringBuffer > String
  9. 4. **StringBufferStringBuilder中常用方法**
  10. > - 增:append(xxx)
  11. > - 删:delete(int start,int end)
  12. > - 改:setCharAt(int n,char ch) / replace(int start,int end,String str)
  13. > - 查:charAt(int n)
  14. > - 插:insert(int offset,xxx)
  15. > - 长度:length()
  16. > - 遍历:for + charAt() / toString
  17. ---
  18. <a name="iiCS6"></a>
  19. # JDK8之前日期时间API
  20. <br />**1.获取系统当前时间:System类中的currentTimeMillis()**
  21. ```java
  22. long time = System.currentTimeMillis();
  23. //返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
  24. //称为时间戳
  25. System.out.println(time);


2.java.util.Date类与java.sql.Date类

java.util.Date类
|—-java.sql.Date类

1.两个构造器的使用
> 构造器一:Date():创建一个对应当前时间的Date对象
> 构造器二:创建指定毫秒数的Date对象

2.两个方法的使用
> toString():显示当前的年、月、日、时、分、秒
> getTime():获取当前Date对象对应的毫秒数(时间戳)

3.java.sql.Date:对应着数据库中的日期类型的变量
> 如何实例化
> 如何将java.util.Date对象转换为java.sql.Date对象

  1. public void test2(){
  2. //构造器一:Date():创建一个对应当前时间的Date对象
  3. Date date1 = new Date();
  4. System.out.println(date1.toString());//Mon Aug 16 18:02:33 CST 2021
  5. System.out.println(date1.getTime());//1629108181268
  6. //构造器二:创建指定毫秒数的Date对象
  7. Date date2 = new Date(1629108181268L);
  8. System.out.println(date2.toString());
  9. //创建java.sql.Date对象
  10. java.sql.Date date3 = new java.sql.Date(2156461151515L);
  11. System.out.println(date3);//2146-05-24
  12. //如何将java.util.Date对象转换为java.sql.Date对象
  13. //情况一:
  14. // Date date4 = new java.sql.Date(6515615616161L);
  15. // java.sql.Date date5 = (java.sql.Date) date4;
  16. //情况二:
  17. Date date6 = new Date();
  18. java.sql.Date date7 = new java.sql.Date(date6.getTime());
  19. System.out.println(date7);
  20. }

3.java.text.SimpleDateFormat类

SimpleDateFormat对日期Date类的格式化和解析

1.两个操作:

1.1格式化:日期 —> 字符串
1.2解析:格式化的逆过程:字符串 —> 日期


2.SimpleDateFormat的实例化:new + 构造器

小练习:

  1. //按照指定的方式格式化和解析:调用带参的构造器
  2. SimpleDateFormat sdf1 = new SimpleDateFormat("k:mm a,z");
  3. //格式化
  4. String format1 = sdf1.format(date);
  5. System.out.println(format1);//11:20 上午,CST
  6. //解析:要求字符串必须是符合:SimpleDateFormat识别的格式(通过构造器参数体现),
  7. //否则,抛异常
  8. Date date2 = sdf1.parse("11:20 上午,CST");
  9. System.out.println(date2);
  1. /*
  2. 练习一:字符串“2020-09-08”转换为java.sql.Date
  3. 练习二:“三天打鱼两天晒网” 1990-01-01 xxxx-xx-xx 打渔?晒网?
  4. 举例:2020-09-08 ? 总天数
  5. 总天数 % 5 == 1,2,3:打渔
  6. 总天数 % 5 == 4,0 :晒网
  7. 总天数的计算?
  8. 方式一:(date2.getTime() - date1.getTime())/(1000 60 60 * 24) + 1
  9. 方式二:1990-01-01 --> 2019-12-31 --> 2020-01-01 --> 2020-09-08
  10. */
  11. @Test
  12. public void testExer() throws ParseException {
  13. String birth = "2020-09-08";
  14. SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
  15. Date date = sdf1.parse(birth);
  16. java.sql.Date birthDate = new java.sql.Date(date.getTime());
  17. System.out.println(birthDate);
  18. }


4.Calendar类:日历类、抽象类

  1. //1.实例化
  2. //方式一:创建其子类(GregorianCalendar)的对象
  3. //方式二:调用其静态方法getInstance()
  4. Calendar calendar = Calendar.getInstance();
  5. // System.out.println(calendar.getClass());
  6. //2.常用方法
  7. //get()
  8. int days = calendar.get(Calendar.DAY_OF_MONTH);
  9. System.out.println(days);
  10. System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
  11. //set()
  12. //calendar可变性
  13. calendar.set(Calendar.DAY_OF_MONTH, 22);
  14. days = calendar.get(Calendar.DAY_OF_MONTH);
  15. System.out.println(days);
  16. //add()
  17. calendar.add(Calendar.DAY_OF_MONTH, -3);
  18. days = calendar.get(Calendar.DAY_OF_MONTH);
  19. System.out.println(days);
  20. //getTime():日历类 --> Date
  21. Date date = calendar.getTime();
  22. System.out.println(date);
  23. //setTime():Date --> 日历类
  24. Date date1 = new Date();
  25. calendar.setTime(date1);
  26. days = calendar.get(Calendar.DAY_OF_MONTH);
  27. System.out.println(days);

JDK8中新日期时间API


1.日期时间API的迭代:

第一代:JDK 1.0 Date类
第二代:JDK 1.1 Calendar,一定程度上替换Date
第三代:JDK 1.8 提出了新的一套API


2.前两代存在的问题举例:
image.png

3.Java 8中新的日期时间API涉及到的包
image.png

4.本地日期、本地时间、本地日期时间的使用:LocalDate / LocalTime / LocalDateTime
4.1说明:
image.png

4.2常用方法:
image.png

5.时间点:Instant
5.1说明:

① 时间线上的一个瞬时点。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC开始的秒数)
② 类似于java.util.Date类


5.2常用方法:
image.png

6.日期时间格式化类:DateTimeFormatter
6.1说明:

① 格式化或解析日期、时间
② 类似于SimpleDateFormat

6.2常用方法:
① 实例化方式:

预定义的标准格式。如: ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)


② 常用方法:
image.png
特别的:自定义的格式。如ofPattern(“yyyy-MM-dd hh:mm:ss”)

  1. //自定义的格式:
  2. DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
  3. //格式化
  4. String s = pattern.format(LocalDateTime.now());
  5. System.out.println(s);
  6. //解析
  7. TemporalAccessor parse1 = pattern.parse("2021-08-17 05:27:09");
  8. System.out.println(parse1);


7.其他API的使用(不讲)
7.1带时区的日期时间:ZonedDateTime / ZoneId


Java比较器


1.Java比较器的使用背景:

Java中的对象,正常情况下,只能进行比较:== 或 != 。不能使用 > 或 < 的,但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。
如何实现?使用两个接口中的任何一个:Comparable或Comparator


2.自然排序:使用Comparable接口
2.1说明:

1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式
2.像String、包装类重写compareTo(obj)方法以后,进行了从小到大的排列
3.重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零
4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法,在compareTo(obj)方法中指明如何排序


2.2自定义类代码举例:

  1. public class Goods implements Comparable{
  2. private String name;
  3. private double price;
  4. //指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从低到高排序
  5. @Override
  6. public int compareTo(Object o) {
  7. System.out.println("***************************");
  8. if (o instanceof Goods){
  9. Goods goods = (Goods) o;
  10. //方式一:
  11. if (this.price > goods.price){
  12. return 1;
  13. }else if (this.price > goods.price){
  14. return -1;
  15. }else {
  16. // return 0;
  17. return -this.name.compareTo(goods.name);
  18. }
  19. //方式二:
  20. // return Double.compare(this.price, goods.price);
  21. }
  22. throw new RuntimeException("传入的数据类型不一致!");
  23. }
  24. //getter、setter、tiString()、构造器省略
  25. }


3.定制排序:使用Comparator接口
3.1说明:

  • 1.背景:

当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用Comparator的对象来排序

2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小:

  • 如果方法返回正整数,则表示o1大于o2;
  • 如果返回0,表示相等;
  • 返回负整数,表示o1小于o2


3.2代码举例:

  1. Comparator com = new Comparator() {
  2. //指明商品比较大小的方式:按照产品名称从低到高排序,再按照价格从高到低排序
  3. @Override
  4. public int compare(Object o1, Object o2) {
  5. if (o1 instanceof Goods && o2 instanceof Goods){
  6. Goods g1 = (Goods) o1;
  7. Goods g2 = (Goods) o2;
  8. if (g1.getName().equals(g2.getName())){
  9. return -Double.compare(g1.getPrice(), g2.getPrice());
  10. }else {
  11. return g1.getName().compareTo(g2.getName());
  12. }
  13. }
  14. throw new RuntimeException("输入数据类型不一致");
  15. }
  16. }


使用:
Arrays.sort.(goods,com);
Colletions.sort(coll,com);
new TreeSet(com);

4.两种排序方式对比:

1.Comparable接口的方式一旦指定,保证Comparable接口实现类的对象在任何位置都可以比较大小
2.Comparator接口属于临时性的比较


其他类


1.System类

① System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
② 由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便的进行调用。


方法:
image.png

2.Math类

java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型。


3.BigInteger类、BigDecimal类
说明:

① java.math包的BigInteger可以表示不可变的任意精度的整数
② 要求数字精度比较高,故用到java.math.BigDecimal类


代码举例:
image.png