1.字符串
1.1.String
1.1.1.String特性
代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现;String是一个final类,代表不可变的字符序列,不可被继承;字符串是常量,用""双引号引起来表示。它们的值在创建之后不能更改。
定义字符串:直接定义,用双引号把字符串引起来;引用String类。
// 源码
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 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);
实现Serializable接口:表示字符串支持序列化的,实现了Comparable接口:表示String可以比较大小;String内部定义了final char[] value 用于存储字符串。
String:代表不可变的字符序列。简称:不可变性体现:当对字符串重新赋值是,需要重写指定内存区域赋值,不能使用原有的value进行赋值;当对现有的字符串进行连接操作时,也需要重写指定内存区域赋值,不能使用原有的value进行赋值;当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
通过字面量的方式(区别与new)给一个字符串赋值,此时的字符串值声明在字符串常量池中;字符串常量池中是不会存储相同内容的字符串的。
@Test
public void test1() {
String s1 = "abc";// 字面量
String s2 = "abc";
System.out.println(s1 == s2);// 比较s1和s2的地址值
s1 = "hello";
System.out.println(s1);// hello
System.out.println(s2);// abc
System.out.println("********************");
String s3 = "abc";
s3 += 3;
System.out.println(s3);// abc3
System.out.println(s2);// abc
String s4 = "abc";
String s5 = s4.replace("a","m");
System.out.println(s4);// abc
System.out.println(s5);// mbc
}
// 比较字符串是否相等
String s = "aabb";
s.equals("aabb");
// 忽略字符串的大小写
String s = "aabb";
boolean equals = s.equals("AAbb");// false
boolean equalsIgnoreCase = s.equalsIgnoreCase("AAbb");// true
// 字符串全部转化为大写
String s = "AAbb";
String upperCase = s.toUpperCase();// AABB
// 字符串全部转化为小写
String s = "AAbb";
String lowerCase = s.toLowerCase();// aabb
// 求字符串长度
String s = "AAbb";
int length = s.length();//4
// index of,定位到字符串A在字符串B中首次的位置。若存在,返回位置;若不存在,返回-1;
String s = "thinking in java";
// 查找字符串i第一次出现在s中的位置:
String s = "thinking in java";
int indexOf = s.indexOf("i");// 2
// 查找字符串java在s中的位置;
String s = "thinking in java";
int indexOf = s.indexOf("java");// 12
// 从第4个位置开始查找in在s中的位置:
String s = "thinking in java";
int indexOf = s.indexOf("in",4);// 5
// 从第7个位置查找in在s中的位置:
String s = "thinking in java";
int indexOf = s.indexOf("in",7);// 9
// 查找最后一次出现in的位置:
String s = "thinking in java";
int lastIndexOf = s.lastIndexOf("in");// 9
// 去掉首尾空格
String s = " thinking in java ";
System.out.println(s.length());// 22
s = s.trim();
System.out.println(s.length());// 16;
// 字符串截取,左边包含,右边不包含
String s = "abcdefg";
String s2 = s.substring(2);// cdefg
System.out.println(s2);
String s3 = s.substring(2, 5);// cde
System.out.println(s3);
// 字符串拆分,注意:拆分后是一个数组。
String s = "abc-de-fg";
String[] split = s.split("-");
for (int i = 0; i < split.length; i++) {
System.out.println(split[i]);
}
// 将一切类型转化为字符串
String s1 = String.valueOf(true);
System.out.println(s1);
String s2 = String.valueOf(1234);
System.out.println(s2);
// 查找某个位置的字符
String s= "abcdefg";
char charAt = s.charAt(3);// d
// 将两个字符串进行连接
String s1 = "你好";
String concat = s1.concat("中国");
// 字符替换,将替换成c
String s = "abcdefg";
String replace = s.replace('a', 'c');//cbcdefg
// 判断是否包含
String s = "hello world";
boolean contains = s.contains("o");// true
boolean contains2 = s.contains("a");// false
结论:常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量;只要其中有一个是变量,结果就在堆中;如果拼接的结果调用intern()方法,返回值就在常量池中。
@Test
public void test3() {
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);// true
System.out.println(s3 == s5);// false
System.out.println(s3 == s6);// false
System.out.println(s5 == s6);// false
System.out.println(s7 == s6);// false
String s8 = s5.intern();// 返回值得到的s8使用的常量值中已经存在的”javaEEhadoop“
System.out.println(s3 == s8);// true
}
使用String字符串注意:String s1 = "a";说明:在字符串常量池中创建了一个字面量为"a"的字符串。s1 = s1 + "b";说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+"b"(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。
String s2 = "ab";说明:直接在字符串常量池中创建一个字面量为"ab"的字符串。String s3 = "a" + "b";说明:s3指向字符串常量池中已经创建的"ab"的字符串。String s4 = s1.intern();说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4。
1.1.2.常用方法
方法 | 说明 |
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个,如果超过了,剩下的全部都放到最后一个元素中 |
@Test
public void test1(){
String s1 = "HellWorld";
System.out.println(s1.length());// 9 字符串长度
System.out.println(s1.charAt(0));// h 取字符串的第一个字符,因为存字符是从0开始的
// System.out.println(s1.charAt(9));// 报异常,最大到长度-1
System.out.println(s1.isEmpty());// false,为空时,true,不为空,false
String s2 = s1.toLowerCase();// 大写编小写
System.out.println(s1);// HellWorld,不可变的
System.out.println(s2);// hellworld
String s3 = " he llo world";
String s4 = s3.trim();// 去除首位空格
System.out.println("-------"+s3+"---------");//------- he llo world---------
System.out.println("-------"+s4+"---------");//-------he llo world---------
String s5 = "HellWorld";
String s6 = "hellworld";
System.out.println(s5.equals(s6));// false
System.out.println(s5.equalsIgnoreCase(s6));// true 忽略大小写
System.out.println(s5.concat(s6));// HellWorldhellworld 拼接
System.out.println(s5.compareTo(s6));// -32,比较相减,涉及字符串排序
System.out.println(s5.substring(2));//llWorld,把前两去删除
System.out.println(s5.substring(2,5));//llW,截取包括2不包括5的字符串
String s7 = "helloWorld";
boolean b1 = s7.endsWith("old");// false,判断字符串是否以old结尾
System.out.println(b1);
System.out.println(s7.startsWith("he"));// true,判断字符串是否以he开始
System.out.println(s7.startsWith("ll", 2));// true,判断字符串从2位置开始是否以ll开始
String s8 = "Wo";
System.out.println(s7.contains(s8));// true,s7字符串是否包含s8
System.out.println(s7.indexOf("lo"));// 3,是否找得到lo,从几开始的,找不到返回-1
System.out.println(s7.indexOf("lo",5));// -1,是否找得到lo,从5开始找
System.out.println(s7.lastIndexOf("lo"));// 3,从后往前找是否找得到lo,从几开始的,找不到返回-1
System.out.println(s7.lastIndexOf("lo",5));// 3,从后往前找是否找得到lo,从5开始找
// 什么时候indexOf(str)lastIndexOf(),存在唯一str或不存在str
}
@Test
public void test4() {
String str = "这朵花很棒";
String str1 = str.replace("花", "菌");// 把str中的“花”替换成:菌子“
System.out.println(str);// 这朵花很棒
System.out.println(str1);// 这朵菌很棒
String str2 = str.replace("这朵花", "你很");// 把”这朵花“字符串替换成”你很“字符串
System.out.println(str2);// 你很很棒
System.out.println("_______________________");
String str3 = "12hello34world5java7891mysql456";
//把字符串中的数字替换成,,如果结果中开头和结尾有,的话去掉
// hello,world,java,mysql
String string = str3.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string);
String str4 = "12345";
//判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = str4.matches("\\d+");
System.out.println(matches);
String tel = "0571-4534289";//true
//判断这是否是一个杭州的固定电话
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result);// true
}
String的实例化方法:方式一:通过字面量定义的方式方式二:通过new + 构造器方式。
String s3 = new String("javaEE");方式创建对象,在内存中创建了几个对象?两个:一个堆空间new结构,另一个是char[]对象的常量池中的数据”javaEE“。
@Test
public void test2() {
// 通过字面量定义的方式:此时的s1和s2的数据JavaEE声明在方法区中的字符串常量池中
String s1 = "javaEE";
String s2 = "javaEE";
// 通过new + 构造器的方式:此时的s3和s4保存的是地址值,是数据在堆空间中开辟空间以后对象的地址值
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s3 == s4);//false
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println("*********");
Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 12);
System.out.println(p1.name.equals(p2.name));// true
System.out.println(p1.name == p2.name);// true
p1.name = "Jerry";
System.out.println(p2.name);// Tom
}
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
1.1.3.与基本数据类型互转
字符串转换成基本数据类型、包装类
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)可由参数的相应类型到字符串的转换。
@Test
public void test1(){
String str = "123";
// int num = (int)str;// 错误的
int num = Integer.parseInt(str);//123
String str1 = String.valueOf(num);//"123"
String str2 = num + "";//"123"
}
字符数组转换成字符串
String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
@Test
public void test2(){
// String转换成char,调用String的toCharArray()
//char转换成String,调用String的构造器
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for(char obj:charArray){
System.out.print(obj + "\t");//a b c 1 2 3
}
char[] arr = new char[]{'h','e','l','l','o'};// hello
String s = new String(arr);
System.out.println(s);
}
字符串转换成字符数组
public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法;public void getChars(int srcBegin, int srcEnd, char[] dst,int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
字节数组转换成字符串
String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String;String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象。
@Test
public void test3() throws UnsupportedEncodingException {
// String与byte[]之间的转换
// 调用getBytes方法
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(gbks));// [97, 98, 99, 49, 50, 51, -42, -48, -71, -6]
System.out.println("-------------------");
// 解码。解码时,要注意编码和解码要使用相同的字符集,否则会出现乱码
String str2 = new String(bytes);// 使用默认的字辅子,进行解码
System.out.println(str2);// abc123中国
String s = new String(gbks); // abc123�й�,出现乱码,原因:编码集和解码集不一致
System.out.println(s);
}
字符串转换成字节数组
public byte[] getBytes() :使用平台的默认字符集将此 String 编码为byte 序列,并将结果存储到一个新的 byte 数组中;public byte[] getBytes(String charsetName) :使用指定的字符集将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
String str = "中";
System.out.println(str.getBytes("ISO8859-1").length);// -128~127
System.out.println(str.getBytes("GBK").length);
System.out.println(str.getBytes("UTF-8").length);
System.out.println(new String(str.getBytes("ISO8859-1"),
"ISO8859-1"));// 乱码,表示不了中文
System.out.println(new String(str.getBytes("GBK"), "GBK"));
System.out.println(new String(str.getBytes("UTF-8"), "UTF-8"));
1.2.StringBuffer
java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象;很多方法与String相同;作为参数传递时,方法内部可以改变值。
StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:StringBuffer():初始容量为16的字符串缓冲区;StringBuffer(int size):构造指定容量的字符串缓冲区;StringBuffer(String str):将内容初始化为指定字符串内容。new StringBuffer(int capacity): 创建一个空的缓冲区,容量是capacity;new StringBuffer(String str):创建一个指定内容的字符串缓冲区,容量是 16 + str的⻓度。
String s = new String("我喜欢学习");
StringBuffer buffer = new StringBuffer("我喜欢学习");
buffer.append("数学");
StringBuffer sb1 = new StringBuffer();
StringBuffer sb2 = new StringBuffer(10);
StringBuffer sb3 = new StringBuffer("中国");
System.out.println(sb1.capacity());// 16
System.out.println(sb2.capacity());// 10
System.out.println(sb3.capacity());// 18
1.2.1.StringBuffer类的常用方法
方法 | 说明 |
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 test4(){
// 增append、删delete、改(replace和setCharAt(int n, char ch)、查charAt、插insert、长度length、遍历for+charAt
StringBuffer s = new StringBuffer("abc");
s.append(1);//拼接
s.append("1");//拼接
System.out.println(s);//abc11
s.delete(2,4);// 删除2,4上的字符
System.out.println(s);//ab1
s.replace(2,4,"hello");// 把2到4换成hello
System.out.println(s);//abhello
s.insert(2,false);// 在2的地方插入false
System.out.println(s);//abfalsehello
System.out.println(s.length());//12
s.substring(1,3);
System.out.println(s);
// 1.deleteCharAt()
StringBuffer sb = new StringBuffer("She");
sb.deleteCharAt(2);
System.out.println(sb);// Sh
}
// 练习
public static void main(String[] args) {
StringBuffer sys = new StringBuffer("《系内课程管理》") ;
System.out.println("欢迎来到 " + sys + "系统");
StringBuffer courseName = new StringBuffer();//课程名称
System.out.println("请输入五⻔必修课程的名称:");
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 5; i++) {
String name = sc.next();
courseName.append(name + " ");
if ( i == 4) {
System.out.println("录入完毕!");
}
}
System.out.println("本学期的必修课程有:");
System.out.println(courseName);
}
当append和insert时,如果原来value数组长度不够,可扩容。StringBuffer类的常用方法:
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)
// 替换字符
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("hello");
sb.setCharAt(1, 'E');
System.out.println(sb);// hEllo
sb.setCharAt(0, 'H');
System.out.println(sb);// HEllo
}
// 反转字符串
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("你好中国");
sb.reverse();
System.out.println(sb);// 国中好你
}
1.3.StringBuilder
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样。
注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder会改变其值。
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));
1.4.三个字符串异同
可变性:String 类中使用 final 关键字字符数组保存字符串,所以String对象是不可变的。而 StringBuilder 与StringBuffer 都继承自 AbstractStringBuilder 类,在AbstractStringBuilder 中也是使用字符数组保存字符串,没有用 final 关键字修饰,所以这两种对象都是可变的。
// 源码
AbstractStringBuilder.java
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
线程安全性:String 中的对象是不可变的,也就可以理解为常量,线程安全。StringBuilder 与 StringBuffer 有公共父类,但是StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
性能:每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新
的对象并改变对象引用。但是相同情况下StirngBuilder 比StringBuffer 更高的性能,但却要冒多线程不安全的风险。
// 源码
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
对于三者使用的总结:操作少量的数据 = String;单线程操作字符串缓冲区下操作大量数据 = StringBuilder;多线程操作字符串缓冲区下操作大量数据 = StringBuffer。
1.5.字符串的一些算法题
public class StringDemo {
public static void main(String[] args) {
StringDemo stringDemo = new StringDemo();
String s = "abcdefg";
System.out.println(stringDemo.reverse(s, 2, 6));// abgfedc
String a = "abkkcabkebfkabkskab";
String str = "ab";
System.out.println(stringDemo.getCount(a, str));// 4
System.out.println(stringDemo.getMaxSameString("abcwerthelloyuiodefabcdef","cbhellobnm"));// hello
}
// 将一个字符串进行反转。将字符串指定部分进行反转。比如“abcdefg”反转为“adfedcg”
public String reverse(String str, int startIndex, int endIndex) {
if (str != null || str.length() != 0) {
char[] arr = str.toCharArray();
for (int x = startIndex, y = endIndex; x < y; x++, y--) {
char temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
return new String(arr);
} else {
return "-1";
}
}
// 获取一个字符串在另一个字符串中出现的次数,比如“ab”在“abkkcabkebfkabkskab”中出现的次数
// 获取subStr在mainStr中出现的次数
public int getCount(String mainStr, String subStr) {
int mainLength = mainStr.length();
int subLength = subStr.length();
int count = 0;
int index = 0;
if (mainLength >= subLength) {
// while ((index = mainStr.indexOf(subStr)) != -1){
// count++;
// mainStr = mainStr.substring(index + subStr.length());
// }
// 方式二改进
while ((index = mainStr.indexOf(subStr, index)) != -1) {
count++;
index += subLength;
}
return count;
} else {
return 0;
}
}
// 获取两个字符串中最大相同字串。比如
// str1 = "abcwerthelloyuiodefabcdef";str2 = "cbhellobnm"
// 将短的那个串进行长度一次递减的字串与较长的串比较,只有一个最大字符串
public String getMaxSameString(String str1, String str2) {
String maxStr = (str1.length() >= str2.length())? str1: str2;
String minStr = (str1.length() < str2.length())? str1: str2;
for (int i = 0;i < minStr.length();i++){
for(int x = 0,y = minStr.length() -i;y <= minStr.length();x++,y++){
String subStr = minStr.substring(x,y);
if (maxStr.contains(subStr)) {
return subStr;
}
}
}
return null;
}
}
1.6.字符串练习
输入一个电话号码,判断是否正确。如果正确,判断是座机还是手机。思路:座机:010-1234567 或者 0476-1234567;手机:1XX12345678。
public static void main(String[] args) {
// 010-1234567
System.out.println("请输入号码:");
Scanner sc = new Scanner(System.in);
String number = sc.next();
if (number.contains("-")) {//座机
String[] split = number.split("-");
if ( (split[0].length() == 3 || split[0].length() == 4) &&
split[1].length() == 7) {
System.out.println("合法的座机号!");
}else {
System.out.println("不合法的座机号!");
}
}else {//手机
String first = number.substring(0,1);
if (first.equals("1") && number.length() == 11) {
System.out.println("合法的手机号");
}else {
System.out.println("不合法的手机号");
}
}
}
// 模拟一个trim方法,去除字符串两端的空格。
// 第1题
public String myTrim(String str) {
if (str != null) {
int start = 0;// 用于记录从前往后首次索引位置不是空格的位置的索引
int end = str.length() - 1;// 用于记录从后往前首次索引位置不是空格的位置的索引
while (start < end && str.charAt(start) == ' ') {
start++;
}
while (start < end && str.charAt(end) == ' ') {
end--;
}
if (str.charAt(start) == ' ') {
return "";
}
return str.substring(start, end + 1);
}
return null;
}
// 对字符串中字符进行自然顺序排序。"abcwerthelloyuiodef"提示:
//字符串变成字符数组;对数组排序,选择,冒泡,Arrays.sort(str.toCharArray());
//将排序后的数组变成字符串
// 第5题
@Test
public void testSort() {
String str = "abcwerthelloyuiodef";
char[] arr = str.toCharArray();
Arrays.sort(arr);
String newStr = new String(arr);
System.out.println(newStr);
}
2.日期
2.1JDK8之前日期时间API
2.1.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)。
@Test
public void test(){
long time = System.currentTimeMillis();
// 返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
// 称为时间戳
System.out.println(time);// 1669222748002
}
2.1.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是时间标准。
import java.util.Date;
Date date = new Date();
System.out.println(date);
System.out.println(System.currentTimeMillis());
System.out.println(date.getTime());
Date date1 = new Date(date.getTime());
System.out.println(date1.getTime());
System.out.println(date1.toString());
java.util.Data类
-----java.sql.Data类
1.两个构造器的使用
构造一:Data():创建一个对应当前时间的Date()对象
构造器二:创建指定毫秒数Date()对象
2.两个方法的使用
toString():显示当前的年、月、日、时分秒
getTime():返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差(时间戳)
java.sql.Data类对应着数据库中的日期类型的遍历
如何实例化;util.Date转换成sql.Date
@Test
public void test1(){
// 构造一:Data()
Date date1 = new Date();
System.out.println(date1.toString());//Thu Nov 24 01:04:27 CST 2022
System.out.println(date1.getTime());//1669223167493
// 构造器二
Date date2 = new Date(1669223167493L);
System.out.println(date2);//Thu Nov 24 01:06:07 CST 2022
// 创建java.sql.Date对象
java.sql.Date date3 = new java.sql.Date(5845658548554L);
System.out.println(date3);//2155-03-30
// util.Date转换成sql.Date
// 情况一
Date date4 = new java.sql.Date(5845658548554L);
java.sql.Date date5 = (java.sql.Date)date4;
// 情况二
Date date6 = new Date();
java.sql.Date date7 = new java.sql.Date(date6.getTime());
}
2.1.3. java.text.SimpleDateFormat类
Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类;它允许进行格式化:日期-》文本、解析:文本-》日期
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
// JDK8之前日期API测试
// System类中currentTimeMillis();
// java.util.Data和子类java.sql.Data
// SimpleDateFormat和Calendar
public class TimeTest {
/*
SimpleDateFormat的使用:SimpleDateFormat对日期Date类的格式化和解析
1.两个操作:
格式化:日期--》字符串
解析:格式化逆过程,字符串--》日期
SimpleDateFormat的实例化
*/
@Test
public void testSimpleDateFormat() throws ParseException {
// 实例化SimpleDateFormat,使用默认构造器
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
// 格式化日期--》字符串
Date date = new Date();
System.out.println(date);//Fri Nov 25 20:17:52 CST 2022
String format = simpleDateFormat.format(date);
System.out.println(format);//22-11-25 下午8:17
// 解析:格式化的逆过程:字符串--》日期
String str = "22-11-25 下午8:17";
Date date1 = simpleDateFormat.parse(str);
System.out.println(date1);// Fri Nov 25 20:17:00 CST 2022
// SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy.MMMMM.dd GGG hh:mm aaa");
// 按照指定的方法格式化和解析:调用带参的构造器
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
// 格式化
String sdf = simpleDateFormat1.format(date);
System.out.println(sdf);// 2022-11-25 08:27:22
// 解析:要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现),否则抛异常
Date date2 = simpleDateFormat1.parse("2022-11-25 08:27:22");
System.out.println(date2);// Fri Nov 25 08:27:22 CST 2022
}
}
格式化:
SimpleDateFormat() :默认的模式和语言环境创建对象
public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用:
public String format(Date date):方法格式化时间对象date
解析:
public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。
Date date = new Date(); // 产生一个Date实例
// 产生一个formater格式化的实例
SimpleDateFormat formater = new SimpleDateFormat();
System.out.println(formater.format(date));// 打印输出默认的格式
SimpleDateFormat formater2 = new SimpleDateFormat("yyyy年MM月dd日 EEE HH:mm:ss");
System.out.println(formater2.format(date));
try {
// 实例化一个指定的格式对象
Date date2 = formater2.parse("2008年08月08日 星期一 08:08:08");
// 将指定的日期解析后格式化按指定的格式输出
System.out.println(date2.toString());
} catch (ParseException e) {
e.printStackTrace();
}
// 字符串”2020-02-25“转换成java.sql.Date
@Test
public void testExer() throws ParseException {
String birth = "2020-02-25";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(birth);
java.sql.Date birthDate = new java.sql.Date(date.getTime());
System.out.println(birthDate);
}
2.1.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。
@Test
public void testCalendar(){
// 实例化,方式一:创建子类(GregorianCalendar)的对象
// 方式二:调用其静态方法getInstance();
Calendar calendar = Calendar.getInstance();
//常用方法,get
int days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);//现在是当月的第几天
// set
calendar.set(Calendar.DAY_OF_MONTH,22);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);//set设置今天是当月第22天,输出22
// add
calendar.add(Calendar.DAY_OF_MONTH,3);//在当月今天上加三天
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);// 之前设置为22,加三为25
// getTime:日历类--》Date
Date date = calendar.getTime();
System.out.println(date);//Fri Nov 25 23:43:33 CST 2022
//setTime:Date--->日历类
Date date1 = new Date();
calendar.setTime(date1);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);// 26
Calendar calendar = Calendar.getInstance();
// 从一个 Calendar 对象中获取 Date 对象
Date date = calendar.getTime();
// 使用给定的 Date 设置此 Calendar 的时间
date = new Date(234234235235L);
calendar.setTime(date);
calendar.set(Calendar.DAY_OF_MONTH, 8);
System.out.println("当前时间日设置为8后,时间是:" + calendar.getTime());
calendar.add(Calendar.HOUR, 2);
System.out.println("当前时间加2小时后,时间是:" + calendar.getTime());
calendar.add(Calendar.MONTH, -2);
System.out.println("当前日期减2个月后,时间是:" + calendar.getTime());
}
2.2.JDK中新日期时间API
JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。他们面临的问题有:可变性:像日期和时间这样的类应该是不可变的;偏移性:Date中的年份是从1900开始的,而月份都从0开始;格式化:格式化只对Date有用,Calendar则不行;此外,它们也不是线程安全的;不能处理闰秒等。
// 偏移量
Date date = new Date(2020 - 1900, 9 - 1, 8);//2020-9-8
System.out.println(date);//Tue Sep 08 00:00:00 CST 2020
2.2.1.新时间日期API
Java 8引入的java.time API 已经纠正了过去的缺陷。是一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。
java.time – 包含值对象的基础包
java.time.chrono – 提供对不同的日历系统的访问
java.time.format – 格式化和解析时间和日期
java.time.temporal – 包括底层框架和扩展特性
java.time.zone – 包含时区支持的类说明:大多数开发者只会用到基础包和format包,也可能会用到temporal包。因此,尽管有68个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期;LocalTime表示一个时间,而不是日期;LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
方法 | 描述 |
now() / * now(ZoneId zone) | 静态方法,根据当前时间创建对象/指定时区的对象 |
of() | 静态方法,根据指定日期/时间创建对象 |
getDayOfMonth()/getDayOfYear() | 获得月份天数(1-31) /获得年份天数(1-366) |
getDayOfWeek() | 获得星期几(返回一个 DayOfWeek 枚举值) |
getMonth() | 获得月份, 返回一个 Month 枚举值 |
getMonthValue() / getYear() | 获得月份(1-12) /获得年份 |
getHour()/getMinute()/getSecond() | 获得当前对象对应的小时、分钟、秒 |
withDayOfMonth()/withDayOfYear()/withMonth()/withYear() | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象 |
plusDays(), plusWeeks(),plusMonths(), plusYears(),plusHours() | 向当前对象添加几天、几周、几个月、几年、几小时 |
minusMonths() / minusWeeks()/ minusDays()/minusYears()/minusHours() | 从当前对象减去几月、几周、几天、几年、几小时 |
@Test
public void test1(){
// LocalDate、LocalTime、LocalDateTime的使用
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);// 2022-11-26
System.out.println(localTime);// 00:39:27.019
System.out.println(localDateTime);// 2022-11-26T00:39:27.019
// of();设置指定的年、月、日、时分秒,没有偏移量
LocalDateTime of = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
System.out.println(of);// 2020-10-06T13:23:43
// getXxx:获取相关的属性
System.out.println(localDateTime.getDayOfMonth());// 26
System.out.println(localDateTime.getDayOfWeek());// SATURDAY
System.out.println(localDateTime.getMonth());// NOVEMBER
System.out.println(localDateTime.getMonthValue());// 11
System.out.println(localDateTime.getMinute());// 48
// 体现不可变性
// withXxx:设置相关的熟悉
LocalDate localDate1 = localDate.withDayOfMonth(22);
System.out.println(localDate); // 2022-11-26
System.out.println(localDate1);// 2022-11-26
LocalDateTime localDateTime1 = localDateTime.withHour(4);
System.out.println(localDateTime);// 2022-11-26T00:54:43.321
System.out.println(localDateTime1);// 2022-11-26T04:54:43.321
// 体现不可变性
LocalDateTime localDateTime2 = localDateTime.plusMinutes(3);
System.out.println(localDateTime);// 2022-11-26T00:58:36.893
System.out.println(localDateTime2);// 2022-11-26T01:01:36.893
LocalDateTime localDateTime3 = localDateTime.minusDays(6);
System.out.println(localDateTime);// 2022-11-26T00:58:36.893
System.out.println(localDateTime3);// 2022-11-20T00:58:36.893
}
2.2.2.瞬时:Instant(时间戳)
Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位;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纳秒。
方法 | 描述 |
now() | 静态方法,返回默认UTC时区的Instant类的对象 |
ofEpochMilli(long epochMilli) | 静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象 |
atOffset(ZoneOffset offset) | 结合即时的偏移来创建一个 OffsetDateTime |
toEpochMilli() | 返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳 |
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
// Instant的使用,类似于java.util.Date类
@Test
public void test2(){
// now():获取本初子午线的标准时间
Instant instant = Instant.now();
System.out.println(instant);// 2022-11-25T17:05:06.488Z,时区问题
// 添加时间的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));// 东八区加8小时
System.out.println(offsetDateTime);// 2022-11-26T01:07:18.997+08:00
// toEpochMilli:获取字1970年1月1日0时0分0秒(UTC)开始的毫秒数
long milli = instant.toEpochMilli();
System.out.println(milli);// 1669396270107
// ofEpochMilli:通过给定的毫秒数,获取Instant实例--》Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1669396270107L);
System.out.println(instant1);// 2022-11-25T17:11:10.107Z
}
2.2.3.格式化与解析日期或时间
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME;本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG);自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
方法 | 描述 |
ofPattern(String pattern) | 静 态 方 法 , 返 回 一 个 指 定 字 符 串 格 式 的DateTimeFormatter |
format(TemporalAccessor t) | 格式化一个日期、时间,返回字符串 |
parse(CharSequence text) | 将指定格式的字符序列解析为一个日期、时间 |
//DateTimeFormatter:格式化活日期解析、时间,类似于SimpleDateFormat
@Test
public void test3(){
// 方式一:预定义的标准格式。如:IOS_LOCAL_DATE_TIME;IOS_LOCAL_DATE_TIME
// 格式化:日期--字符串
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
String str1 = formatter.format(localDateTime);
System.out.println(localDateTime);// 2022-11-26T11:39:53.472
System.out.println(str1);// 2022-11-26T11:39:53.472
// 解析
TemporalAccessor parse = formatter.parse("2022-11-26T11:39:53.472");
System.out.println(parse);// {},ISO resolved to 2022-11-26T11:39:53.472
// 方式二:本地化相关的格式。如:ofLocalizeDateTime(FormatStyle.LONG)
// FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
// 格式化
String str2 = formatter1.format(localDateTime);
System.out.println(str2);// 22-11-26 上午11:49
// 本地化相关的格式。如:ofLocalizedDate
// FormatStyle.FULL / FormatStyle.LONE / FormatStyle.MEDIUM / FormatStyle.SHORT:适用于LocalDate
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String str3 = formatter2.format(LocalDate.now());
System.out.println(str3);// 2022年11月26日 星期六
// 方式三:自定义的格式。如ofPattern("yyyy-MM-dd hh:mm:ss E")
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
// 格式化
String str4 = formatter3.format(LocalDateTime.now());
System.out.println(str4);// 2022-11-26 11:55:49
// 解析
TemporalAccessor parse1 = formatter3.parse("2022-11-26 11:55:49");
System.out.println(parse1);// {SecondOfMinute=49, NanoOfSecond=0, MicroOfSecond=0, HourOfAmPm=11, MinuteOfHour=55, MilliOfSecond=0},ISO resolved to 2022-11-26
}
2.2.4.其他API
方法 | 描述 |
ZoneId | 该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris |
ZonedDateTime | 一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如: Asia/Shanghai等 |
Clock | 使用时区提供对当前即时、日期和时间的访问的时钟 |
持续时间:Duration | 用于计算两个“时间”间隔 |
日期间隔:Period | 用于计算两个“日期”间隔 |
TemporalAdjuster | 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作 |
TemporalAdjusters | 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现 |
//ZoneId:类中包含了所有的时区信息
// ZoneId的getAvailableZoneIds():获取所有的ZoneId
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String s : zoneIds) {
System.out.println(s);
}
// ZoneId的of():获取指定时区的时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(localDateTime);
//ZonedDateTime:带时区的日期时间
// ZonedDateTime的now():获取本时区的ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
// ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime1);
/Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
LocalTime localTime = LocalTime.now();
LocalTime localTime1 = LocalTime.of(15, 23, 32);
//between():静态方法,返回Duration对象,表示两个时间的间隔
Duration duration = Duration.between(localTime1, localTime);
System.out.println(duration);
System.out.println(duration.getSeconds());
System.out.println(duration.getNano());
LocalDateTime localDateTime = LocalDateTime.of(2016, 6, 12, 15, 23, 32);
LocalDateTime localDateTime1 = LocalDateTime.of(2017, 6, 12, 15, 23, 32);
Duration duration1 = Duration.between(localDateTime1, localDateTime);
System.out.println(duration1.toDays());
9.3 JDK8中新日期时间API
//Period:用于计算两个“日期”间隔,以年、月、日衡量
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = LocalDate.of(2028, 3, 18);
Period period = Period.between(localDate, localDate1);
System.out.println(period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
Period period1 = period.withYears(2);
System.out.println(period1);
// TemporalAdjuster:时间校正器
// 获取当前日期的下一个周日是哪天?
TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDateTime localDateTime = LocalDateTime.now().with(temporalAdjuster);
System.out.println(localDateTime);
// 获取下一个工作日是哪天?
LocalDate localDate = LocalDate.now().with(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate date = (LocalDate) temporal;
if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
return date.plusDays(3);
} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
return date.plusDays(2);
} else {
return date.plusDays(1);
}
}
});
System.out.println("下一个工作日是:" + localDate);
2.2.5.Duration 和 Period
Duration:用于计算两个“时间”间隔;Period:用于计算两个“日期”间隔。
2.2.6.日期的操纵
TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作;TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。
LocalDate nextSunday = LocalDate.now().with(
TemporalAdjusters.next(DayOfWeek.SUNDAY)
);
2.2.7.解析与格式化
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:预定义的标准格式;语言环境相关的格式;自定义的格式。
2.2.8.时区的处理
Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime。其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式例如 :Asia/Shanghai 等。
ZoneId:该类中包含了所有的时区信息;getAvailableZoneIds() : 可以获取所有时区时区信息;of(id) : 用指定的时区信息获取ZoneId 对象。
2.2.9.与传统日期处理的转换
类 | To遗留类 | From遗留类 |
java.time.Instant与java.util.Date | Date.from(instant) | date.toInstant() |
java.time.Instant与java.sql.Timestamp | Timestamp.from(instant) | timestamp.toInstant() |
java.time.ZonedDateTime与 java.util.GregorianCalendar | GregorianCalendar.from(zonedDateTime) | cal.toZonedDateTime() |
java.time.LocalDate与java.sql.Time | Date.valueOf(localDate) | date.toLocalDate() |
java.time.LocalTime与java.sql.Time | Date.valueOf(localDate) | date.toLocalTime() |
java.time.LocalDateTime与 java.sql.Timestamp | Timestamp.valueOf(localDateTime) | timestamp.toLocalDateTime() |
java.time.ZoneId与java.util.TimeZone | Timezone.getTimeZone(id) | timeZone.toZoneId() |
java.time.format.DateTimeFormatter与java.text.DateFormat | formatter.toFormat() | 无 |
在java.util包下,有Date类和Calender类都可以处理日期和时间;Date:封装了系统的日期和时间信息;calender:根据系统的日历来解释Date对象。
Date:表示系统特定的时间戳,精确到毫秒。①构造方法:Date():获取本地的当前时间;Date(long d):从1970年1月1日(GMT :格林尼治时间)开始经过d的毫秒数。CST : 中央标准时间 (中国标准时间)
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);// Tue Jul 21 15:24:37 CST 2020
Date date2 = new Date(60000);
System.out.println(date2);// Thu Jan 01 08:01:00 CST 1970
}
②常用方法:boolean after(Date when) 判断此日期是否在指定日期之后;
boolean before(Date when) 判断此日期是否在指定日期之前;long getTime() 返回1970-1-1 到现在的毫秒数;int compare(Date date) 比较两个日期的顺序;equal(Object obj) 比较两个日期的相等性。
// 设定一个做某事的时间,然后判断该事件有没有完成
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入要做的事情:");
String titil = sc.next();
Date date1 = new Date(12243214525345L);
System.out.println(date1 + "时刻要去" + titil);
Date now = new Date();//此时的时间
System.out.println("现在时刻:" + now);
if (now.before(date1)) {//事情还没做
System.out.println( (date1.getTime() - now.getTime())/1000 + "秒后需要去完成" + titil + "事情!");
}else {
System.out.println(titil + "这件事已经过去了" + (now.getTime() -
date1.getTime())/1000 + "秒");
}
}
Calender:calender可以通过getInstance()方法来获取对象。①获取当前时间;②设置指定时间;③获取当前时间的某个字段;④给时间做加减法:add方法,正数表示加,负数表示减;⑤时间比较:比较两个calender对象表示的时间值,大则返回1,小则返回-1,相等则返回0;
// calender可以通过getInstance()方法来获取对象
Calendar c = Calendar.getInstance();//获取calender对象
// 获取当前时间
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
Date now = c.getTime();// 获取当前日期对象
System.out.println(now);// Tue Jul 21 16:08:41 CST 2020
long timeInMillis = c.getTimeInMillis();// 获取当前时间的毫秒数
System.out.println(timeInMillis);// 1595318921729
}
// 设置指定时间
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, 2008);//设置年份
System.out.println(c.getTime());//Mon Jul 21 16:12:07 CST 2008
c.set(Calendar.MONTH, 4);//设置月份
System.out.println(c.getTime());//Wed May 21 16:13:50 CST 2008
c.set(2014, 5, 1);//设置年月日
System.out.println(c.getTime());//Sun Jun 01 16:15:47 CST 2014
c.set(2010, 2, 23, 8, 10,30);//设置年月日时分秒
System.out.println(c.getTime());//Tue Mar 23 08:10:30 CST 2010
}
// 获取当前时间的某个字段
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);//获取年份
int month = c.get(Calendar.MONTH) + 1;//获取月份
int date = c.get(Calendar.DATE);//获取日期
int hour = c.get(Calendar.HOUR_OF_DAY);//获取小时(24计时法)
int min = c.get(Calendar.MINUTE);//获取分钟
int second = c.get(Calendar.SECOND);//获取秒钟
int week = c.get(Calendar.DAY_OF_WEEK);//获取星期
System.out.println(year);
System.out.println(month);
System.out.println(date);
System.out.println(hour);
System.out.println(min);
System.out.println(second);
System.out.println(week);
}
// 给时间做加减法,add方法: 正数表示加,负数表示减
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, 10);//向后推10天
System.out.println(c.getTime());
c.add(Calendar.DAY_OF_MONTH, -10);//提前10天
// 时间比较,比较两个calender对象表示的时间值,大则返回1,小则返回-1,相等则返回0
public static void main(String[] args) {
Calendar now = Calendar.getInstance();//当前日期
Calendar c2 = Calendar.getInstance();
c2.add(Calendar.DAY_OF_MONTH, 10);//十天后的日期
int compareTo = now.compareTo(c2);
System.out.println(compareTo);// 1
}
日期格式化:SimpleDateFormat类可以实现日期格式化;构造方法:SimpleDateFormat(String pattern)。
public static void main(String[] args) throws ParseException {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //指定日期格式
String format = sdf.format(now);//日期对象--> 字符串对象
System.out.println(format);
Date parse = sdf.parse("2008-10-01 12:23:45");// 字符串对象 -- > 日期对象
System.out.println(parse);
}
习题:获取两个日期相差的天数
public static void main(String[] args) throws ParseException {
Test test = new Test();
int a = test.getTwoDay("2020-04-05","2020-04-25");
System.out.println(a);
}
// sj1和sj2 相差的天数
public int getTwoDay(String sj1 , String sj2) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse(sj1);
Date date2 = sdf.parse(sj2);
int day = (int)((date2.getTime() - date1.getTime())/ (1000*3600*24));
return day;
}