文章目录
九、字符串相关的类
9.1 String
9.1.1 String 的特性
- String类:代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
- String是一个final类,代表不可变的字符序列。
- 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
- String对象的字符内容是存储在一个字符数组value[]中的。
public final class String
implements java.io.Serializable, Comparable<String>,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:字符串,使用一对""引起来表示。
1.String声明为final的,不可被继承
2.String实现了Serializable接口:
表示字符串是支持序列化的;
实现了Comparable接口:
表示String可以比较大小
3.String内部定义了final char[] value用于存储字符串数据
4.String:代表不可变的字符序列。简称:不可变性。
体现:
5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串声明在字符串常量池中。
6.字符串常量池中是不会存储相同内容的字符串的。
public class StringTest {
@Test
public void test(){
String s1 = "abc";//字面量的定义方式
String s2 = "abc";
System.out.println(s1 == s2);//true
s1 = "hello";
System.out.println(s1 == s2);//false
System.out.println(s1);//hello
System.out.println(s2);//abc
String s3 = s2.replace('a','m');
System.out.println(s3);//mbc
}
9.1.2 String对象的创建
String的实例化方式:
- 方式一,通过字面量定义的方式。
- 方式二,通过new+构造器的方式。
String str = “hello”;
//本质上this.value = new char[0];
String s1 = new String();
//this.value = original.value;
String s2 = new String(String original);
//this.value = Arrays.copyOf(value, value.length);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex,int count);
@Test
public void test5(){
//通过字面量定义的方式,此时的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(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println("*********************");
Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 12);
//Equals一般比较地址值是否相同,但如果比较的是string类型的,会比较内容,因为string类的equals重写过。
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true
p1.name = "Jerry";
System.out.println(p1.name);
System.out.println(p2.name);
}
面试题:
String s = new String(“abc”);方式创建对象,创建了几个对象?
两个或一个
一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc”;如果一开始常量池中就有"abc",则只在堆空间中创建一个对象。
9.1.3 String不同拼接操作的对比
1.常量与常量的拼接结果在常量池。 且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中。
@Test
public void test4(){
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = "hadoop";
System.out.println(s1 == s3);//false
//final修饰变量,相当于常量,在常量池当中
//s4常量,final修饰,一旦初始化,不可更改
final String s4 = "javaEE";
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true
}
**下列程序运行的结果:
【面试题】
**
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 static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + " and ");//
System.out.println(ex.ch);
}
}
9.1.4 JVM中涉及字符串的内存结构
9.1.5 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 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个,如果超过了,剩下的全部都放到最后一个元素中。
方法测试:
package com.string.java;
import org.junit.Test;
/**
- @BelongsProject: JavaSenior
- @BelongsPackage: com.string.java
- @Author: Yanyang Li
- @CreateTime: 2023-01-09 14:49
- @Description: TODO
- @Version: 1.0
*/
public class StringMethodTest {
@Test
public void test1(){
String s1 = "HelloWorld";
System.out.println(s1.length());//10
System.out.println(s1.charAt(0));//H
System.out.println(s1.charAt(9));//d
// System.out.println(s1.charAt(10));//java.lang.StringIndexOutOfBoundsException: String index out of range: 10
// s1 = "";
System.out.println(s1.isEmpty());//false
String s2 = s1.toLowerCase();
String s3 = s1.toUpperCase();
System.out.println(s1);//s1不可变(final)
System.out.println(s2);//helloworld
System.out.println(s3);//HELLOWORLD
String s4 = " he llo world";
String s5 = s4.trim();
System.out.println("-----" + s4 + "-----");//----- he llo world-----
System.out.println("-----" + s5 + "-----");//-----he llo world-----
}
@Test
public void test2(){
String s1 = "HelloWorld";
String s2 = "helloworld";
System.out.println(s1.equals(s2));//false
System.out.println(s1.equalsIgnoreCase(s2));//true
String s3 = "abc";
String s4 = s3.concat("def");
System.out.println(s4);//abcdef
String s5 = new String("abf");
System.out.println(s4.compareTo(s5));//-3 涉及到字符串排序
String s6 = "北京尚硅谷教育";
String s7 = s6.substring(2);
String s8 = s6.substring(2,5);//左闭右开
System.out.println(s6);//北京尚硅谷教育
System.out.println(s7);//尚硅谷教育
System.out.println(s8);//尚硅谷
}
@Test
public void test3(){
String s1 = "helloworld";
boolean b1 = s1.endsWith("ld");//对""中字符串的长度无要求
System.out.println(b1);//true
System.out.println(s1.startsWith("h"));//true
System.out.println(s1.startsWith(String.valueOf(s1.charAt(0))));//true
boolean b2 = s1.startsWith("ll",2);
System.out.println(b2);//true
String s2 = "wo";
String s3 = "woD";
System.out.println(s1.contains(s2));//true
System.out.println(s1.contains(s3));//false
System.out.println(s1.indexOf("lo"));//3 对应字符串首次出现的位置
System.out.println(s1.indexOf("lol"));//-1 没有出现则返回-1
System.out.println(s1.indexOf("lo",5));//-1 没有出现则返回-1
String s4 = "hellorworld";
System.out.println(s4.indexOf("or"));//4
System.out.println(s4.lastIndexOf("or"));//7
System.out.println(s4.lastIndexOf("or",6));//4
String s5 = "hellorworworld";
System.out.println(s5.lastIndexOf("or",9));//7
/*
什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?
情况一:存在唯一的str
情况二:不存在str
*/
}
@Test
public void test4(){
String s1 = "北京尚硅谷教育北京";
String s2 = s1.replace("北京", "Beijing");
System.out.println(s1);//北京尚硅谷教育北京
System.out.println(s2);//Beijing尚硅谷教育Beijing
String s3 = "12hello34world567java8mysql9";
String s4 = s3.replaceAll("\\d",",");//将数字替换为逗号
System.out.println(s3);//12hello34world567java8mysql9
System.out.println(s4);//,,hello,,world,,,java,mysql,
String s5 = s4.replaceAll("^,|$,", "");//如果字符串开头或结尾有,的话去掉
System.out.println(s5);//,hello,,world,,,java,mysql,
System.out.println("*********************");
String str = "12345";
//判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = str.matches("\\d+");//true
System.out.println(matches);//true
String tel = "0571-4534289";
//判断这是否是一个杭州的固定电话
boolean result = tel.matches("0571-\\d{7,8}");//true 后面7位或者8位数字
System.out.println(result);//true
System.out.println("*********************");
String str1 = "hello|world|java";
String[] strs1 = str1.split("\\|");
for(int i = 0;i < strs1.length; i++) {
System.out.println(strs1[i]);
}
System.out.println("*********************");
String str2 = "hello.world.java";
String[] strs2 = str2.split("\\.");
for(int i = 0;i < strs2.length; i++){
System.out.println(strs2[i]);
}
}
}
9.1.6 String与基本数据类型转换
字符串 → 基本数据类型、包装类
- Integer包装类的public static int parseInt(String s):可以将由“数字”字
符组成的字符串转换为整型。
类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应
的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 → 字符串
- 调用String类的public String valueOf(int n)可将int型转换为字符串
相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double
d)、valueOf(boolean b)可由参数的相应类型到字符串的转换
字符数组 → 字符串
- String 类的构造器:String(char[]) 和 String(char[],int offset,int
length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
字符串 → 字符数组
- public char[] toCharArray():将字符串中的全部字符存放在一个字符数组
中的方法。- public void getChars(int srcBegin, int srcEnd, char[] dst,
int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
代码演示
package com.string.java;
import org.junit.Test;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
- @BelongsProject: JavaSenior
- @BelongsPackage: com.string.java
- @Author: Yanyang Li
- @CreateTime: 2023-01-09 14:49
- @Description: TODO
- @Version: 1.0
*/
public class StringTest {
/*
String的实例化方式:
方式一,通过字面量定义的方式。
方式二,通过new+构造器的方式。
面试题:
String s = new String("abc");方式创建对象,创建了几个对象?
两个:
一个是堆空间中new结构,,另一个是char[]对应的常量池中的数据:"abc"
*/
@Test
public void test5(){
//通过字面量定义的方式,此时的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(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println("*********************");
Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 12);
//Equals一般比较地址值是否相同,但如果比较的是string类型的,会比较内容,因为string类的equals重写过。
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true
p1.name = "Jerry";
System.out.println(p1.name);
System.out.println(p2.name);
}
/*
String:字符串,使用一对""引起来表示。
1.String声明为final的,不可被继承
2.String实现了Serializable接口:表示字符串是支持序列化的
实现了Comparable接口:表示String可以比较大小
3.String内部定义了final char[] value用于存储字符串数据
4.String:代表不可变的字符序列。简称:不可变性。
体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2.将对现有的字符串进行连接,操作时也需要重新指定内存区域复制,不能使用原有的value赋值。
3.当调用string的replace方法修改指定字符或字符串时,也需要重新指定内存区域赋值。
5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串声明在字符串常量池中。
6.字符串常量池中是不会存储相同内容的字符串的。
*/
@Test
public void test(){
String s1 = "abc";//字面量的定义方式
String s2 = "abc";
System.out.println(s1 == s2);//true
s1 = "hello";
System.out.println(s1 == s2);//false
System.out.println(s1);//hello
System.out.println(s2);//abc
String s3 = s2.replace('a','m');
System.out.println(s3);//mbc
}
/*
1.常量与常量的拼接结果在常量池。 且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中。
*/
@Test
public void test4(){
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = "hadoop";
System.out.println(s1 == s3);//false
//final修饰变量,相当于常量,在常量池当中
//s4常量,final修饰,一旦初始化,不可更改
final String s4 = "javaEE";
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true
}
/*
String与byte[]之间的转换
编码 String-->byte[]:getBytes(); Array.toString(str.getBytes())
解码 byte[]-->String: String构造器
编码:字符串-->字节(看得懂-->看不懂的二进制数据)
解码:编码的逆过程,字节-->字符串(看不懂的二进制数据-->看得懂)
说明:解码时,要求解码使用的字符集要和编码时使用的字符集一致
*/
@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(str3);//出现乱码,编码集和解码集不一致
String str4 = new String(gbks, "gbk");
System.out.println(str4);
}
/*
String 与char[]之间的转换
String-->char[]:调用String的toCharArray()
char[]-->String:调用String的构造器
*/
@Test
public void test2() {
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
//首尾两两交换
for (int i = 1; i < charArray.length / 2; i++) {
char temp = charArray[i];
charArray[i] = charArray[charArray.length - 1 - i];
charArray[charArray.length - 1 - i] = temp;
}
System.out.println(new String(charArray));//a21cb3
char[] arr = new char[]{'h', 'e', 'l', 'l', 'o'};
String str2 = new String(arr);
System.out.println(str2);
}
/*
String 与基本数据类型、包装类之间的转换。
String-->基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
基本数据类型、包装类-->String:调用String重载的valueOf(xxx)
*/
@Test
public void test1() {
String str1 = "123";
// int num = (int)str1;//错误的
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num);//"123"
String str3 = num + "";
System.out.println(str1 == str3);
System.out.println(123);
}
}
9.1.7 String常见算法题目
9.1.8 StringBuffer和StringBuilder
- java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符
串内容进行增删,此时不会产生新的对象。- 很多方法与String相同。
- 作为参数传递时,方法内部可以改变值。
jdk1.9之后, String这三个类底层都是byte数组了(byte[])
String、StringBuffer、StringBuilder三者的异同:
String:不可变的字符序列
StringBuffer:可变的字符序列:线程安全,效率低
StringBuilder:可变的字符序列,jdk5.0新增的,线程不安全,效率高(不是多线程没有共享数据优先选择),局部变量用StringBuilder,因为局部变量不存在线程安全问题。
源码分析:
String str = new String();//new char[0]
String str1 = new String("abc");//new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//new char[16];底层创建了一个长度是16的数组
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)
@Test
public void test1(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0,'m');
System.out.println(sb1);//mbc 可变的
StringBuffer sb2 = new StringBuffer();
System.out.println(sb2.length());//0
}
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)
总结:
- 增:append(xxx)
- 删:delete(int start,int end)
- 改:setCharAt(int n,char ch)/replace(int start,int end,String str)
- 查:charAt()
- 插:insert(int offset,xxx)
- 长度:length();
- 遍历:for() + charAt()
代码
@Test
public void test2(){
StringBuffer s1 = new StringBuffer("abc");
s1.append(1);
s1.append('1');
System.out.println(s1);//abc11
s1.delete(2,4);
System.out.println(s1);//ab1
s1.replace(0,2,"hello");
System.out.println(s1);//hello1
s1.insert(2,false);
System.out.println(s1);//hefalsello1
System.out.println(s1.length());//11
s1.reverse();
System.out.println(s1);//1olleslafeh
System.out.println(s1.length());//11
String s2 = s1.substring(4,9);
System.out.println(s2);//eslaf
StringBuffer s3 = new StringBuffer(s2);
System.out.println(s3.reverse());//false
char c = s3.charAt(1);
System.out.println(c);//a
System.out.println("**************************");
System.out.println(s3);//false
for(int i = 0; i < s3.length(); i++){
System.out.println(s1.charAt(i));
}
System.out.println(s3);//false
for(int i = 0; i < s3.length(); i++){
System.out.println(s1.charAt(i));
}
System.out.println(s3.toString());//false
}
对比String、StringBuffer、StringBuilder三者的效率:
从高到低排列:StringBuilder > StringBuffer > String
@Test
public void test3(){
//初始设置
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));
}
执行结果:
StringBuffer的执行时间:6
StringBuilder的执行时间:4
String的执行时间:1373
9.2 JDK 8之前的日期时间API
9.2.1 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
9.2.2 java.util.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是时间标准。- 其它很多方法都过时了
9.2.3 java.text.SimpleDateFormat类
- Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat
类是一个不与语言环境有关的方式来格式化和解析日期的具体类。- 它允许进行格式化:日期→文本、解析:文本→日期
- 格式化:
- SimpleDateFormat() :默认的模式和语言环境创建对象
- public SimpleDateFormat(String pattern):该构造方法可以用参数pattern
指定的格式创建一个对象,该对象调用:- public String format(Date date):方法格式化时间对象date
- 解析:
public Date parse(String source):从给定字符串的开始解析文本,以生成
一个日期。
9.2.4. java.util.Calendar(日历)类
- 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
测试代码:
package com.string.java;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-09 20:36
* @Description: TODO JDK 8之前日期和时间的API测试
* @Version: 1.0
*/
public class DateTimeTest {
/*
java.util.Date类
|---java.sql.Date类
1.两个构造器的使用
2.两个方法的使用
>toString(): String、包装类、File、Date类重写过,显示当前星期几、月、日、时、分、秒
>getTime():获取当前data对象对应的毫秒数。(时间戳)
3.java.sql.Date对应着数据库中的日期类型的变量
>如何实例化:
>如何将java.util.Date对象转换为java.sql.Date
jdk 8之前的日期时间的API测试
1.System类中currentTimeMillis();
2.java.util.Date和子类java.sql.Date
3.SimpleDateFormat
4.Calendar
SimpleDateFormat的使用:SimpleDateFormat对日期Date类的格式化和解析
1.两个操作:
1.1 格式化: 日期-->字符串
1.2 解析:格式化的逆过程:字符串-->日期
2.SimpleDateFormat的实例化(非静态的)
*/
@Test
public void testSimpleDateFormat() throws ParseException {
//实例化SimpleDateFormat:使用默认的构造器
SimpleDateFormat sdf = new SimpleDateFormat();
//格式化:日期-->字符串
Date date = new Date();
System.out.println(date);//Tue Jan 10 12:01:59 CST 2023
String format = sdf.format(date);
System.out.println(format);//23-1-10 下午12:01
//解析:格式化的逆过程:字符串-->日期
String str = "23-1-10 下午12:06";
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(date1);
System.out.println(format1);//2023-01-10 12:06:00
//解析:要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现),否则,抛异常。
Date date2 = sdf1.parse(format1);
System.out.println(date2);//Tue Jan 10 00:06:00 CST 2023
}
/*
练习一:字符串"2020-09-08"转换为java.sql.Date
练习二:"三天打鱼,两天晒网" 1990-01-01 xxxx-xx-xx 打鱼?晒网?
举例:2020-09-08 ?计算总天数
总天数 % 5 == 1,2,3:打鱼
总天数 % 5 == 4,0:晒网
总天数的计算?
方式一:date2.getTime() - date1.getTime() / (1000*60*60*24)+ 1
方式二:1990-01-01 --> 2019-12-31 + 2020-01-01 --> 2020-09-08
*/
@Test
public void testExer() throws ParseException {
//解析:格式化的逆过程:字符串-->日期
String birth = "2020-09-08";
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf1.parse(birth);
// System.out.println(date);//Tue Sep 08 00:00:00 CST 2020 默认时分秒为0
java.sql.Date birthDate = new java.sql.Date(date.getTime());
System.out.println(birthDate);
}
/*
Calendar日历类的使用
*/
@Test
public void testCalendar(){
//1.实例化
//方式一:创建其子类(GregorianCalendar)的对象(它本身是抽象类)
//方式二:调用其静态方法getInstance()
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);//这个月的第几天 10
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//今天是这一年的第十天
//set()
calendar.set(Calendar.DAY_OF_MONTH,22);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//22
//add()
calendar.add(Calendar.DAY_OF_MONTH,3);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//25
//getTime():日历类-->Date
Date date = calendar.getTime();
System.out.println(date);//Wed Jan 25 21:04:35 CST 2023
//setTime():Date-->日历类
Date date1 = new Date();
calendar.setTime(date1);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//10
}
@Test
public void test2(){
//构造器一:Date() 创建了一个当前时间的Date对象
Date date1 = new Date();
System.out.println(date1);
System.out.println(date1.toString());//Mon Jan 09 21:13:16 CST 2023 显示到秒
System.out.println(date1.getTime());//1673269996427 显示到毫秒(ms)
//构造器二:创建指定毫秒数的Date对象
Date date2 = new Date(1673269996427L);
System.out.println(date2.toString());
//创建java.sql.Date对象
java.sql.Date date3 = new java.sql.Date(35235325345L);
System.out.println(date3);//1971-02-13
//如何将java.util.Date对象转换为java.sql.Date
//情况一:
// Date date4 = new java.sql.Date(2343243242323L);
// java.sql.Date date5 = (java.sql.Date) date4;
//情况二:
Date date6 = new Date();
java.sql.Date date7 = new java.sql.Date(date6.getTime());
}
//1.System类中的currentTimeMiles()
@Test
public void test1(){
//返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
//称为时间戳
long times = System.currentTimeMillis();
System.out.println(times);
}
}
9.3 JDK 8中新日期时间API
9.3.1 LocalDate、LocalTime、LocalDateTime
测试代码:
package com.string.java;
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-11 19:31
* @Description: TODO jdk 8中日期时间API的测试
* @Version: 1.0
*/
public class JDK8DateTimeTest {
@Test
public void testDate(){
//偏移量
Date date1 = new Date(2020 - 1900,9 - 1,8);
System.out.println(date1);//Tue Sep 08 00:00:00 CST 2020 偏移量的原因,year-1900,month-1
}
/*
LocalDate、LocalTime、LocalDateTime 的使用
说明:
1.LocalDateTime相较于LocalDate、LocalTime,使用频率更高
2.类似于Calendar
*/
@Test
public void test1(){
//now():获取当前的日期、时间、日期+时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);//2023-01-11
System.out.println(localTime);//20:05:21.532
System.out.println(localDateTime);//2023-01-11T20:05:21.532
System.out.println("****************************************");
//of():设置指定的年、月、日、时、分、秒,没有偏移量。
LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
System.out.println(localDateTime1);//2020-10-06T13:23:43
//getXxx():获取相关的属性
System.out.println(localDateTime1.getDayOfYear());//280
System.out.println(localDateTime1.getDayOfMonth());//6
System.out.println(localDateTime1.getDayOfWeek());//TUESDAY
System.out.println(localDateTime1.getMonth());//OCTOBER
System.out.println(localDateTime1.getMonthValue());//10
System.out.println(localDateTime1.getMinute());//23
//体现不可变性,重新设置数据后,会重新造对象接收
//withXxx():设置相关的属性
LocalDate localDate1 = localDate.withDayOfMonth(15);
System.out.println(localDate1);//2023-01-15
System.out.println(localDate);//2023-01-11
LocalDateTime localDateTime2 = localDateTime1.withHour(15);
System.out.println(localDateTime1);//2020-10-06T13:23:43
System.out.println(localDateTime2);//2020-10-06T15:23:43
//不可变性
LocalDateTime localDateTime3 = localDateTime.plusMonths(3);
System.out.println(localDateTime);//2023-01-11T20:46:21.386
System.out.println(localDateTime3);//2023-04-11T20:46:21.386
LocalDateTime localDateTime4 = localDateTime.minusMonths(6);
System.out.println(localDateTime);//2023-01-11T21:09:50.252
System.out.println(localDateTime4);//2022-07-11T21:09:50.252
}
}
9.3.2 瞬时:Instant
测试代码:
package com.string.java;
import org.junit.Test;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-11 21:25
* @Description: TODO Instant的使用 类似于java.util.Date类
* @Version: 1.0
*/
public class InstantTest {
@Test
public void test1(){
//now():获取对应本初子午线对应的时间
Instant instant = Instant.now();
System.out.println(instant);//2023-01-11T13:34:32.120Z 我们在东八区,需要这个时间加上8小时
//添加时间的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2023-01-11T21:34:32.120+08:00
//toEpochMilli():获取对应的毫秒数 表示自1970年1月1日0时0分0秒(UTC)开始的秒数。
long milli = instant.toEpochMilli();
System.out.println(milli);
//ofEpochMilli():通过给定的毫秒数,获取Instant实例 -->Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1673444476825L);
System.out.println(instant1);//2023-01-11T13:41:16.825Z
OffsetDateTime offsetDateTime1 = instant1.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime1);//2023-01-11T21:41:16.825+08:00
}
}
9.3.3 格式化与解析日期或时间
测试代码
package com.string.java;
import org.junit.Test;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-11 21:25
* @Description: TODO Instant的使用 类似于java.util.Date类
* @Version: 1.0
*/
public class InstantTest {
@Test
public void test1(){
//now():获取对应本初子午线对应的时间
Instant instant = Instant.now();
System.out.println(instant);//2023-01-11T13:34:32.120Z 我们在东八区,需要这个时间加上8小时
//添加时间的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2023-01-11T21:34:32.120+08:00
//toEpochMilli():获取对应的毫秒数 表示自1970年1月1日0时0分0秒(UTC)开始的秒数。
long milli = instant.toEpochMilli();
System.out.println(milli);
//ofEpochMilli():通过给定的毫秒数,获取Instant实例 -->Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1673444476825L);
System.out.println(instant1);//2023-01-11T13:41:16.825Z
OffsetDateTime offsetDateTime1 = instant1.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime1);//2023-01-11T21:41:16.825+08:00
}
/*
DateTimeFormatter:格式化或解析日期、时间
类似于SimpleDateFormat
*/
@Test
public void test2(){
// 方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIM
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化:日期-->字符串
LocalDateTime localDateTime = LocalDateTime.now();
String str1 = formatter.format(localDateTime);
System.out.println(localDateTime);//2023-01-12T19:19:44.357
System.out.println(str1);//2023-01-12T19:19:44.357
//解析:字符串-->日期
TemporalAccessor parse = formatter.parse("2023-01-12T19:19:44.357");
System.out.println(parse);//{},ISO resolved to 2023-01-12T19:19:44.357
// 方式二:本地化相关的格式。如:ofLocalizedDateTime()
//FormatStyle.LONG/FormatStyle.MEDIUM/FormatStyle.SHORT 适用于LocalDateTime
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
//格式化
String str2 = formatter1.format(localDateTime);
System.out.println(str2);//23-1-12 下午7:46
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
System.out.println(formatter2.format(localDateTime));//2023年1月12日 下午07时46分35秒
//本地化相关的格式。如:ofLocalizedDate()
//FormatStyle.FULL/FormatStyle.LONG/FormatStyle.MEDIUM/FormatStyle.SHORT 适用于LocalDate
DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String str3 = formatter3.format(LocalDate.now());
System.out.println(str3);//2023年1月12日 星期四
// 重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
//hh 12小时制 HH 24小时制
DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//格式化
String str4 = formatter4.format(LocalDateTime.now());
System.out.println(str4);//2023-01-12 20:04:15
//解析
TemporalAccessor accessor = formatter4.parse("2023-01-12 20:04:15");
System.out.println(accessor);//{},ISO resolved to 2023-01-12T20:04:15
}
}
全球24个时区,东12区,西十二区
9.3.4 其它API
9.3.5 参考:与传统日期处理的转换
9.4 Java比较器*(重要)
Java实现对象排序的方式有两种:
自然排序:java.lang.Comparable
定制排序:java.util.Comparato
9.4.1 Comparable接口
测试代码:
package com.string.java;
import org.junit.Test;
import java.util.Arrays;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-12 20:27
* @Description: TODO
* @Version: 1.0
*/
/*
一、说明:Java中的对象,正常情况下只能进行比较。 == 或 != 不能使用 > 或 < 的。
但是在开发场景中,我们需要对多个对象进行排序。言外之意就需要比较对象的大小。
如何实现?使用2个接口中的任何一个 comparable或Comparator。
二、Comparable接口的使用
*/
public class CompareTest {
/*
Comparable接口的使用举例: 自然排序
1.像String、包装类等实现了Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方式
2.像String、包装类重写compareTo()方法以后,进行了从小到大的排序
3.重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零。
4.对于自定义类来说,如果需要排序,我们可以让自定义类实现comparable接口,重写CompareTo(obj)方法。
在compareTo(obj)方法中指明如何排序
*/
@Test
public void test1(){
//String实现了Comparable接口
String[] arr = new String[]{"AA","CC","MM","GG","JJ","DD"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));//[AA, CC, DD, GG, JJ, MM]
}
@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));
//[Goods{name='xiaomiMouse', price=12.0}, Goods{name='lenovoMouse', price=34.0},
// Goods{name='dellMouse', price=43.0}, Goods{name='huaweiMouse', price=65.0}],
// Goods{name='microsoftMouse', price=65.0}]
}
}
package com.string.java;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-12 20:48
* @Description: TODO 商品类
* @Version: 1.0
*/
public class Goods implements Comparable{
private String name;
private double price;
public Goods() {
}
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
//指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从低到高排序
@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 this.name.compareTo(goods.name);
}
//方式二:
// return Double.compare(this.price,goods.price);
}
// return 0;
throw new RuntimeException("传入的数据类型不一致!");
}
}
9.4.2 Comparator接口
测试代码
package com.string.java;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
/**
* @BelongsProject: JavaSenior
* @BelongsPackage: com.string.java
* @Author: Yanyang Li
* @CreateTime: 2023-01-12 20:27
* @Description: TODO
* @Version: 1.0
*/
/*
一、说明:Java中的对象,正常情况下只能进行比较。 == 或 != 不能使用 > 或 < 的。
但是在开发场景中,我们需要对多个对象进行排序。言外之意就需要比较对象的大小。
如何实现?使用2个接口中的任何一个 comparable或Comparator。
二、Comparable接口与Comparator的使用的对比:
Comparable:让一个类实现此接口,此方式一旦一定,保证comparable接口实现类的对象在任何位置都可以比较大小。
Comparator:使用时临时创建一种排序方式 属于临时性的比较。
*/
public class CompareTest {
/*
Comparable接口的使用举例: 自然排序
1.像String、包装类等实现了Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方式
2.像String、包装类重写compareTo()方法以后,进行了从小到大的排序
3.重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零。
4.对于自定义类来说,如果需要排序,我们可以让自定义类实现comparable接口,重写CompareTo(obj)方法。
在compareTo(obj)方法中指明如何排序
*/
@Test
public void test1(){
//String实现了Comparable接口
String[] arr = new String[]{"AA","CC","MM","GG","JJ","DD"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));//[AA, CC, DD, GG, JJ, MM]
}
@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));
//[Goods{name='xiaomiMouse', price=12.0}, Goods{name='lenovoMouse', price=34.0},
// Goods{name='dellMouse', price=43.0}, Goods{name='huaweiMouse', price=65.0}],
// Goods{name='microsoftMouse', price=65.0}]
}
/*
Comparator接口的使用:定制排序
1.背景:
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,
或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那
么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排
序的比较。
2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2;
如果返回0,表示相等;
返回负整数,表示o1小于o2。
*/
@Test
public void test3(){
String[] arr = new String[]{"AA","CC","MM","GG","JJ","DD"};
Arrays.sort(arr, 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);
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));//[MM, JJ, GG, DD, CC, AA]
}
@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.getName());
}
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
//[Goods{name='dellMouse', price=43.0},
// Goods{name='huaweiMouse', price=65.0},
// Goods{name='lenovoMouse', price=34.0},
// Goods{name='microsoftMouse', price=65.0},
// Goods{name='xiaomiMouse', price=12.0}]
}
}
9.5 System类
测试代码
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);
9.6 Math类
9.7 BigInteger与BigDecimal
测试代码
public void testBigInteger() {
BigInteger bi = new BigInteger("12433241123");
BigDecimal bd = new BigDecimal("12435.351");
BigDecimal bd2 = new BigDecimal("11");
System.out.println(bi);
// System.out.println(bd.divide(bd2));
System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));
System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP));
}