B站视频指路:尚硅谷Java入门视频教程(在线答疑+Java面试真题)_哔哩哔哩_bilibili
写在前面:马上秋招,打算从0开始再学一遍Java,开个知识点记录贴,就当做课堂笔记吧.
希望秋招顺利.
String的特性
·String类:代表字符串.Java程序中的所有字符串字面值(如:"abc")都作为此类实现.
·String是一个final类,代表不可改变的字符序列 不可以被继承
·字符串是常量,用双引号引起来表示.它们的值在创建之后不能更改
tips:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能原有value进行赋值
2.当对现有字符串进行+=连接操作时也需要重写指定内存区域赋值,不能原有value进行赋值(String s="abc" s+="ef");
3.当调用String的replace()修改指定的字符或字符串时,需要重写指定内存区域赋值,不能原有value进行赋值
·String对象的字符内容是存储在一个字符数组value[]中的
·String实现了Serializable接口:表示字符串是支持序列化的
·String实现了Comparable接口:表示String可以比较大小
·String内部定义了final char[]value用于存储字符串数据
·String不是基本数据类型 String s = " "是属于字面量的定义方式
·通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
·String s1="1",String s2="1" (s1==s2 true)比较的是s1和s2的地址值,s1和s2指向的地址是同一个 即 两个new的对象 指向方法区内相同的地址
·字符串常量池中不会同时存储两个相同内容的字符串
String对象的创建
1.String s = "hello";//通过字面量定义:此时的hello声明在方法区中的字符串常量池中
2.String s = new String();//本质上是this.value=new char[0];
3.String s = new String(char[] a);//this.value=original.value;
4.String s = new String(char[] a,int startIndex,intcount)
//this.value=Arrays.copyOf(value,value.length);
问:String str1 = "abc"与String str2 = new String("abc")的区别?
例1:
String str1 = "abc" String str2 = "abc"
//通过字面量定义:此时的abc声明在方法区中的字符串常量池中 所以 s1==s2 true;
String str3 = new String("abc") String str4 = new String("abc")
//通过new+构造器的方式,此时的abc保存的地址值,是数据在堆空间中开辟空间以后对应的地址值
s3==s4 false; s1==s3 false; s1和s3比较的是堆的地址值 一个是1234 一个是3456 所以false但是堆中的value存储的其实也是常量池中abc的地址1234
例2:
例3:字符串对象是如何存储的
tips:这里都是字面量赋值 所以true
P p1 = new P("1");//字面量赋值
P p2 = new P(new String("1"));//new+构造器
面试题:
String s = new String("abc");方式创建对象,在内存中创建了几个对象?
两个:1.堆空间中new的结构2.char[]对应的常量池中的数据"abc"
String不同拼接操作对比
public class StringTest { @Test public void test1(){ String s1 = "JavaEE"; String s2 = "hadoop"; String s3 = "JavaEEhadoop";//3和4都是字面量 都在常量池 String s4 = "JavaEE"+"hadoop";//4、5、6、7都有变量 所以需要在堆空间 String s5 = s1+"hadoop"; String s6 = "JavaEE"+s2; String s7 = s1+s2; String s8 = s5.intern();//返回值得到的s8使用的常量值中已经存在的jh 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 System.out.println(s4 == s8);//TRUE } }
结论:
·常量与常量的拼接结果在常量池.且常量中不会存在相同内容的常量
·只要其中有一个是变量、结果就在堆中
·如果拼接的结果调用intern(),返回值就在常量池中
练习:
1.
2. ans: good and best
str把地址传递给形参str 现在都指向常量池中的good 此时对形参str重新赋值 那么形参str 会重新指向常量池中的test ok 不会影响原来的str 即: 当对字符串重新赋值时,需要重写指定内存区域赋值,不能原有value进行赋值
String的常用方法1:
import org.junit.Test; import java.util.Locale; public class StringMethod1Test { @Test public void test(){ String s1 = "zhangke"; String s2 = "TJW"; String s3 = " TJW z h a ng k e "; String s4 = "ziangkf"; String s5 = "zhangkeeeeee"; System.out.println(s1.length());//返回字符串的长度 return value.length System.out.println(s1.charAt(0));//返回某索引处的字符 return value[index] System.out.println(s1.isBlank());//判断是否是空字符串 return value.length==0 System.out.println(s2.toLowerCase(Locale.ROOT));//使用默认语言环境 将String中所有的字符转为小写 s2本身没变 还是大写 是新建了一个 体现不可变性 System.out.println(s2);//使用默认语言环境 将String中所有的字符转为小写 s2本身没变 还是大写 是新建了一个 体现不可变性 System.out.println(s1.toUpperCase(Locale.ROOT));//使用默认语言环境 将String中所有的字符转大写 s1本身没变 还是小写 System.out.println("---"+s3+"---");//返回字符串的副本 忽略前导和尾部空白 System.out.println("---"+s3.trim()+"---"); System.out.println(s1.equals(s4));//比较字符串的内容是否相同 System.out.println(s1.equalsIgnoreCase(s4));//比较字符串的内容是否相同 且忽略大小写 System.out.println(s1.concat(s2));//将制定字符串连接到此字符串的结尾 等价于用"+" System.out.println(s1.compareTo(s2));//比较两个字符串的大小 涉及到字符串排序 /* 核心思想就是先取俩字符串公共长度lim,后面开始对每一位字符进行比较只要某一位不同了则返回其字符的unicode值的差; 假如公共长度部分全都一样,则返回俩字符串长度差。例如对于"abc"和"abcde"会返回-2。 */ System.out.println(s1.substring(3));//返回一个字符串 它是以字符串的从beginIndex开始截取 System.out.println(s1.substring(3,5));//返回一个字符串 它是以字符串的从beginIndex开始截取 endIndex结束 左闭右开 } }
String的常用方法2:
import org.junit.Test; import java.util.Locale; public class StringMethod1Test { @Test public void test(){ String s1 = "zk"; String s2 = "zhangke"; String s3 = "zheaneeegke"; System.out.println(s1.endsWith("s"));//测试此字符串是否以指定的后缀结束 System.out.println("----------"); System.out.println(s1.endsWith("k")); System.out.println("----------"); System.out.println(s2.startsWith("zhang"));//测试此字符串是否以指定的前缀开始 System.out.println("----------"); System.out.println(s2.startsWith("asfdsdf")); System.out.println("----------"); System.out.println(s2.startsWith("ang", 2));//测试此字符串从指定索引开始的子字符串是否以指定的前缀开始 System.out.println("----------"); System.out.println(s1.contains("zhang"));//当且仅当此字符串包含指定的char值序列时,返回true System.out.println("----------"); System.out.println(s2.contains("zhang")); System.out.println("----------"); System.out.println(s1.indexOf("z"));//返回指定字符串在此字符串中第一次出现处的索引 System.out.println("----------"); System.out.println(s3.indexOf("e")); System.out.println("----------"); System.out.println(s3.indexOf("e", 3));//返回指定字符串在此字符串中第一次出现处的索引,从指定的索引开始 System.out.println(s3.lastIndexOf("e"));//返回指定字符串在此字符串中最右边出现处的索引 System.out.println("----------"); System.out.println(s3.lastIndexOf("e",9));//返回指定字符串在此字符串中最后一次出现处的索引 从指定的索引开始反向搜索 //indexOf和lastIndexOf方法如果未找到都是返回-1 } }
String的常用方法3:
import org.junit.Test; public class StringMethod1Test { @Test public void test(){ String s1 = "zk"; String s2 = "zhangke"; System.out.println(s2.replace('a', 'y'));//返回一个新的字符串.它是通过用newchar替换此字符串中出现的所有oldchar得到的 //不会改变原来的字符串 而是得到一个新串 System.out.println(s2); System.out.println(s2.replace("ang", "tj"));//使用指定的字面值替换序列来替换此字符串中所有匹配字面值目标序列的子字符串 //通俗的讲 上面那个是替换单个字符 下面这个是字符串 System.out.println(s2); } }
String类与其它结构之间的转换
1. String与基本数据类型、包装类之间的转换
import org.junit.Test; public class StringTransferTest { /* String--->基本数据类型、包装类:调用包装类的静态方法:parseXxx @test1 基本数据类型、包装类--->String:调用String重载的valueof(Xxx) @test2 */ @Test public void test1(){ String s1 = "123"; int num1= Integer.parseInt(s1); System.out.println(num1); } @Test public void test2(){ int num1 = 123; String s1 = String.valueOf(num1); String s3 = num1+"";//这样也行 System.out.println(s1); } }
2. String与char[ ]之间的转换
import org.junit.Test; public class StringTransferTest { /* String与基本数据类型、包装类之间的转换 String--->char[]:调用String的toCharArray() @test1 char[]--->String:调用String的构造器 @test2 */ @Test public void test1(){ String s1 = "abc123"; char[] charS1 = s1.toCharArray(); for (int i = 0; i < charS1.length; i++) { System.out.println(charS1[i]); } } @Test public void test2(){ char[] arr = new char[]{'z','h','a','n','g'}; String s = new String(arr); System.out.println(s); } }
2. String与byte[ ]之间的转换
import org.junit.Test; import java.nio.charset.StandardCharsets; public class StringTransferTest { /* String与基本数据类型、包装类之间的转换 编码:String--->byte[]字符串->字节:调用String的getBytes() @test1 解码:byte[]--->String字节->字符串:调用String的构造器 @test2 编码解码需要用一样的编码字符集 */ @Test public void test1(){ String s1 = "abc123"; byte[] byteS1 = s1.getBytes();//使用默认的字符集进行编码 for (int i = 0; i < byteS1.length; i++) { System.out.println(byteS1[i]); } } @Test public void test2(){ byte[] arr = new byte[]{97,98,99,100,101}; String s = new String(arr);//使用默认的字符集进行解码 System.out.println(s); } }
小问题:
public class StringTransferTest { @Test public void test1(){ String s1 = "zhangke"; String s2 = "ke"; String s3 = "zhang"+s2; System.out.println(s1 == s3);//false final String s4 = "ke"; String s5 = "zhang"+s4; System.out.println(s1 == s5);true } }
tips:常量与常量的拼接结果在常量池 且常量池中不会存在相同内容的常量 s4虽然是个变量但是加了final前缀之后就是常量了 所以是true
StringBuffer类
·java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象
·很多方法与String相同
·作为参数传递时,方法内部可以改变值
关于StringBuffer和StringBuilder的使用
String、StringBuffer和StringBuilder三者的相同点和区别?
1.基本定义
①String:
不可变的字符序列 底层使用char[ ]存储
②StringBuffer:
可变的字符序列 线程安全 效率低 底层使用char[ ]存储
③StringBuilder:
可变的字符序列 线程不安全 效率高 底层使用char[ ]存储
2.源码分析
①String str = new String();//char[]value = new char[0]
String str1 = new String("abc:);//char[]value = new char[]{'a','b','c'}
②Stringbuffer sb = new StringBuffer();
//char[]value = new char[16] 底层创建了一个长度为16的数组
sb.append('a');//value[0]='a'; sb.append('b');//value[1]='b';
Stringbuffer sb2 = new StringBuffer("abc");
//char[]value = new char["abc".length+16];
Q1:Syste.out.println(sb2.length()); // 3
Syste.out.println(sb.length()); // 0
Q2:扩容问题:若要添加你的数据底层数组盛不下了,那就需要扩容底层的数组,默认情况下,扩容为原来容量的2倍+2,同时将原有数组的元素复制到新的数组中.buffer和builder都这样扩容.
tips:开发中尽量使用StringBuffer(int capacity)或StringBuilder(int capacity)
3.StringBuffer类的常用方法(builder和buffer方法名一样 同步了)
·当append和insert时,如果原来value数组长度不够,可以扩容
·如上方法支持方法链操作
·方法链原理:
import org.junit.Test; public class StringBufferBuilderTest { @Test public void test(){ StringBuffer sb = new StringBuffer("123"); StringBuffer sb1 = new StringBuffer("123123"); sb.append("s"); System.out.println(sb); sb.delete(0,1); System.out.println(sb); sb1.replace(2,4,"zhangke");//左闭右开 System.out.println(sb1); System.out.println(sb1.length()); sb1.insert(0,true); System.out.println(sb1); System.out.println(sb1.length()); System.out.println(sb1.reverse()); System.out.println(sb1); System.out.println(sb1.indexOf("1")); System.out.println(sb1.substring(0,5));//这里返回的是子串 sb1本身没变 System.out.println(sb1); System.out.println(sb1.charAt(0)); } }
总结:
·增:append(xxx) 方法链就是s.append(xxx).append(xxx).append(xxx).append(xxx);
·删:delete(int start,int end);
·改:setCharAt(int n,char ch)改一个字符 replace(int s,int e,String s)替换字符串
·查:charAt(int n)
·插:insert(int offset,xxx)
·长度:length()
·遍历:for() + charAt()/toString()
对比String、StringBuffer、StringBuilder三者的效率
StringBuilder>StringBuffer>String
System类中获取时间戳的方法
1.java.lang.System类
System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分之间以毫秒为单位的时间差 此方法适用于计算时间差
2.1.java.util.Date类
表示特定的瞬间,精确到毫秒
·构造器:
①Date():使用无参构造器创建对象可以获取本地当前时间
②Date(long date)
·常用方法
①getTime():返回自1970年1月1日0时0分以来此Date对象表示的毫秒数
②toString():把此Date对象转换为以下形式的String:dow mon dd hh:mm:ss zzz yyy
其中dow是星期几(Sun、Mon....),zzz是时间标准eg:Sun Mar 13 17:11:41 HKT 2022
import org.junit.Test; import java.util.Date; public class DateTest { @Test public void test(){ 1.Date():创建一个对应当前时间的Date对象 Date a = new Date(); System.out.println(a.toString()); System.out.println(a.getTime()); 2.Date():创建一个指定毫秒数的Date对象 Date b = new Date(647162775579L); System.out.println(b.toString()); } }Sun Mar 13 17:12:55 HKT 2022
1647162775579
Thu Jul 05 15:26:15 HKT 1990
2.2.java.sql.Date类
对应着数据库中的日期类型的变量
import org.junit.Test; import java.sql.Date; public class DateTest { @Test public void test(){ Date a = new Date(1647162977519L); System.out.println(a.toString()); System.out.println(a.getTime()); } }2022-03-13
1647162977519
如何将java.util.Date对象转换为java.sql.Date对象
法1:
java.util.Date d = new Date();
java.sql.Date d2 = (java.sql.Date)d;//多态法2:
java.util.Date d = new Date();
java.sql.Date d2 = new java.sql.Date(d.getTime());
3.java.text.SimpleDateFormat类
jdk8之前的日期时间的API测试
1.System类中的currentTimeMillis();
2.java.util.Date和子类 java.sql.Date
3.SimpleDateFormat
4.Calendar
3.
import org.junit.Test; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateTest { /* SimpleDateFormat的使用:SimpleDateFormat是对日期Date类的格式化和解析 1.两个操作 1.1:格式化:日期-->字符串 1.2:解析:格式化的逆过程,字符串-->日期 2.SimpleDateFormat的实例化:new +构造器 */ @Test public void test() throws ParseException{ //实例化SimpleDateFormat:使用默认的构造器 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(); //格式化:日期-->字符串 Date date = new Date(); System.out.println(date); String format = simpleDateFormat.format(date); System.out.println(format); //格式化的逆过程,字符串-->日期 String s = "2022/3/14 上午10:55";//字符串格式有要求 Date parse = simpleDateFormat.parse(s); System.out.println(parse); System.out.println("---------------按照指定的方式格式化和解析:调用带参的构造器-------------------"); SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy.MMMM.dd GGG hh:mm aaa"); SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //格式化 String f1 = simpleDateFormat1.format(date); String f2 = simpleDateFormat2.format(date); System.out.println(f1); System.out.println(f2); //解析:要求字符串符合simpleDateFormat识别的格式(通过构造器参数体现) 否则抛异常 Date parse2 = simpleDateFormat2.parse("2022-03-24 10:23:39"); System.out.println(parse2); Date parse1 = simpleDateFormat1.parse("2022.三月.18 公元 11:29 上午"); System.out.println(parse1); } }
练习:
1.画出如下几行代码的内容结构:
String s1 = "hello"; String s2 = "hello"; String s3 = new String("hello"); s1+="world"; 前三行:加上第四行:
2.如何理解String的不可变性:
·字符串是常量,用双引号引起来表示.它们的值在创建之后不能更改
tips:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能原有value进行赋值
2.当对现有字符串进行+=连接操作时也需要重写指定内存区域赋值,不能原有value进行赋值(String s="abc" s+="ef");
3.当调用String的replace()修改指定的字符或字符串时,需要重写指定内存区域赋值,不能原有value进行赋值
3.String类是否可以被继承?为什么?
不能 final
String s = new String("hello");在内存中创建了几个对象?
两个:1.堆空间中new的结构2.char[]对应的常量池中的数据"hello"
4.不涉及多线程或者涉及到多线程但不涉及共享数据的话用StringBuilder 涉及到使用共享数据的多线程用StringBuffer
常见算法题目:
1.模拟一个trim方法,去除字符串两端的空格
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;
}
2.将一个字符串进行反转,将字符串指定部分进行反转.比如"abcdefg"反转为"abfedcg"
法1:转换为char[ ]
public class StringTest { public static void main(String[] args) { String s = "abcdefg"; StringTest st = new StringTest(); System.out.println(st.reverse(s, 2, 5)); } public String reverse(String s,int start,int end){ if(s!=null&&s.length()!=0){ char [] ans = s.toCharArray(); for (int i = start,j=end; i <j ; i++,j--) { char a = ans[i]; ans[i]=ans[j]; ans[j]=a; } return new String(ans); } return null; } }法2:使用字符串的拼接 和 substring()
public class StringTest { public static void main(String[] args) { String s = "abcdefg"; StringTest st = new StringTest(); System.out.println(st.reverse(s, 2, 5)); } public String reverse(String s,int start,int end){ if(s!=null){ String rs1 = s.substring(0,start); for(int i = end ;i>=start;i--){ rs1+=s.charAt(i); } rs1+=s.substring(end+1); return rs1; } return null; } }法3:在法2的基础上使用StringBuffer/StringBuilder替换String
public class StringTest { public static void main(String[] args) { String s = "abcdefg"; StringTest st = new StringTest(); System.out.println(st.reverse(s, 2, 5)); } public String reverse(String s,int start,int end){ if(s!=null){ StringBuilder b = new StringBuilder(s.length()); b.append(s.substring(0,start)); for(int i = end;i>=start;i--){ b.append(s.charAt(i)); } b.append(s.substring(end+1)); return b.toString(); } return null; } }
3.获取一个字符串在另一个字符串中出现的次数.比如获取"ab"在"abkkcadkabkebfkabkskab"中出现的次数
public class StringTest { public static void main(String[] args) { String s = "abkkcadkabkebfkabkskab"; String sub = "ab"; StringTest st=new StringTest(); System.out.println(st.getCount(s, sub)); } public int getCount(String s,String sub){ int sLen= s.length(); int sublen = sub.length(); int count = 0 ; int index = 0; if(sLen>=sublen){ //方式一:不断对主字符串s进行修改 while((index=s.indexOf(sub))!=-1){ count++; s=s.substring(index+sub.length()); } //方式二:对方式一的改进 while((index=s.indexOf(sub,index))!=-1){ count++; index = index+sublen; } return count; }else { return 0; } } }
4.获取两个字符串中最大相同子串.比如s1="abcwerthelloyuiodef",s2="cvhellobnm"
tips:将短的那个串的长度依次递减的子串与较长的串比较//前提:字符串中只有一个最大相同子串
public class StringTest { public static void main(String[] args) { String s1 = "abcwerthelloyuiodef"; String s2 = "cvhellobnm"; StringTest st=new StringTest(); System.out.println(st.getSameString(s1, s2)); } public String getSameString(String s1,String s2){ if (s1!=null&&s2!=null){ String maxString = s1.length()>=s2.length()?s1:s2; String minString = s1.length()<s2.length()?s1:s2; int len = minString.length(); for(int i=0;i<len;i++){ for(int x=0, y=len-i;y<=len;x++,y++){ String subStr = minString.substring(x,y); if(maxString.contains(subStr)) return subStr; } } } return null; } }// 如果存在多个长度相同的最大相同子串
// 此时先返回String[],后面可以用集合中的ArrayList替换,较方便
public String[] getMaxSameSubString1(String str1, String str2) {
if (str1 != null && str2 != null) {
StringBuffer sBuffer = new StringBuffer();
String maxString = (str1.length() > str2.length()) ? str1 : str2;
String minString = (str1.length() > str2.length()) ? str2 : str1;int len = minString.length();
for (int i = 0; i < len; i++) {
for (int x = 0, y = len - i; y <= len; x++, y++) {
String subString = minString.substring(x, y);
if (maxString.contains(subString)) {
sBuffer.append(subString + ",");
}
}
System.out.println(sBuffer);
if (sBuffer.length() != 0) {
break;
}
}
String[] split = sBuffer.toString().replaceAll(",$", "").split("\\,");
return split;
}return null;
}
// 如果存在多个长度相同的最大相同子串:使用ArrayList
// public List<String> getMaxSameSubString1(String str1, String str2) {
// if (str1 != null && str2 != null) {
// List<String> list = new ArrayList<String>();
// String maxString = (str1.length() > str2.length()) ? str1 : str2;
// String minString = (str1.length() > str2.length()) ? str2 : str1;
//
// int len = minString.length();
// for (int i = 0; i < len; i++) {
// for (int x = 0, y = len - i; y <= len; x++, y++) {
// String subString = minString.substring(x, y);
// if (maxString.contains(subString)) {
// list.add(subString);
// }
// }
// if (list.size() != 0) {
// break;
// }
// }
// return list;
// }
//
// return null;
// }
5.对字符串中字符进行自然顺序排序
tips:
①字符串变成字符数组
②对数组排序、选择、冒泡、Arrays.sort()
③将排序后的数组变成字符串public void testSort() {
String str = "abcwerthelloyuiodef";
char[] arr = str.toCharArray();
Arrays.sort(arr);String newStr = new String(arr);
System.out.println(newStr);
}
}
一个问题:
public class StringTest { public static void main(String[] args) { String s1 = null; StringBuffer s2 = new StringBuffer(); s2.append(s1); System.out.println(s2.length());//4 System.out.println(s2);//"null" StringBuffer s3 = new StringBuffer(s1);//抛出异常NullPointerException System.out.println(s3); } }
jdk8之前的日期时间的API测试
1.System类中currentTimeMillis();
2.java.util.Date和子类java.sql.Date
3.SimpleDateFormat
4.Calendar
3.SimpleDateFormat的使用:SimpleDateFormat是对日期Date类的格式化和解析 1.两个操作 1.1:格式化:日期-->字符串 1.2:解析:格式化的逆过程,字符串-->日期 2.SimpleDateFormat的实例化@Test public void test() throws ParseException{ //实例化SimpleDateFormat:使用默认的构造器 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(); //格式化:日期-->字符串 Date date = new Date(); System.out.println(date); String format = simpleDateFormat.format(date); System.out.println(format); //格式化的逆过程,字符串-->日期 String s = "2022/3/14 上午10:55";//字符串格式有要求 Date parse = simpleDateFormat.parse(s); System.out.println(parse); System.out.println("---------------按照指定的方式格式化和解析:调用带参的构造器-------------------"); SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy.MMMM.dd GGG hh:mm aaa"); SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //格式化 String f1 = simpleDateFormat1.format(date); String f2 = simpleDateFormat2.format(date); System.out.println(f1); System.out.println(f2); //解析:要求字符串符合simpleDateFormat识别的格式(通过构造器参数体现) 否则抛异常 Date parse2 = simpleDateFormat2.parse("2022-03-24 10:23:39"); System.out.println(parse2); Date parse1 = simpleDateFormat1.parse("2022.三月.18 公元 11:29 上午"); System.out.println(parse1); }练习1:字符串"2020-09-08"转换为java.sql.Date
@Test public void test() throws ParseException{ //实例化SimpleDateFormat:使用默认的构造器 String s = "2020-09-08"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); java.util.Date d = simpleDateFormat.parse(s); java.sql.Date date1 = new java.sql.Date(d.getTime()); //String format = simpleDateFormat.format(date); System.out.println(date1);//2020-09-08 这里调用的是date1的toString方法 练习2:"三天打鱼两天晒网" 从1990-01-01 问某年某月某日 他在干啥 方式一:(d2.getTime()-d1.getTime())/(1000*60*60*24) + 1计算毫秒数 方式二:强行计算天数 考虑闰年
4.Calender(日历)类
@Test public void test(){ /* 1.实例化: 方式一:创建其子类(GregorianCalendar)的对象 方式二:调用其静态方法getInstance(); */ Calendar calendar = Calendar.getInstance(); System.out.println(calendar.getClass());//class java.util.GregorianCalendar /* 2.常用方法: get() set() add() getTime():日历类--->Date setTime():Date--->日历类 */ int d = calendar.get(Calendar.DAY_OF_MONTH); System.out.println(d); System.out.println(calendar.get(Calendar.DAY_OF_YEAR)); calendar.set(Calendar.DAY_OF_MONTH,22); System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); calendar.add(Calendar.DAY_OF_MONTH,3); System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); Date time = calendar.getTime(); System.out.println(time); Date date = new Date(); calendar.setTime(date); System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); } }
jdk8中新日期时间的API测试
LocalDate、LocalTime、LocalDateTime的使用
LocalDateTime使用的频率略微高点,类似于Calendar
@Test public void test(){ //now():获取当前的日期、时间、日期+时间 LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDate); System.out.println(localTime); System.out.println(localDateTime); //of():设定指定的时间 没有偏移量 LocalDateTime localDateTime1 = LocalDateTime.of(2022, 10, 1, 13, 24, 31); System.out.println(localDateTime1); //getXxx() System.out.println(localDateTime.getDayOfMonth()); System.out.println(localDateTime.getDayOfWeek()); //withXxx():设置相关的属性体现不可变性 LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(22); System.out.println(localDateTime2.getDayOfMonth()); LocalDateTime localDateTime3 = localDateTime.plusMonths(3); System.out.println(localDateTime3); } }
瞬时:Instant 类似于java.util.Date类
@Test public void test(){ Instant instant = Instant.now();//now():获取本初子午线的时间 System.out.println(instant); System.out.println(instant.atOffset(ZoneOffset.ofHours(8)));//添加偏移量 System.out.println(instant.toEpochMilli());//获取自1970-01-01 0:0:0开始的毫秒数--->Date类的get() System.out.println(Instant.ofEpochMilli(1647242914123L));//通过给定的毫秒数、获取Instant实例--->(long millis)
java.time.format.DateTimeFormatter类:类似于SimpleDateFormat
import org.junit.Test; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.time.temporal.TemporalAccessor; import java.util.Calendar; import java.util.Date; import java.util.Locale; public class DateTest { /* */ @Test public void test(){ //方式一:预定义的标准格式 ISO_LOCAL_DATE_TIME.... DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; //格式化:日期--->字符串 LocalDateTime localDateTime = LocalDateTime.now(); String s = formatter.format(localDateTime); System.out.println(localDateTime); System.out.println(s); //解析:字符串--->解析 TemporalAccessor accessor = formatter.parse("2022-03-14T15:52:39.2178908"); System.out.println(accessor); //格式化:日期--->字符串 System.out.println("--------------------------------------------"); //方式二:本地化相关的格式 ofLocalizedDateTime(FormatStyle.LONG) DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); //LONG和FULL 在JDK11之后需要加上.withZone(ZoneId.systemDefault()) //格式化:日期--->字符串 String s1 = formatter1.format(localDateTime); System.out.println(s1); //解析:字符串--->日期 TemporalAccessor accessor1 = formatter.parse("2022-03-14T15:50:53.6997053"); System.out.println(accessor1); System.out.println("--------------------------------------------"); //方式三:自定义的格式 ofPattern("yyyy-MM-dd hh:mm:ss E") 要加上.withLocale(Locale.CHINA); DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"); //格式化: String s2 = formatter2.format(localDateTime); System.out.println(s2); //解析: TemporalAccessor accessor2 = formatter2.parse("2022-03-14 04:24:14"); System.out.println(accessor2); } }
Java比较器
·在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题
·Java实现对象排序的方式有两种:
①自然排序:java.lang.Comparable
②定制排序:java.util.Comparator
·Java中的对象,正常情况下,只能比较:==或!= 不能使用>、<
1.Comparable接口的使用:自然排序
①像String、包装类等实现了Comparable接口,重写了compareTo()给出了比较两个对象大小的方式.
②重写compareTo()的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负数,
若相等则返回0
③像String、包装类重写了compareTo()以后,进行了从小到大的排列
④实现Comparable接口的对象列表(和数组)可以通过Collections.sort或Arrays.sort进行自动排序,实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器
⑤对于类C的每一个e1和e2来说,当且仅当e1.compareTo(e2)==0与e1.equals(e2)具有相同的boolean值时,类C的自然排序才叫做与equals一致.建议(但是不必需)最好使自然排序与equals一致
⑥对于自定义类来说,若需要排序,我们可以让自定义类去实现Comparable接口,重写compareTo(obj)方法,在compareTo(obj)方法中指明如何排序
6.public class Goods implements Comparable{ private int price; private String name; public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Goods() { } public Goods(int price, String name) { this.price = price; this.name = name; } @Override public String toString() { return "Goods{" + "price=" + price + ", name='" + name + '\'' + '}'; } //指明按照什么方式进行排序:先按照价格从低到高 再按照产品名字从低到高 @Override public int compareTo(Object o) { if(o instanceof Goods){ Goods g = (Goods) o; if(this.price>g.price){ return 1; } else if(this.price<g.price){ return -1; } else { return this.name.compareTo(g.name); } } throw new RuntimeException("No!"); } }import org.junit.Test; import java.util.Arrays; public class GoodsTest { @Test public void test(){ Goods[]arr = new Goods[4]; arr[0] = new Goods(20,"dell"); arr[1] = new Goods(43,"hp"); arr[2] = new Goods(32,"vivo"); arr[3] = new Goods(43,"oppo"); Arrays.sort(arr); System.out.println(Arrays.toString(arr)); } }
2.Comparator接口的使用:定制排序
·当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用Comparator的对象来排序,强行对多个对象进行整体排序的比较
·重写compare(Object o1,Object o2)方法,比较o1和o2的大小:若方法返回正整数则表示o1大于o2,若返回0则表示相等,若返回负整数,表示o1小于o2
·可以将Comparator传递给sort方法(比如Collections.sort或Arrays.sort),从而允许在排序顺序上实现精确控制
·还可以使用Comparator来控制某些数据结构(如:有序set或有序映射)的顺序,或者为哪些没有自然顺序的对象collection提供排序
import org.junit.Test; import java.util.Arrays; import java.util.Comparator; public class GoodsTest { @Test public void test(){ Goods[]arr = new Goods[4]; arr[0] = new Goods(20,"dell"); arr[1] = new Goods(43,"hp"); arr[2] = new Goods(32,"vivo"); arr[3] = new Goods(43,"oppo"); Arrays.sort(arr); System.out.println(Arrays.toString(arr)); } @Test public void test1(){ String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"}; Arrays.sort(arr,new Comparator(){ @Override public int compare(Object o1, Object o2) { if(o1 instanceof String && o2 instanceof String){ String s1 = (String) o1; String s2 = (String) o2; return -s1.compareTo(s2); } throw new RuntimeException("No!"); } }); System.out.println(Arrays.toString(arr)); } @Test public void test2(){ Goods[]arr = new Goods[5]; arr[0] = new Goods(20,"dell"); arr[1] = new Goods(43,"hp"); arr[2] = new Goods(32,"vivo"); arr[3] = new Goods(43,"oppo"); arr[4] = new Goods(40,"oppo"); Arrays.sort(arr, new Comparator<Goods>() { @Override public int compare(Goods o1, Goods o2) { if(o1 instanceof Goods && o2 instanceof Goods){ Goods s1 = (Goods) o1; Goods s2 = (Goods) o2; if(s1.getName().equals(s2.getName())){ return -Double.compare(s1.getPrice(),s2.getPrice()); }else{ return s1.getName().compareTo(s2.getName()); } } throw new RuntimeException("No!"); } }); System.out.println(Arrays.toString(arr)); } }
3.对比
①Comparable接口的方式一旦指定,保证Comparable接口实现类的对象在任何位置都可以比较大小
②Comparator接口属于临时的比较.
System类
Math类
BigInteger与BigDecimal
1.BigInteger类:
①Integer类作为int的包装类,能存储的最大整型值为2^31-1,Long类也是有限的,最大
为2^63-1.若表示更大的整数,不管是基本数据类型还是它们的包装类都无能为力更别说运算了
②java.math包的BigInteger可以表示不可变的任意精度的整数.BigInteger提供所有Java的基本整数操作符的对应物,并提供java.lang.Math的所有相关方法.另外,BigInteger还提供一下运算:模运算、GCD计算、质数测试、素数生成、位操作以及一些其他操作
③构造器:BigInteger(String val):根据字符串构建BigInteger对象
2.BigDecimal类:
①一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中要求数字精度比较高,故用到java.math.BigDecimal类
②BigDecimal类支出不可变的、任意精度的有符号十进制定点数
③构造器:BigDecimal(String val) 、 BigDecimal(double val)
④常用方法:
public void test3(){ BigInteger bigInteger = new BigInteger("2312316546546"); BigDecimal bigDecimal = new BigDecimal("121231.2313"); BigDecimal bigDecimal2 = new BigDecimal("12"); System.out.println(bigInteger); System.out.println(bigDecimal.divide(bigDecimal2,10, RoundingMode.HALF_UP)); }