目录
一、❤️字符串相关类
1. String类
1.1 String的特性
1.2 String的实例化方式
1.3 String类中的常用方法
2. StringBuffer、StringBuilder类
二、❤️JDK 8之前日期时间API
1. java.lang.System类
2. java.util.Date类
3. java.sql.Date类
4. java.text.SimpleDateFormat类
5. java.util.Calender类
三、❤️JDK 8中新日期时间API
1. LocalDate、LocalTime、LocalDateTime类
2. Instant类
3. DateTimeFormatter类
4. 新旧API之间的转换
四、❤️Java比较器
1. 自然排序 : java.lang.Comparable
2. 定制排序 : java.lang.Comparator
3. 两种比较接口的使用对比
五、❤️System类
六、❤️Math类
七、❤️BigInteger与BigDecimal
1. BigInteger
2. BigDecimal
String类:代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
String是一个final类(不可继承),代表不可变的字符序列 (final char[] value)。
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
String对象的字符内容是存储在一个字符数组value[]中的。
public final class String
implements java.io.Serializable, Comparable, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
String : 字符串, 使用一对""引起来表示
String声明为final的,不可被继承
String实现了Serializable接口 : 表示字符串是支持序列化的 实现了Comparable接口 : 表示String可以比较大小
String内部定义了final char[] value 用于存储字符串数据
String : 代表不可变的字符序列 简称 : 不可变性 (不可变 : 只要对字符串的内容做任何的修改都必须重新造,原有的不能改变)
体现 :
当对字符串重新赋值时,需要重新指定区域赋值,不能使用原有的value进行赋值
当对现有的字符串进行连接操作时,也需要重新指定区域赋值,不能使用原有的value进行赋值
当调用String的replace()方法修改指定的字符或字符串时,也需要重新指定区域赋值,不能使用原有的value进行赋值
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
字符串常量池中不会存储相同内容的字符串
@Test
public void test01(){
String s1 = "abc";//字面量赋值
String s2 = "abc";
System.out.println(s1 == s2);//true
s2 = "hello";
System.out.println(s1 == s2);//false
System.out.println(s1);//abc
System.out.println(s2);//hello
System.out.println("*****************");
String s3 = "abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println(s1);//abc
System.out.println("*****************");
String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
以上代码的内存结构解析 :
方式一 : 通过字面量定义的方式
方式二 : 通过 new + 构造器的方式
Stirng str = new String();
//本质上 : this.value = new char[0];
面试题 : String str = new String("abc");方式创建对象,在内存中创建了几个对象 ?
答案 : 两个,一个是堆空间中new结构,另一个是String对象中的char[]对应的常量池中的数据 "abc"
@Test
public void test02(){
//此时的s1和s2的数据声明在方法区的字符串常量池中
String s1 = "JavaEE";
String s2 = "JavaEE";
//此时的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(s1 == s3);//false
System.out.println(s1 == s4);//false
}
以上代码的内存结构解析 :
有变量参与的字符串拼接赋值都相当于new的方式
@Test
public void test03(){
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
System.out.println(s6 == s7);//false
//如果拼接的结果调用intern()方法,返回值就在常量池中
String s8 = s5.intern();//返回值得到的s8使用的常量池中已经存在的"javaEEhadoop"
System.out.println(s3 == s8);//true
}
//当一个变量被final修饰以后就变成了常量 符合拼接规则 声明在字符串常量池
@Test
public void test04(){
String str1 = "javaEEhadoop";
final String str2 = "javaEE";
String str3 = "javaEE";
String str4 = str2 + "hadoop";
String str5 = str3 + "hadoop";
System.out.println(str1 == str4);//true
System.out.println(str1 == str5);//false
}
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 test01(){
String str1 = "HelloWorld";
//int length():返回字符串的长度: return value.length
System.out.println(str1.length());//10
//char charAt(int index): 返回某索引处的字符return value[index]
System.out.println(str1.charAt(0));//H
System.out.println(str1.charAt(1));//e
System.out.println(str1.charAt(5));//W
//boolean isEmpty():判断是否是空字符串:return value.length == 0
System.out.println(str1.isEmpty());//false
//String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
String str2 = str1.toLowerCase();
System.out.println(str1);//HelloWorld
System.out.println(str2);//helloworld
String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
String str3 = str1.toUpperCase();
System.out.println(str3);//HELLOWORLD
//String trim():返回字符串的副本,忽略前导空白和尾部空白
String str4 = " h ello world ";
String str5 = str4.trim();
System.out.println("--" + str4 + "--");//-- h ello world --
System.out.println("--" + str5 + "--");//--h ello world--
}
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 test02(){
String str1 = "abc";
String str2 = "abC";
//boolean equals(Object obj):比较字符串的内容是否相同
System.out.println(str1.equals(str2));//false
//boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
System.out.println(str1.equalsIgnoreCase(str2));//true
//String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
String str3 = str1.concat("def");
System.out.println(str3);//abcdef
//int compareTo(String anotherString):比较两个字符串的大小
System.out.println(str1.compareTo(str3));//-3 涉及到字符串排序
//String substring(int beginIndex):返回一个新的字符串,它是此字符串的
// 从beginIndex开始截取到最后的一个子字符串。
String str4 = "jchuanHou";
String str5 = str4.substring(6);
System.out.println(str4);//jchuanHou
System.out.println(str5);//Hou
//String substring(int beginIndex, int endIndex) :
// 返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
String str6 = str4.substring(1, 6);
System.out.println(str6);//chuan 左闭右开
}
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
@Test
public void test03(){
String str1 = "helloWorld";
//boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean b1 = str1.endsWith("ld");
System.out.println(b1);//true
//boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean b2 = str1.startsWith("ll");
System.out.println(b2);//false
//boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
boolean b3 = str1.startsWith("ll", 2);
System.out.println(b3);//true
//boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
String str2 = "Wo";
boolean contains = str1.contains(str2);
System.out.println(contains);//true
//int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
System.out.println(str1.indexOf("lo"));//3
//int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
System.out.println(str1.indexOf("lo", 5));//-1
//int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
System.out.println(str1.lastIndexOf("l"));//8
//int lastIndexOf(String str, int fromIndex):
// 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
System.out.println(str1.lastIndexOf("l", 7));//3
//当indexOf 和 lastIndexOf 返回值相同时 就说明当前子串在字符串中没有或者只有一个
}
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个,如果超过了,剩下的全部都放到最后一个元素中。
@Test
public void test04(){
String str1 = "北京的北京";
//String replace(char oldChar, char newChar):返回一个新的字符串,
// 它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String str2 = str1.replace('北', '东');
System.out.println(str1);//北京的北京
System.out.println(str2);//东京的东京
//String replace(CharSequence target, CharSequence replacement):
// 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String str3 = str1.replace("北京", "上海");
System.out.println(str3);//上海的上海
//使用正则匹配
//String replaceAll(String regex, String replacement) :
// 使用给定的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String str4 = "12hello34world5java7891mysql456";
//将字符串中的数字改为逗号
String str5 = str4.replaceAll("\\d+", ",");
System.out.println(str5);//,hello,world,java,mysql,
//将开头或者结尾的逗号变成空字符串
System.out.println(str5.replaceAll("^,|,$", ""));//hello,world,java,mysql
//判断这是一个杭州固话号码
//boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
String tel = "0571-4522345";
boolean matches = tel.matches("0571-\\d{7,8}");
System.out.println(matches);//true
//正则表达式切割
String str6 = "hello|world|java";
//String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String [] strs = str6.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
String与char[]之间的转换 :
/*
String 与 char[] 之前的转换
String --> char[] 调用String的toCharArray()
char[] --> String 调用String的构造器
*/
@Test
public void test01(){
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.print(charArray[i]);
}
System.out.println();
char[] chars = new char[]{'h', 'e', 'l', 'l', 'o'};
String toString = new String(chars);
System.out.println(toString);
}
String与byte[]之间的转换 :
/*
String 与 byte[] 之间的转换
String --> byte[] 调用String的getBytes()
byte[] --> String 调用String的构造器
编码 : String --> byte[]
解码 : byte[] --> String
编码 : 字符串 --> 字节(二进制数据)
解码 : 编码的逆过程
说明 : 解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码
*/
@Test
public void test02() throws UnsupportedEncodingException {
String str = "abc123";
String str1 = "中国";
byte[] bytes = str.getBytes();//使用默认的字符集进行编码 : 本电脑设置的为utf-8
System.out.println(Arrays.toString(bytes));//[97, 98, 99, 49, 50, 51]
byte[] bytes1 = str1.getBytes();
//使用utf-8 一个汉字占三个字节
System.out.println(Arrays.toString(bytes1));//[-28, -72, -83, -27, -101, -67]
//指定gbk字符集进行编码 英文字母与utf-8的编码方式一样
byte[] bytes2 = str1.getBytes("gbk");
System.out.println(Arrays.toString(bytes2));//[-42, -48, -71, -6]
String str2 = new String(bytes);//使用默认的字符集进行解码 : 本电脑设置的为utf-8
System.out.println(str2);//abc123
String str3 = new String(bytes2);//按utf8解码由gbk编码的字节数组
System.out.println(str3);//�й� 出现乱码 原因 : 编码集和解码集不一致
String str4 = new String(bytes2, "gbk");//使用gbk解码
System.out.println(str4);//中国 没有出现乱码 原因 : 编码集和解码集一致
}
String与StringBuffer、StringBuilder之间的转换 :
@Test
public void test05(){
//String --> StringBuffer StringBuilder 调用后两个类的构造器
String str = "abc";
StringBuffer stbf = new StringBuffer(str);
StringBuilder stbl = new StringBuilder(str);
//StringBuffer StringBuilder --> String 1. 调用String的构造器
//2. 调用前两个类的toString()方法
StringBuffer stringBuffer = new StringBuffer("hello");
String string = new String(stringBuffer);
String string2 = stringBuffer.toString();
}
java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象。很多方法与String相同。作为参数传递时,方法内部可以改变值。
String、StringBuffer、StringBuilder三者的异同 ?
String : 不可变的字符序列;底层使用char[]存储
StringBuffer : 可变的字符序列,线程安全的,效率低;底层使用char[]存储
StringBuilder : 可变的字符序列,JDK5.0新增,线程不安全的,效率高;底层使用char[]存储
@Test
public void test01(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0, 'm');
System.out.println(sb1);//mbc --> 可变的
}
源码分析 :
String str = new String();//char[] value = new char[0];
String str = new String("abc");//char[] value = new char[]{'a', 'b', 'c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];
//底层创建了一个长度是16的char型数组
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
问题一 : length()方法返回的是现有的字符数
问题二 : 扩容问题,如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。默认情况下,扩容为原来容量的2倍 + 2(int newCapacity = (value.length << 1) + 2;),同时将原有数组中的元素复制到新的数组中。
指导意义 : 开发中建议大家使用 : StringBuffer(int capacity) 或 StringBuilder(int capacity),尽量避免扩容时数组复制导致效率低的问题。
StringBuffer与StringBuilder中的常用方法 :
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() :把当前字符序列逆转
@Test
public void test01(){
StringBuffer s1 = new StringBuffer("abc");
//StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
s1.append(1);
s1.append('1');
System.out.println(s1);//abc11
//StringBuffer delete(int start,int end):删除指定位置的内容
s1.delete(3, 4);//左闭右开
System.out.println(s1);//abc1
//StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
s1.replace(1, 2, "hello");
System.out.println(s1);//ahelloc1
//StringBuffer insert(int offset, xxx):在指定位置插入xxx
s1.insert(2, false);
System.out.println(s1);//ahfalseelloc1
//StringBuffer reverse() :把当前字符序列逆转
s1.reverse();
System.out.println(s1);//1colleeslafha
}
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)
@Test
public void test02(){
StringBuffer s1 = new StringBuffer("JavaEEHelloWorld");
//public int indexOf(String str)
int index = s1.indexOf("Hello");
System.out.println(index);//6
//public String substring(int start,int end) : 返回一个从指定位置开始到结束的一个左闭右开的子字符串
String substring = s1.substring(s1.indexOf("Hello"), s1.indexOf("World"));
System.out.println(substring);//Hello
//public char charAt(int n )
char c = substring.charAt(2);
System.out.println(c);//l
//public void setCharAt(int n ,char ch)
s1.setCharAt(0, '0');
System.out.println(s1);//0avaEEHelloWorld
}
总结 :
增 : append(xxx) (方法链 : 即s1.append().append().append()...)
删 : 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()
遍历 : toString()
三种类型的效率对比 :
@Test
public void test03(){
//初始设置
long startTime = 0L;
long endTime = 0L;
String text = "";
StringBuffer buffer = new StringBuffer("");
StringBuilder builder = new StringBuilder("");
//开始对比
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
text = text + i; }
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
}
/*
result :
StringBuffer的执行时间:3
StringBuilder的执行时间:2
String的执行时间:1260
*/
效率从高到低排列 : StringBuilder > StringBuffer > String
System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。此方法适于计算时间差。
计算世界时间的主要标准有:
UTC(Coordinated Universal Time)
GMT(Greenwich Mean Time)
CST(Central Standard Time)
@Test
public void test01(){
//返回当前时间与1970年1月1日0时0分0秒的以毫秒为单位的时间差
//称为时间戳
long time = System.currentTimeMillis();
System.out.println(time);//1659921215194
}
表示特定的瞬间,精确到毫秒
java.util.Date类
-------java.sql.Date类(上面的子类)
构造器 :
Date():使用无参构造器创建的对象可以获取本地当前时间。
Date(long date)
常用方法 :
getTime() : 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
toString() : 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat),zzz是时间标准。
其它很多方法都过时了。
@Test
public void test02(){
//空参构造器
Date date1 = new Date();//创建一个对应当前时间的Date对象
//toString()方法
System.out.println(date1);//Mon Aug 08 09:20:11 CST 2022
//getTime()方法
long time = date1.getTime();
System.out.println(time);//1659921712164
//带参构造器
Date date2 = new Date(1659921712164L);//创建指定毫秒数的Date对象
System.out.println(date2);//Mon Aug 08 09:21:52 CST 2022
}
java.util.Date的子类,对应数据库中的日期类型的变量
构造器和常用方法 :
@Test
public void test03(){
//创建一个java.sql.Date类型的对象
java.sql.Date date1 = new java.sql.Date(1659921712164L);
//toString方法
System.out.println(date1);//2022-08-08
//getTime()方法
long time = date1.getTime();
System.out.println(time);//1659921712164
}
将java.util.Date对象转换为java.sql.Date对象 :
@Test
public void test04(){
//情况一 : 多态 向下转型
Date date1 = new java.sql.Date(1659921712164L);
java.sql.Date date2 = (java.sql.Date)date1;
//情况二 :
Date date3 = new Date(1659921712164L);
java.sql.Date date4 = new java.sql.Date(date2.getTime());
}
Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
它允许进行格式化 : 日期 --> 文本、解析 : 文本 --> 日期
格式化:
SimpleDateFormat() :默认的模式和语言环境创建对象
public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用:
public String format(Date date):方法格式化时间对象date
解析:
public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。
使用默认构造器
@Test
public void test01() throws ParseException {
//SimpleDateFormat实例化 : 使用默认的构造器
SimpleDateFormat spf = new SimpleDateFormat();
Date date = new Date();
System.out.println(date);
//格式化
String format = spf.format(date);
System.out.println(format);
//解析 : 要求要与格式化出来的字符串的格式一样
String str = "22-8-11 上午10:58";
Date date1 = spf.parse(str);//需要抛出异常
System.out.println(date1);
}
使用带参构造器
关于日期时间格式的规定 : 见图1。
例如 : 见图2。
@Test
public void test02() throws ParseException {
//实例化SimpleDateFormat : 带参构造器
SimpleDateFormat spf = new SimpleDateFormat("yyyy.MMMM.dd GGG hh:mm aaa");
SimpleDateFormat spf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = new Date();
System.out.println(date);//Thu Aug 11 11:14:25 CST 2022
//格式化
String format = spf.format(date);
System.out.println(format);//2022.八月.11 公元 11:14 上午
System.out.println(spf1.format(date));//2022-08-11 11:14:25
//解析 : 要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现)
//不然会抛出异常
Date date1 = spf1.parse("2002-08-27 11:16:52");
System.out.println(date1);//Tue Aug 27 11:16:52 CST 2002
}
练习 : 将字符串"2002-08-27" 转换为 java.sql.Date
@Test
public void test03() throws ParseException {
String str = "2002-08-27";
SimpleDateFormat spf = new SimpleDateFormat("yyyy-MM-dd");
//解析为java.util.Date
Date date = spf.parse(str);
System.out.println(date);//Tue Aug 27 00:00:00 CST 2002
//转换为java.sql.Date
java.sql.Date sqlDate = new java.sql.Date(date.getTime());
System.out.println(sqlDate);//2002-08-27
}
Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
获取Calendar实例的方法
使用Calendar.getInstance()方法
调用它的子类GregorianCalendar的构造器。
一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、MINUTE、SECOND
public void set(int field,int value)
public void add(int field,int amount)
public final Date getTime()
public final void setTime(Date date)
注意
获取月份时:一月是0,二月是1,以此类推,12月是11
获取星期时:周日是1,周一是2 ....... 周六是7
@Test
public void test01(){
//实例化
//方式一 : 调用Calendar的静态方法getInstance()
//方式二 : 创建其子类(class java.util.GregorianCalendar)的对象
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getClass());//class java.util.GregorianCalendar
//常用方法
//get()
int days = calendar.get(Calendar.DAY_OF_MONTH);///获取这个月的第几天
System.out.println(days);//11
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//223 获取这一年的第几天
//set()
calendar.set(Calendar.DAY_OF_MONTH, 10);//将时间改为这个月的第十天 修改的是calendar对象本身
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//10
//add()
calendar.add(Calendar.DAY_OF_MONTH, 5);//将calendar对象的时间改为在之前基础上加5天
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//15
calendar.add(Calendar.DAY_OF_MONTH, -5);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
//getTime() : 日历类 --> Date类
Date date = calendar.getTime();
System.out.println(date);//Wed Aug 10 17:53:22 CST 2022
//setTime() : Date类 --> 日历类
Date nowDate = new Date();
calendar.setTime(nowDate);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//11
}
如果我们可以跟别人说:“我们在1502643933071见面,别晚了!”那么就再简单不过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:
可变性:像日期和时间这样的类应该是不可变的。
偏移性:Date中的年份是从1900开始的,而月份都从0开始。
格式化:格式化只对Date有用,Calendar则不行。
此外,它们也不是线程安全的;不能处理闰秒等。
@Test
public void test(){
//偏移量
Date date = new Date(2022, 8, 11);
System.out.println(date);//Mon Sep 11 00:00:00 CST 3922
Date nowDate = new Date(2022 - 1900, 8 - 1, 11);
System.out.println(nowDate);//Thu Aug 11 00:00:00 CST 2022
}
第三次引入的API是成功的,并且Java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。
Java 8 吸收了 Joda-Time (一个jar包) 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。
java.time – 包含值对象的基础包
java.time.chrono – 提供对不同的日历系统的访问
java.time.format – 格式化和解析时间和日期
java.time.temporal – 包括底层框架和扩展特性
java.time.zone – 包含时区支持的类
说明:大多数开发者只会用到基础包和format包,也可能会用到temporal包。因此,尽管有68个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
java.time包下,类似于Calendar类
@Test
public void test01(){
//实例化
//方式一 : 调用其静态方法now() 获取当前的日期时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);//2022-08-11
System.out.println(localTime);//18:21:31.851
System.out.println(localDateTime);//2022-08-11T18:21:31.851
//方式二 : 调用其静态方法of() 根据设置的日期时间创建对象 没有偏移量
LocalDateTime localDateTime1 = LocalDateTime.of(2022, 8, 1, 18, 20);
System.out.println(localDateTime1);//2022-08-01T18:20
//getXxx() 获取相关的属性
System.out.println(localDateTime.getDayOfMonth());//11
System.out.println(localDateTime.getDayOfWeek());//THURSDAY
System.out.println(localDateTime.getMonth());//AUGUST
System.out.println(localDateTime.getMonthValue());//8
//withXxx() 设置相关的属性
LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(12);//返回一个新的对象 (不可变性)
System.out.println(localDateTime);//2022-08-11T18:29:10.288
System.out.println(localDateTime2);//2022-08-12T18:27:33.212
//plusXxx() 加上 不可变性
LocalDateTime localDateTime3 = localDateTime.plusDays(63);
System.out.println(localDateTime);//2022-08-11T18:32:51.780
System.out.println(localDateTime3);//2022-10-13T18:32:51.780
//minusXxx() 减去 不可变性
LocalDateTime localDateTime4 = localDateTime3.minusDays(63);
System.out.println(localDateTime4);//2022-08-11T18:40:28.488
}
Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数
java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
(1 ns = 10-9 s) 1秒 = 1000毫秒 =10^6微秒=10^9纳秒
java.time.Instant类,类似于java.util.Date类
@Test
public void test(){
//now() : 获取本初子午线对应的标准时间来创建对象
Instant instant = Instant.now();
System.out.println(instant);//2022-08-11T10:51:38.562Z
//根据毫秒数创建对象 --> 类似于Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1660215230919L);
System.out.println(instant1);//2022-08-11T10:53:50.919Z
//添加时间的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2022-08-11T18:51:38.562+08:00
//获取UTC开始的对应的毫秒数 --> 类似于Date类的getTime()方法
System.out.println(instant.toEpochMilli());//1660215230919
}
格式化与解析日期和时间
该类提供了三种格式化方法:
预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
@Test
public void test01(){
//格式一 : 预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
DateTimeFormatter formatter= DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime localDateTime = LocalDateTime.now();
//格式化 : 日期 --> 字符串
String format = formatter.format(localDateTime);
System.out.println(localDateTime);//2022-08-11T19:18:38.673
System.out.println(format);//2022-08-11T19:18:38.673
//解析 : 字符串 --> 日期
String str = "2022-08-11T19:18:38.673";
//多态的方式
TemporalAccessor parseDateTime = formatter.parse(str);
System.out.println(parseDateTime);//{},ISO resolved to 2022-08-11T19:18:38.673
//格式二 :
//本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.SHORT)
//格式化
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
String str1 = formatter1.format(localDateTime);
System.out.println(str1);//22-8-11 下午7:27
//本地化相关的格式。如:ofLocalizedDate(FormatStyle.FULL)
//格式化
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String str2 = formatter2.format(localDateTime);
System.out.println(str2);//2022年8月11日 星期四
//格式三(重点) : 自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss E”)
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss E");
//格式化
String str3 = formatter3.format(LocalDateTime.now());
System.out.println(str3);//2022-08-11 07:33:22 星期四
//解析
TemporalAccessor parse = formatter3.parse("2022-08-11 07:33:22 星期四");
System.out.println(parse);//{MinuteOfHour=33, SecondOfMinute=22, NanoOfSecond=0, HourOfAmPm=7, MicroOfSecond=0,
// MilliOfSecond=0},ISO resolved to 2022-08-11
}
JDK8之前与之后的日期时间类的对比 :
在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。
Java实现对象排序的方式有两种:
自然排序:java.lang.Comparable
定制排序:java.util.Comparator
Comparable的使用举例 :
像String、包装类等实现了Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方式
像String、包装类等实现了Comparable接口,重写了compareTo()方法以后,进行了从小到大的排列
重写compareTo(obj)规则 : 如果当前对象this大于形参对象obj,则返回正整数 如果当前对象this小于形参对象obj,则返回负整数 如果当前对象this等于形参对象obj,则返回零。
实现Comparable接口的对象列表(和数组)可以通过 Collections.sort 或Arrays.sort进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
@Test
public void test01(){
String[] strings = new String[]{"AA", "CC", "BB", "DD", "FF", "EE"};
System.out.println(Arrays.toString(strings));//[AA, CC, BB, DD, FF, EE]
Arrays.sort(strings);
System.out.println(Arrays.toString(strings));//[AA, BB, CC, DD, EE, FF]
}
对于自定义类,如果需要排序,我们可以让自定义类实现Comparable接口,重写CompareTo()方法,在方法中指明如何排序,如果未重写就调用Arrays.sort或Collections.sort,则会报异常。
@Test
public void test02(){
Goods[] goods = new Goods[4];
goods[0] = new Goods("lenovo", 34);
goods[1] = new Goods("xiaomi", 12);
goods[2] = new Goods("dell", 43);
goods[3] = new Goods("huawei", 65);
System.out.println(Arrays.toString(goods));
Arrays.sort(goods);//如果未实现Comparable接口 则抛出ClassCastException
System.out.println(Arrays.toString(goods));
}
//商品类
class Goods implements Comparable{
private String name;
private double price;
public Goods(){}
public Goods(String name, double price){
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
//指明商品比较大小的方式
//按照价格从低到高排序 按照产品名称从高到低排序
@Override
public int compareTo(Object o) {
if (o instanceof Goods) {
Goods goods = (Goods) o;
//方式一 :
if (this.price > goods.price) return 1;
if (this.price < goods.price) return -1;
if (this.price == goods.price){
return -this.name.compareTo(goods.name);
}
//方式二 : 使用包装类
// return Double.compare(this.price, goods.price);
}
throw new RuntimeException("传入的数据类型不一致");
}
}
Comparator的使用举例 :
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排序的比较。
重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,表示o1大于o2
如果方法返回负整数,表示o1小于o2
如果方法返回0,表示o1与o2相等
可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。
@Test
public void test(){
String[] arr = new String[]{"AA", "CC", "BB", "DD", "FF", "EE"};
System.out.println(Arrays.toString(arr));//[AA, CC, BB, DD, FF, EE]
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof String && o2 instanceof String){
String str1 = (String) o1;
String str2 = (String) o2;
return -str1.compareTo(str2);
}
throw new RuntimeException("传入数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));//[FF, EE, DD, CC, BB, AA]
}
对于自定义类的比较 :
@Test
public void test02(){
Goods[] goods = new Goods[4];
goods[0] = new Goods("lenovo", 34);
goods[1] = new Goods("xiaomi", 12);
goods[2] = new Goods("xiaomi", 43);
goods[3] = new Goods("huawei", 65);
System.out.println(Arrays.toString(goods));
Arrays.sort(goods, new Comparator() {
//按照产品名称从低到高排序 按照价格从高到低排序
@Override
public int compare(Goods o1, Goods o2) {
if (o1.getName().equals(o2.getName())){
return -Double.compare(o1.getPrice(), o2.getPrice());
} else return o1.getName().compareTo(o2.getName());
}
});
System.out.println(Arrays.toString(goods));
}
Comparable接口在类内重写,一旦确定,则保证Comparable接口实现类的对象在任何位置都可以比较大小
Comparator接口属于临时性的比较
System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便的进行调用。
成员变量
System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
成员方法
native long currentTimeMillis(): 该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
void exit(int status): 该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。
void gc():该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
String getProperty(String key): 该方法的作用是获得系统中属性名为key的属性对应的值。
@Test
public void test(){
String javaVersion = System.getProperty("java.version");
System.out.println("java的version:" + javaVersion);
String javaHome = System.getProperty("java.home");
System.out.println("java的home:" + javaHome);
String osName = System.getProperty("os.name");
System.out.println("os的name:" + osName);
String osVersion = System.getProperty("os.version");
System.out.println("os的version:" + osVersion);
String userName = System.getProperty("user.name");
System.out.println("user的name:" + userName);
String userHome = System.getProperty("user.home");
System.out.println("user的home:" + userHome);
String userDir = System.getProperty("user.dir");
System.out.println("user的dir:" + userDir);
}
/*
result :
java的version:1.8.0_311
java的home:D:\App\JavaSE\jdk1.8.0_311\jre
os的name:Windows 10
os的version:10.0
user的name:暖阳icc
user的home:C:\Users\暖阳icc
user的dir:D:\CS\Java\Java高级\Java常用类\Code
*/
java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型。
abs 绝对值
acos,asin,atan,cos,sin,tan 三角函数
sqrt 平方根
pow(double a,doble b) a的b次幂
log 自然对数
exp e为底指数
max(double a,double b)
min(double a,double b)
random() 返回0.0到1.0的随机数
long round(double a) double型数据a转换为long型(四舍五入)
toDegrees(double angrad) 弧度—>角度
toRadians(double angdeg) 角度—>弧度
Integer类作为int的包装类,能存储的最大整型值有限,Long类也是有限的。如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
java.math包的BigInteger可以表示不可变的任意精度的整数。
BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
构造器
BigInteger(String val):根据字符串构建BigInteger对象
一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
构造器
public BigDecimal(double val)
public BigDecimal(String val)