9常用类
9.1字符串相关的类:String
9.1.1String类
String:字符串,使用一对""引起来表示。
1.String声明为final的,不可被继承
2.String实现了Serializable接口:表示字符串是支持序列化的
- 实现了ComparabLe接口:表示String可以比较大小
3.String内部定义了final char[ ] value用于存储字符串数据
4.String:代表不可变的字符序列。简称:不可变性。
-
体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
-
体现:2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
-
体现:3.当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,
-
@Test public void test1(){ //不可变性 //体现1 String s1="abc";//字面量。String是一个类。却可以像基本数据类型那样来造对象,而不用new String s2="abc"; System.out.println(s1 == s2);//比较s1和s2的地址值:true s1="hello"; System.out.println(s1); System.out.println(s2); //体现2 System.out.println("*****************"); String s3 = "abc" ; s3 += "def" ; System.out.println(s3);// abcdef System.out.println(s2); //体现3 System.out.println("*****************"); String s4 = "abc" ; String s5 = s4.replace( 'a', 'm'); System.out.println(s4); System.out.println(s5); }
内存结构解析
5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6.字符串常量池中是 不会存储相同内容的字符串的。
9.1.2String的实例化方式
-
方式一:通过字面量定义的方式
- 此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
-
方式二:通过new +构造器的方式
- 通过new +构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值
-
@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(s1 == s3);//false System.out.println(s1 == s4);//false System.out.println(s3 == s4);//false Person p1 = new Person("aa",1); Person p2 = new Person("aa",1); System.out.println(p1.name.equals(p2.name));//true System.out.println(p1.name == p2.name);//true } class Person{ public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; } }
-
内存解析
-
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
- 只要其中有一个是变量,结果就在堆中
- 如果拼接的结果(无论有没有变量)调用intern()方法,返回值就在常量池中
9.1.3面试题
1.String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc”
若方法区中本来就有"abc",那么以上代码就只创建了一个对象,堆空间中new结构
2.
package com.atguigu.exr;
/**
* @author zhy
* @create 2022-11-26 8:42
*/
public class StringTest {
String str=new String("good");
char[] ch={'t','e','s','t'};
public void change(String str,char ch[]){
str="test ok";
ch[0]='b';
}
public void change2(StringTest st){
st.str="test and";
st.ch[0]='b';
}
public static void main(String[] args) {
StringTest st = new StringTest();
StringTest st2 = new StringTest();
//情况1
st.change(st.str,st.ch);
System.out.print(st.str+" ");
System.out.println(st.ch);
//good best
//情况2
st2.change2(st2);
System.out.print(st2.str+" ");
System.out.println(st2.ch);
//test and best
}
}
情况1内存解析:
情况2内存解析:
9.1.4 String常用方法
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 equalslgnoreCase(String anotherString):与equals方法类似,忽略大小写
String concat(String str):将指定字符串连接到此字符串的结尾。等价于用‘+’
int compare To(String anotherString):比较两个字符串的大小,逐个字符比较,不相等则相减
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginlndex开始截取到最后的一个子字符串。
String substring(int beginIndex,int endlndex):返回一个新字符串,它是此字符串从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个,如果超过了,剩下的全部都放到最后一个元素中。
StringBuffer、StringBuilder
9.1.5 String与char[]的转化
String→char[]:用String的对象调用toCharArray()方法
char[]→String:用String类的构造器
9.1.6 String与byte[]的转化
编码:字符串–>字节(看得懂—>看不懂的二进制数据)
解码:编码的逆过程,字节–>字符串(看不懂的二进制数据—〉看得懂)
编码:String→byte[]:用String的对象调用getBytes()方法
- getBytes()使用默认字符集(当前编译环境的字符集)进行转化
- getBytes(“gbk”)使用gbk字符集进行转化
String str1="abc123中国";
byte[] bytes=str1.getBytes();//使用默认字符集,进行编码
System.out.println(Arrays.toString(bytes));
//[97,98,99,49,50,51,-28,-72,-83,-27,-101,-67]
byte[] gbks=str1.getBytes("gbk");//使用gbk字符集,进行编码
System.out.println(Arrays.toString(bytes));
//[97,98,99,49,50,51,-28,-72,-83,-27,-101,-67]
String str2=new String(bytes);//使用默认字符集,对bytes进行解码
System.out.println(str2);
//abc123中国
String str3=new String(gbks);//使用默认字符集,对gbks进行解码
System.out.println(str3);
//abc123乱码
String str4=new String(gbks,"gbk");//使用默认字符集,对gbks进行解码
System.out.println(str4);
//abc123中国
9.1.7String相关常见算法题目
1.模拟一个trim方法,去除字符串两端的空格。
2.将一个字符串进行反转。将字符串中指定部分进行反转。比如abcdefg”反转为"”abfedcg"
3.获取一个字符串在另一个字符串中出现的次数。比如:获取"ab”在“abkkcadkabkebfkabkskab”中出现的次数
4.获取两个字符串中最大相同子串。比如:str1 = “abcwerthelloyuiodef”;str2 = "cvhellobnm"提示:将短的那个串进行长度依次递减的子串与较长的串比较。
5.对字符串中字符进行自然顺序排序。提示:1)字符串变成字符数组。2)对数组排序,选择,冒泡,Arrays.sort();3)将排序后的数组变成字符串。
9.2字符串相关的类:StringBuffer和StringBuilder
9.2.1String.StringBuffer.StringBuilder三者的异同
(面试高频)
异:
String:不可变的字符序列;效率最低
StringBuffer:可变的字符序列;线程安全的,效率低;
StringBuiLder:可变的字符序列;jdk5.e新增的,线程不安全的,效率高;
同:
底层使用char[]存储
源码分析:
String str = new String();//char[] value = new char[0];
String str1 = new String(" abc" );//char[] value = new char[]i{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度为16的char型数组
System.out.println(sb1.Length( ));//0
sb1.append('a'); //value[0] = 'a '
sb1.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)和StringBuiLder(int capacity)可以避免扩容中的赋值过程提高效率
9.2.2StringBuffer类的常用方法
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)返回一个[start,end)区间的子字符串
public int length()
public char charAt(int n )
public void setCharAt(int n ,char ch):将索引n处的字符修改为ch
总结:
增: append(xxx)
删: deLete(int start,int end)
改: setCharAt(int n ,char ch) / replace(int start, int end,String str)
查: charAt(int n )
插: insert(int offset,xXx)
长度:Length();
遍历: for() + charAt() / toString()
9.2.3StringBuiLder的常用方法
与StringBuffer类似,只不过都不是线程安全的,方法没用synchnized修饰
9.2JDK8之前的日期时间API
1.System类提供的public static long currentTimeMillis()
2.java.util.Date类(父类)
|—java.sqL.Date类(子类)
3.SimpleDateFormat
4.Calender日历类
package com.atguigu.java;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* JDK8 之前日期和时间API的测试
* @author zhy
* @create 2022-12-19 11:36
*/
public class DateTimeTest {
@Test
//System类提供的public static long currentTimeMillis()
public void test1(){
//用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。将其成为时间戳
long timeMillis = System.currentTimeMillis();
System.out.println(timeMillis);
}
@Test
/*
java.util.Date类(父类)
|---java.sqL.Date类(子类)
对于java.util.Date类,需要关注:
1.两个构造器的使用
构造器1:创建一个对应当前的Date对象
构造器2:创建指定毫秒数的Date对象
2.两个方法的使用
>toString():显示当前的星期、月、日、时、分、秒、时区、年
>getTime()∶获取当前Date对象对应的毫秒数。(时间戳)
对于java.sqL.Date类,需要关注:
>如何实例化
>如何将sqL.Date->util.Date:利用多态
>sqL.Date<-util.Date
*/
public void test2(){
//构造器1:创建一个对应当前的Date对象
Date date1 = new Date();//java.util.Date
System.out.println(date1.toString());
System.out.println(date1.getTime());
//构造器2:创建指定毫秒数的Date对象
Date date2 = new Date(1671435182309L);
System.out.println(date2);
//创建java.sqL.Date对象
java.sql.Date date3 = new java.sql.Date(1671435182309L);
System.out.println(date3);//2022-12-09
//转换情况1
//sqL.Date -> util.Date
Date date4=new java.sql.Date(1671435182309L);
//sqL.Date <- util.Date
java.sql.Date date5=(java.sql.Date)date4;
//转换情况2
Date date6 = new Date();
//java.sql.Date date7 = (java.sql.Date)date6;//运行时报错
java.sql.Date date7 = new java.sql.Date(date6.getTime());
}
@Test
public void test3() throws ParseException {
//实例化SimpleDateFormat:使用默认构造器
SimpleDateFormat sdf = new SimpleDateFormat();
//格式化:日期->字符串
Date date = new Date();
System.out.println(date);//Fri Dec 23 10:27:25 CST 2022
String strDate=sdf.format(date);
System.out.println(strDate);//22-12-23 上午10:27
//解析:字符串->日期
String strDate2="18-11-20 下午6:27";//SimpleDateFormat默认只能解析这种格式的字符串
Date parse = sdf.parse(strDate2);
System.out.println(parse);
/****************************************************/
//实例化SimpleDateFormat:使用带参构造器
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:sss");
//格式化
String strDate3=sdf2.format(date);
System.out.println(strDate3);//2022-12-23 11:15:026
//解析
Date parse1 = sdf2.parse("2022-12-23 11:15:026");//此时必须是2022-12-23 11:15:026这种格式
System.out.println(parse1);
}
@Test
//Calender日历类(抽象类)的使用
public void test4(){
//1.实例化
//方式1:创建其子类GregorianCalendar的对象
//方式2:调用其静态方法getance
Calendar calender = Calendar.getInstance();
System.out.println(calender.getClass());
//class java.util.GregorianCalendar,由此可知getInstance返回的还是子类GregorianCalendar的对象
//2.常用方法
//get
System.out.println(calender.get(Calendar.DAY_OF_MONTH));//获取当前日期是本月的第几天
//set
calender.set(Calendar.DAY_OF_MONTH,20);
System.out.println(calender.get(Calendar.DAY_OF_MONTH));//20
//add
calender.add(Calendar.DAY_OF_MONTH,5);//在当前计算的数值上再加5天
System.out.println(calender.get(Calendar.DAY_OF_MONTH));//set中已经设置为20天,加5天之后为25
//getTime
Date date = calender.getTime();
System.out.println(date);
//setTime
Date date1 = new Date();
calender.setTime(date1);
System.out.println(calender.get(Calendar.DAY_OF_MONTH));//23
}
}
每日一考
1.画出如下几行代码的内容结构:
String s1 = “hello”;
String s2 = “hello”;
String s3 = new String(“hello”);
s1+=“world";
2.如何理解String类的不可变性
3.String类是否可以被继承?为什么?
String源码中声明为final
String s = new String(“hello”);在内存中创建了几个对象?请说明。
4.String,StringBuffer,StringBuilder三者的对比
5.String的常用方法有哪些?(至少7个),
9.3JDK 8中新日期时间API
JDK8之前的项目若想用JDK8之后的时间API,可以导入第三方的jav包Joda-Time
9.3.1LocalDate、LocalTime、LocalDateTime
package com.atguigu.java;
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* @author zhy
* @create 2022-12-24 11:47
*/
public class JKD8DateTimeTest {
@Test
//LocalDate、LocalTime、LocalDateTime的使用
public void test(){
//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, 12, 24, 20, 46, 30);
System.out.println(localDateTime1);
//getXxx:获取相关的属性
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getDayOfYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getMinute());
//体现不可变性
//withXxx()∶设置相关的属性
LocalDate localDate1 = localDate.withDayOfMonth(20);
System.out.println(localDate);
System.out.println(localDate1);
//plusXxx():增加
LocalDate localDate2 = localDate.plusMonths(3);
System.out.println(localDate);
System.out.println(localDate2);
//minusXxx():减少
LocalDateTime localDateTime2 = localDateTime.minusHours(3);
System.out.println(localDateTime);
System.out.println(localDateTime2);
}
}
9.3.2Instant
package com.atguigu.java;
import org.junit.Test;
import java.time.*;
/**
* @author zhy
* @create 2022-12-24 11:47
*/
public class JKD8DateTimeTest {
@Test
//LocalDate、LocalTime、LocalDateTime的使用
public void test(){
//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, 12, 24, 20, 46, 30);
System.out.println(localDateTime1);
//getXxx:获取相关的属性
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getDayOfYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getMinute());
//体现不可变性
//withXxx()∶设置相关的属性
LocalDate localDate1 = localDate.withDayOfMonth(20);
System.out.println(localDate);
System.out.println(localDate1);
//plusXxx():增加
LocalDate localDate2 = localDate.plusMonths(3);
System.out.println(localDate);
System.out.println(localDate2);
//minusXxx():减少
LocalDateTime localDateTime2 = localDateTime.minusHours(3);
System.out.println(localDateTime);
System.out.println(localDateTime2);
}
@Test
//instant
public void test2(){
//实例化。now()∶获取本初子午线对应的标准时间
Instant instant = Instant.now();
System.out.println(instant);//2022-12-24T14:22:32.240Z
//添加时间的偏移量:由本初子午线到北京东八区需要+8h
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2022-12-24T22:22:32.240+08:00
//获取自1970年1月1日日时日分日秒(UTC)开始的毫秒数.类似于Date的getTime
long milli = instant.toEpochMilli();
System.out.println(milli);//1671891940083
//实例化,通过毫秒数。
Instant instant1 = Instant.ofEpochMilli(1671891940083L);
System.out.println(instant1);//2022-12-24T14:25:40.083Z
}
}
9.3.3DateTimeFormatter
9.3.4其它类
9.4Java比较器
说明:Java中的对象,正常情况下,只能进行比较: ==或!=。不能使用>或<的
但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。如何实现?
使用两个接口中的任何一个:Comparable或Comparator
9.4.1Comparable接口
Comparable接口的使用举例:自然排序
1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象
2.像String、包装类重写compareTo()方法以后,进行了从小到大的排列
3.重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零。
4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法,在compareTo(obj)方法中指明如何排序
9.4.2Comparator接口
Comparator接口的使用:定制排序
1.背景:
当元素的类型没有实现java.Lang. Comparable接口而又不方便修改代码,或者实现了java.Lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用Comparator的对象来排序
2.重写compare(object o1,object o2)方法,比较o1和o2的大小:
如果返回正整数,则表示o1大于o2;
如果返回0,表示相等;
如果返回负整数,表示o1小于o2。
9.5System类
9.6Math类
9.7BigInteger与BigDecimal
9.7.1BigInteger
9.7.2BigDecimal
每日一考
P495
1.将字符串”2017-08-16"转换为对应的java.sql.Date类的对象。(使用JDK8之前或JDK8中的API皆可)。
2.解释何为编码?解码?何为日期时间的格式化?解析?
3.自定义Person类如下,如何实现自然排序(按姓名从小到大排序),代码说明
class Person{
private String name;
private int age;
}
4.提供定制排序涉及到的接口的实现类对象,并按Person类的年龄从大到小排序
5.JDK8之前和JDK8中日期、时间相关的类分别有哪些?