1. String類
1.1 String的特性
-
String類:代表字符串。Java程序中的所有字符串字面值(如“abc”)都作為此類的實例實現。
-
String是一個final類,代表不可變的字符序列。
-
String字符串是常量,用雙引號引起來表示。他們的值在創建之后不能更改。
-
String對象的找字符內容是存儲在一個字符數組value[]中的。(jdk新版本已改為使用byte類型的數組value[]存放)

1.2 String字面量賦值的內存理解
字面量賦值是直接在常量池中賦值的
Demo:
package com.broky.commonClass;
import org.junit.jupiter.api.Test;
/**
* String 的使用
*
* @author 13roky
* @date 2021-04-24 10:34
*/
public class StringTest {
/*
String:字符串,使用一對""來表示.
1.String類是被聲明為final的,不可被繼承.
2.String實現了Serializable接口:標識字符串是支持序列化的. (io流)
實現了Comparable接口:可以比較大小.
3.String內部定義了final char[] value用於存儲字符串數字. final表示數組和其元素不能被修改。(為了節省jvm的內存空間jdk9已經改為byte[]類型數組)
4.String:代表不可變的字符序列。簡稱:不可變性。
體現:1.當對字符串重新賦值時,需要重新指定內存區域賦值,不能使用原有的value進行賦值.(因為原有的value是final的)
2.當對現有的字符串進行連接操作時,需要重新指定內存區域賦值,不能使用原有的value賦值.
3.當調用String的replace()方法修改字符或字符串時,也必須重新指定內存區域賦值,不能使用原有的value賦值.
5.通過字面量的方式(區別於new)給一個字符串賦值,此時的字符串值生命在字符串常量池中.
6.字符串常量池中是不會存儲相同內容的字符串的.
*/
@Test
public void test01(){
//字面量的定義方式, 在內存中用的是同一個內存地址
String s1 = "abc";
String s2 = "abc";
//==比較的是地址值,為true說明s1和s2在內存中指向的是同一個位置
System.out.println(s1 == s2);//true
s1 = "hello";
System.out.println(s1);//hello
System.out.println(s2);//abc
System.out.println("================================================");
String s3 = "abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println(s2);//abc
System.out.println("================================================");
String s4 = "adb";
String s5 = s4.replace('a','m');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
}
圖解:
- 由於字符串常量池中是不會存儲相同內容的字符串的,所以在字符串常量池中s1和s2指向同一個內存地址。

- 由於String內部定義了final char[] value用於存儲字符串數字,final表示數組和其元素不能被修改,其也就有了不可變的字符序列的性質。所以改變s1取值為hello后,並不會改變字符串常量池中的對應位置的值,而是會新開辟一個內存地址存放hello值,並且s1指向新的內存地址。

- 以下圖解類似。


1.3 String new方式賦值的內存理解
Demo:
package com.broky.commonClass;
import org.junit.jupiter.api.Test;
/**
* String 的使用
*
* @author 13roky
* @date 2021-04-24 10:34
*/
public class StringTest {
/*
String實例化方式測試:
方式一: 通過字面量定義的方式
方式二: 通過new + 構造器的方式
面試題:String s = new String("abc);方式創建對象,在內存中創建了幾個對象?
兩個:一個是堆空間中new結構,另一個是char[]對應的常量池中的數據"abc"
*/
@Test
public void test2() {
//通過字面量定義的方式:此時的s1和s2的數據javaEE生命在方法區中的字符串常量池中.
String s1 = "javaEE";
String s2 = "javaEE";
//通過new + 構造器的方式:此時的s3和s4保存的地址值是數據在堆空間中開辟空間后對應的地址值.
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
System.out.println(s3.equals(s4));//true
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
}
}
class Person{
public String name;
public int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
}
圖解:
new的結構是存在於堆中的,比如 String s3 = new String("javaEE");

1.4 String 拼接字面量和變量的方式賦值
Demo:
package com.broky.commonClass;
import org.junit.jupiter.api.Test;
/**
* String 的使用
*
* @author 13roky
* @date 2021-04-24 10:34
*/
public class StringTest {
/*
1.常量與常量的拼接結果在常量池。且常量池中不會存在享同內容的常量。
2.只要其中有一個是變量,結果就在堆中。
3.如果拼接的結果調用intern()方法,返回值就會在常量池中。
*/
@Test
public void test03() {
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";//引號中的為字面量,這里是字面量的拼接
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
final String s8 = "hadoop";
String s9 = "javaEE" + s8;
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(s3 == s9);//true
String s10 = s5.intern();//返回值得到的s8使用的常量值中已經存在的”javaEEhadoop“(s5.intern返回的時常量池中對應的內存地址)
System.out.println(s3 == s10);//true
}
}
圖解:
- 常量與常量的拼接,結果直接保存在常量池中。如
String s4 = "javaEE" + "hadoop";,如果常量池中存在“javaEEhadoop”,那么s4直接指向其地址。 - 只要拼接賦值時,其中有一個是變量,那么結果就會存在於堆中,如
String s5 = s1 + "hadoop";,棧中的變量名s5指向堆中對應的地址0x0001,堆中的地址又指向常量池的地址0x1214。 - s5指向的是堆中的內存地址0x0001,但是方法
s5.intern返回的直接是常量池中的地址。所以String s10 = s5.intern();這行代碼會讓s10直接指向常量池對應的內存地址。

package com.broky.commonClass.exer;
import java.util.Arrays;
/**
* @author 13roky
* @date 2021-04-26 7:27
*/
public class StringValueChangeEx {
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) {
StringValueChangeEx test01 = new StringValueChangeEx();
test01.change(test01.str, test01.ch);
//這里涉及字符串的拼接,所以會用toString方法,而char中的toString返回的是哈希值,所以要用arrays類
System.out.println(test01.str + " and " + Arrays.toString(test01.ch)); //good and [C@2f4d3709
System.out.println(test01.str); //good
System.out.println(test01.ch); //test
}
}
1.5 String類常用方法
int Length():返回字符的長度: return value.Lengthchar charAt(int index):返回某索引處的字return vaLue[index]booLean isEmpty():判斷是否是空字符牢: return value. Length == 0String toLowercase():使用默認語言環境,將 String中的所有字符轉換為小寫String toUppercase():使用默認語言環境,將 String中的所有字符轉換為大寫String trim():返回字符的副本,忽略前導空白和尾部空白boolean equals(Object obj):比較字符的內容是否相同booLean equalsIgnoreCase(String anotherString):與equls方法類似,忽略大小寫String concat(string str):將指定字符牢連接到此字符的結尾。等價於用"+"int compare To(String anotherstring):比較兩個字符的大小String substring(int beginIndex):返回一個新的字符,它是此字符的從 beginIndex開始截取到最后一個子字符串.String substring(int beginIndex, int endindex):返回一個新字符串,它是此字符從beginIndex開始截取到endIndex(不包含)的一個子字符串.
Demo:
package com.broky.commonClass;
import org.junit.jupiter.api.Test;
import java.util.Locale;
/**
* @author 13roky
* @date 2021-04-26 21:47
*/
public class CommonMethod {
/*
int Length():返回字符的長度: return value.Length
char charAt( nt 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):與equls方法類似,忽略大小寫
String concat(string str):將指定字符牢連接到此字符的結尾。等價於用"+"
int compare To(String anotherstring):比較兩個字符的大小
String substring(int beginIndex):返回一個新的字符,它是此字符的從 beginIndex開始截取到最后一個子字符串.
String substring(int beginIndex, int endindex):返回一個新字符串,它是此字符從beginIndex開始截取到endIndex(不包含)的一個子字符串.
*/
@Test
public void test01(){
String s1 ="HelloWorld";
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.charAt(9));
System.out.println(s1.isEmpty());
String s2 = s1.toLowerCase();
System.out.println(s1);
System.out.println(s2);
String s3 = " he llo world ";
String s4 = s3.trim();
System.out.println(s3);
System.out.println(s4);
}
@Test
public void test02(){
String s1 = "HelloWorld";
String s2 = "helloworld";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));
String s3 = "abc";
String s4 = "def".concat(s3);
System.out.println(s4);
String s5 = "abc";
String s6 = new String("abd");
System.out.println(s5.compareTo(s6));
String s7 = "13roky學Java";
String s8 = s7.substring(2,6);
System.out.println(s7);
System.out.println(s8);
}
}
boolean endsWith(String suffix):測試此字符串是否以指定的后綴結束boolean startsWith(String prefix):測試此字符串是否以指定的前綴開始boolean startsWith(String prefix, int toffset):測試此字符串從指定索引開始的子字符串是否以指定的前綴開始boolean contains(CharSequence s):當且僅當此字符串包含指定的char值序列時,返回trueint indexOf(String str): 返回指定子字符串在此字符串中第一次出現處的索引int indexOf(String str,int fromIndex):返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引處開始int lastIndexOf(String str):返回指定子字符串在此字符串中最右邊出現處的索引int lastIndexOf(String str,int fromIndex):返回指定子字符串在此字符串中最后一次出現處的索引,從指定的索引開始反向搜索(從右往左搜索)indexOf和lastindexOf方法如果未找到,返回結果都是-1
Demo:
package com.broky.commonClass;
import jdk.jfr.DataAmount;
import org.junit.jupiter.api.Test;
import java.util.Locale;
/**
* @author 13roky
* @date 2021-04-26 21:47
*/
public class CommonMethod {
/*
boolean endsWith(String suffix):測試此字符串是否以指定的后綴結束
boolean startsWith(String prefix):測試此字符串是否以指定的前綴開始
boolean startsWith(String prefix, int toffset):測試此字符串從指定索引開始的子字符串是否以指定的前綴開始
boolean contains(CharSequence s):當且僅當此字符串包含指定的char值序列時,返回true
int indexOf(String str): 返回指定子字符串在此字符串中第一次出現處的索引
int indexOf(String str,int fromIndex):返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引處開始
int lastIndexOf(String str):返回指定子字符串在此字符串中最右邊出現處的索引
int lastIndexOf(String str,int fromIndex):返回指定子字符串在此字符串中最后一次出現處的索引,從指定的索引開始反向搜索(從右往左搜索)
indexOf和lastindexOf方法如果未找到,返回結果都是-1
*/
@Test
public void test03(){
String str1 = "helloworld";
boolean b1 = str1.endsWith("rld");
System.out.println(b1);
boolean b2 = str1.startsWith("He");
System.out.println(b2);
boolean b3 =str1.startsWith("ll",2);
System.out.println(b3);
String str2 = "wo";
System.out.println(str1.contains(str2));
System.out.println(str1.indexOf("lol"));
System.out.println(str1.indexOf("l"));
System.out.println(str1.indexOf("lo", 5));
String str3 = "hellorworld";
System.out.println(str3.lastIndexOf("or"));
System.out.println(str3.lastIndexOf("or",6));
}
//什么情況下,indexOf(str)和lastIndexOf(str)返回值相同?
//情況一:存在唯一的一個str.
//情況二:不存在str
}
- 替換:
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個,如果超出,剩下的全部都放到最后一個元素
Demo:
package com.broky.commonClass;
import jdk.jfr.DataAmount;
import org.junit.jupiter.api.Test;
import java.util.Locale;
/**
* @author 13roky
* @date 2021-04-26 21:47
*/
public class CommonMethod {
/*
替換
String replace(char oldChar,char newChar):返回一個新的字符串,它是通過用newChar替換oldChar
String replace(CharSequence target,CharSequence replacement):使用字面值替換序列替換此字符串所有匹配字面值目標序列的子字符串.
String replaceAll(String regex,String replacement):使用給定的replacement替換此字符串多有匹配給定的正則表達式的子字符串
String replaceFirst(String regex,String replacement):使用給定的replacement替換此字符串匹配給定的正則表達式的第一個子字符串.
匹配:
boolean matches(String regex):告知此字符串是否匹配給定得正則表達式
切片:
String[] split(String regex):根據給定的正則表達式的匹配拆分此字符串
String[] split(String regex,int limit):根據匹配給定的正則表達式來分此字符串,最多不超過limit個,如果超出,剩下的全部都放到最后一個元素
*/
@Test
public void test04(){
String str1 = "13roky學Java";
String str2 = str1.replace('學','寫');
System.out.println(str1);
System.out.println(str2);
String str3 = str1.replace("13roky", "geek");
System.out.println(str3);
System.out.println("=====================================================");
String str = "123klnjklsdnafdmc123pojasvapos";
String string = str.replace("\\d+",",").replaceAll("^,|,$","|");
System.out.println(string);
str = "12345";
//判斷str字符串中是否全部有數字組成,即有1-n個數字組成
boolean matches = str.matches("\\d+");
System.out.println(matches);
String tel = "0571-4534289";
//判斷一個電話是否是杭州的
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result);
System.out.println("================================================");
str = "hello|world|java";
String[] strs = str.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
System.out.println();
str2 = "hello.world.java";
String[] strs2 = str2.split("\\|");
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]);
}
}
}
1.6 String與其它類型的轉換
demo:
package com.broky.commonClass;
import org.junit.jupiter.api.Test;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* String類與其他結構之間的轉換
* String 與 char[] 之間的轉換
* String 與 byte[] 之間的轉換
*
* @author 13roky
* @date 2021-05-02 19:33
*/
public class StringChange {
/*
復習:String與其他數據類型,包裝類之間的轉換
String --> 基本數據類型、包裝類:調用包裝類的靜態方法:parseXxx(str)
基本數據類型、包裝類 ——》String:調用String重載的valueOf(xxx) 或者直接拼接“”
*/
@Test
public void test(){
String str = "123";
//int num = (int) str; 只有子父類的關系才可以使用強制類型轉換
int num = Integer.parseInt(str);
String str2 = String.valueOf(num);
String str3 = num + "";
}
/*
String 與 char[] 之間的轉換
String --> char[] :String類中的toCharArray()方法
char[] --> String :String的構造器
*/
@Test
public void test02(){
String str = "abcde";
char[] c1 = str.toCharArray();
for (int i = 0; i < c1.length; i++) {
System.out.println(c1[i]);
}
char[] c2 = new char[]{'f','s','c','a'};
String str2 = new String(c2);
System.out.println(str2);
}
/*
String 與 byte[] 之間的轉換
編碼:String --> byte[] :調用String的getBytes()
解碼:
轉化的時候會涉及編碼和解碼
編碼:字符串 --> 字節 (看得懂轉換為看不懂的二進制數據)
解碼 字節 --> 字符串 (看不懂的二進制數據轉換為看得懂)
*/
@Test
public void test03() throws UnsupportedEncodingException {
String str = "abc123此方";
// 使用ide默認的編碼集進行轉換
byte[] b1 = str.getBytes();
// 字節byte類型 采用ASCLL編碼 由於ASCLL中沒有中文編碼,所以中文會轉為默認的編碼如(UTF-8,UTF-8中一個漢字占三位)然后再轉為ASCLL
System.out.println(Arrays.toString(b1));
// 使用 gbk 字符集進行編碼,需要處理異常
byte[] b2 = str.getBytes("gbk");
System.out.println(Arrays.toString(b2));
System.out.println("=======================================");
// 使用ide默認的編碼集進行解碼
String str2 = new String(b1);
System.out.println(str2);
// 出現亂碼。原因:編碼及和解碼集不一致倒置的
String str3 = new String(b2);
System.out.println(str3);
// 指定編碼集
String str4 = new String(b2, "gbk");
System.out.println(str4);
}
}
1.7 常見算法題目
- 模擬一個trim方法,去除字符串兩端的空格。
- 將一個字符串進行反轉。將字符串中間指定部分進行反轉。比如“abcdefg”反轉為“abfedcg”。
- 獲取一個字符串在另一個字符串中出現的次數。
- 獲取兩個字符串中最大的相同字符串。
- 將字符串中字符進行自然順序排序。Arrays.sort()
package com.broky.commonClass.exer;import org.junit.jupiter.api.Test;import java.nio.CharBuffer;import java.util.Arrays;import java.util.Objects;/** * 四道常見String算法題目 * 1. 模擬一個 trim 方法,去除字符串兩端的空格。 * * @author 13roky * @date 2021-05-08 10:06 */public class Algorithms { @Test public void testMyTrim() { String s1 = " 123 "; s1.trim(); s1 = myTrim(s1); System.out.println(s1); } // 模擬一個 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; } @Test public void testMyReverse() { System.out.println(myReverse01("abcdefg", 2, 5)); System.out.println(myReverse02("abcdefg", 2, 5)); System.out.println(myReverse03("abcdefg", 2, 5)); } /* 將一個字符串進行反轉。將字符串中指定部分進行反轉。比如“abcdefg”反轉為“abfedcg” */ // 方式一:轉換為char[] public String myReverse01(String str, int start, int end) { if (str != null) { char[] chars = str.toCharArray(); char tmp = 0; for (int s = start, e = end; s < e; s++, e--) { tmp = chars[s]; chars[s] = chars[e]; chars[e] = tmp; } return new String(chars); } return null; } // 方式二:使用String的拼接 public String myReverse02(String str, int start, int end) { if (str != null) { String partOne = str.substring(0, start); String parThree = str.substring(end + 1); for (int i = end; i >= start; i--) { partOne += str.charAt(i); } partOne += parThree; return partOne; } return null; } // 方式三:使用StringBuffer 或 StringBuilder 替換String public String myReverse03(String str, int start, int end) { StringBuilder builder = new StringBuilder(str.length()); builder.append(str.substring(0, start)); for (int i = end; i >= start; i--) { builder.append(str.charAt(i)); } builder.append(str.substring(end + 1)); return String.valueOf(builder); } /* 獲取一個字符串在另一個字符串中出現的次數。 如:獲取 "ab" 在 “abkkcakabkebfkabkskab” 出現的次數 */ @Test public void testGetCount() { getCount01("ab", "abkkcakabkebfkabkskab"); getCount02("ab", "abkkcakabkebfkabkskab"); } // 方法一: public int getCount01(String mainStr, String subStr) { int n = 0; for (int i = 0; i < subStr.length() - mainStr.length() + 1; i++) { if (mainStr.charAt(0) == subStr.charAt(i)) { if (mainStr.equals(subStr.substring(i, i + mainStr.length()))) { n++; } } } System.out.println(n); return n; } // 方法二: public int getCount02(String mainStr, String subStr) { int count = 0; int index = 0; if (subStr.length() >= mainStr.length()) {// while ((index = subStr.indexOf(mainStr)) != -1) {// count++;// subStr = subStr.substring(index + mainStr.length());// } // 改進 while ((index = subStr.indexOf(mainStr,index)) != -1) { count++; index += mainStr.length(); } System.out.println(count); return count; } else { return 0; } }}
2. StringBuffer 和 StringBuilder類
2.1 String、StringBuffer、StringBuilder 三者的異同
- String:不可變的字符序列,底層使用char[]進行存儲
- StringBuffer:可變的字符序列,線程安全的,效率低,底層使用char[]進行存儲
- StringBuilder:可變的字符序列,線程不安全的,效率高,jdk5.0新特性,底層使用char[]進行存儲
源碼分析:
- String:
String str = new String(); // 底層代碼為 char[] value = new char[0];
String str1 = new String("abc"); // 底層代碼為 char[] value = new char[]{'a','b','c'}; - StringBuffer:
String sb1 = new StringBuffer(); // char[] value = new char[16];底層創建了一個長度是16的數組
sb1.append('a'); // value[0] = 'a';
sb1.append('b'); // value[1] = 'b'; - 問題:
- System.out.println(sb1.length()); 返回的是有的值count,而不是底層開辟的空間value.length.
- 擴容問題,如果要添加的數據底層數組盛不下了,那就需要擴容底層的數組。默認情況下,擴容為原來容量的2倍+2(源碼中采用了位運算<<),同時將原有數組中的元素復制到新數組中。
- 總結:
- 開發中盡量不要用String,String不可變,效率最差,每次都會新造。而StringBuufer和StringBuilder只有長度不夠用的時候才去擴容並復制。
- 開發中如果知道會頻繁使用append時,建議使用StringBuffer的指定容量的構造器,避免之后進行擴容。
2.2 StringBuffer 類的常用方法
- StringBuffer append(xx):提供了很多的 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(xx)
刪:delete( int start, int end)
改:setCharAt(int n,char ch) / replace( int start, int end, String str)
查:charAt(int n)
插:insert( int offset,xxx)
長度:Length()
遍歷:for() + charAt() / toString() - 方法鏈的原理:s1.append().append().append(); s1調用完append后返回的依舊是s1,可以繼續調用append
package com.broky.commonClass.exer;import org.junit.jupiter.api.Test;/** * StringBuffer 的常用方法 * * @author 13roky * @date 2021-05-07 13:27 */public class StringBufferMethod { @Test public void test(){ StringBuffer s1 = new StringBuffer("abc"); s1.append(1); s1.append("234"); System.out.println(s1.delete(2, 4)); System.out.println(s1); System.out.println(s1.replace(2, 4, "hello")); System.out.println(s1.reverse()); }}
關於append方法
package com.broky.commonClass;import org.junit.jupiter.api.Test;public class StringBufferBuilderTest { @Test public void test2(){ String str = null; StringBuffer sb = new StringBuffer(); //StringBuffer 的 append 方法會將null值轉換為字符“null”加入 sb.append(str); System.out.println(sb.length());//4 System.out.println(sb);//"null" StringBuffer sb2 = new StringBuffer(str); System.out.println(sb2); }}
2.3 String、StringBuffer、StringBuilder 三者的效率
效率:StringBuilder > StringBuffer > String
package com.broky.commonClass;import org.junit.jupiter.api.Test; /** * String StringBuffer StringBuilder 效率測試 */ @Test public void timeTest() { 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 + String.valueOf(i); } endTime = System.currentTimeMillis(); System.out.println("String 執行時間" + (endTime - startTime)); }}
3. JDK8 之前的日期和時間 api 相關類
3.1 java.lang.System 類
System 類提供的 public static long currentTimeMillis() 用來返回當前時間與1970年1月1日0時0分0秒之間以毫秒為單位的時間差。
3.2 java.util.Date 和 java.sql.Date 類
-
兩個構造器的使用
構造器一:Date():創建一個對應當前時間的Date對象
構造器二:創建指定毫秒數的Date對象 -
兩個方法的使用
toString():顯示當前的年、月、日、時、分、秒
getTime():獲取當前Date對象對應的毫秒數。(時間戳) -
java.sql.Date 對應這數據庫中的日期類型的變量
實例化
將 sql.date 轉換 util.date: 多態直接賦值
將 util.date 轉換 sql.date: 通過共同的getTime()時間戳實現
Demo:
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.util.Date;/** * JDK8 之前的日期和時間的 api 測試 * * @author 13roky * @date 2021-05-08 9:15 */public class DateTimeTest { /* System類提供的 public static long currentTimeMillis() 用來返回當前時間與1970年1月1日0時0分0秒之間以毫秒為單位的時間差。 */ @Test public void test() { long time = System.currentTimeMillis(); System.out.println(time); } /* java.util.Date 類 |---java.sql.Date 類 數據庫 1. 兩個構造器的使用 > 構造器一:Date():創建一個對應當前時間的Date對象 > 構造器二:創建指定毫秒數的Date對象 2. 兩個方法的使用 > toString():顯示當前的年、月、日、時、分、秒 > getTime():獲取當前Date對象對應的毫秒數。(時間戳) 3. java.sql.Date 對應這數據庫中的日期類型的變量 > 實例化 > 將 sql.date 轉換 util.date: 多態直接賦值 > 將 util.date 轉換 sql.date: 通過共同的getTime()時間戳實現 */ @Test public void test02() { // 構造器一:Date():創建一個對應當前時間的Date對象 Date date1 = new Date(); System.out.println(date1.toString()); System.out.println(date1.getTime()); // 構造器二:創建指定毫秒數的Date對象 Date date2 = new Date(1620437519431L); java.sql.Date date3 = new java.sql.Date(1620437519431L); System.out.println(date3); // 將 util.date 轉換 sql.date: // 情況一 Date date4 = new java.sql.Date(1620437519431L); java.sql.Date date5 = (java.sql.Date) date4; // 情況二 Date date6 = new Date(); java.sql.Date date7 = new java.sql.Date(date6.getTime()); /* 當new的是父類的時候,如果強轉為子類,那么編譯時不會報錯,運行時會報錯,因為new的父類缺少子類特有的屬性和方法 當new的是子類的時候,但是賦給了父類,這時候是可以強轉成子類的,如情況一 */ }}
注意:
使用Data的構造器,設置時間會存在 偏移量 的問題
Demo:
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.util.Date;/** * JDK8 之前的日期和時間的 api 測試 * * @author 13roky * @date 2021-05-08 9:15 */public class DateTimeTest { // Date中的偏移量 @Test public void test01() { /* 由於構造方法存在一個偏移量,年份是從1990年開始,月份是從0開始所以構造時應該減去偏移量 */ Date date1 = new Date(2020, 9, 8); System.out.println(date1); // Fri Oct 08 00:00:00 CST 3920 date1 = new Date(2020 - 1900, 9 - 1, 8); System.out.println(date1); // Tue Sep 08 00:00:00 CST 2020 }}
3.3 SimpleDateFormat 類
SimpleDateFormat 是用來 格式化 Date 類中 時間格式的 和 對格式進行解析成 Date 的類
可以使用默認格式,也可以自定義格式。
- 兩個操作
1.1 格式化:日期 ---> 字符串
1.2 解析:格式化的逆過程,字符串 ---> 日期 - SimpleDateFormat 的實例化
Demo
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * jdk 8 之前的日期時間的API測試 * 1. System類中currentTimeMillis(); * 2. java.util.Date 和 子類 java.sql.Date * 3. SimpleDateFormat * 4. Calendar * * @author 13roky * @date 2021-05-09 12:53 */public class DateTimeTest2 { /* 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); String format = sdf.format(date); System.out.println(format); // 解析: 格式化的逆過程,字符串 ---> 日期 String str = "2021/5/9 下午1:04"; Date date1 = null; date1 = sdf.parse(str); System.out.println(date1); //********************************* // SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa"); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String format1 = sdf1.format(date); System.out.println(format1); Date date2 = sdf1.parse("2021-05-09 01:09:56"); System.out.println(date2); }}
練習:
- 字符串“2020-02-23”轉化為java.sql.Date
- 三天打魚兩天曬網 1990-01-01 視頻分析:P482480.尚硅谷_常用類-SimpleDateFormat的課后練習2
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date; @Test public void testEx01() throws ParseException { //練習一:字符串“2020-02-23”轉化為java.sql.Date String str ="2020-02-23"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date = sdf.parse(str); System.out.println(date); java.sql.Date sqlDate = new java.sql.Date(date.getTime()); System.out.println(sqlDate); } @Test public void testEx02() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date startDate = sdf.parse("1990-01-01"); long oneDay = sdf.parse("1990-01-02").getTime() - startDate.getTime(); long period = oneDay * 5; // long now = sdf.parse(sdf.format(new Date())).getTime() - startDate.getTime(); long now = sdf.parse("1990-01-06").getTime() - startDate.getTime() + oneDay; if (now % period > 3 * oneDay || now % period == 0) { System.out.println("曬網"); } else { System.out.println("打魚"); } }}
3.4 Calendar 類
- calendar類是一個抽象類,是可變的
demo
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;/** * jdk 8 之前的日期時間的API測試 * 1. System類中currentTimeMillis(); * 2. java.util.Date 和 子類 java.sql.Date * 3. SimpleDateFormat * 4. Calendar * * @author 13roky * @date 2021-05-09 12:53 */public class DateTimeTest2 { /* Calendar 日歷類(抽象類)的使用 */ @Test public void testCalendar(){ // 1. 實例化 // 方式一: 創建其子類 (GregorianCalendar)的對象 // 方式二:調用其靜態方法getInstance() // 兩種創建方法本質上一樣 Calendar calendar = Calendar.getInstance(); System.out.println(calendar.getClass()); // 2.常用方法 //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); //add() calendar.add(Calendar.DAY_OF_MONTH,-3); days = calendar.get(Calendar.DAY_OF_MONTH); System.out.println(days); //getTime(): 日歷類-->Date Date date = calendar.getTime(); System.out.println(date); //setTime(): Date--->日歷類 Date date1 = new Date(); calendar.setTime(date1); days = calendar.get(Calendar.DAY_OF_MONTH); System.out.println(days); }}
注意
- 獲取月份時:一月是0,二月是1,以此類推12月是11
- 獲取星期時:周日是1,周二是2.。。。周六是7
3.5 JDK8 之前時間日期api的一些問題
如果我們可以跟別人說:“我們在1502643933071見晚了!”那么就再簡單不過了。但是我們希望時間與量夜和四季有關,於是事情就變復雜了。JDK10中包含了個 java util. Date類,但是它的大多數方法已經在JDK11引入 Calendar類之后被棄用而 Calendar並不比Date好多少。它們面臨的問題是:
**可變性: **像日期和時間這樣的類應該是不可變的。
**偏移性: **Date中的年份是從1900開始的,而月份都從0開始。
格式化: 格式化只對Date有用, Calendar則不行
此外,它們也不是線程安全的;不能處理閏秒等。
因此我們需要引入 以下 新的時間日期api來處理這些問題。
4. JDK8 中新的時間日期 api
- 第三次引入的API是成功的,並且Java8中引入的 java. time API 已經糾正了過去的缺陷,將來很長一段時間內它都會為我們服務。
- Java8 吸收了Joda-Time的精華,以一個新的開始為Java創建優秀的AP新的 java. time中包含了所有關於本地日期( LocalDate)、本地時間( LocalTime)、本地日期時間( LocalDate Time)、時區( Zoned Date Time)和持續時間( Duration)的類。歷史悠久的Date類新增了 tolnstant()方法,用於把Date轉換成新的表示形式。這些新增的本地化時間口期 API 大大簡化了日期時間和本地化的管理。
- 在JDK8 之前joda-time是作為jar包的形式導入項目使用的,在jdk8 的時候官方將其引入.
4.1 LocalDate、LocalTime、LocalDateTime 類的使用
實例化:
- 實例化方式一:使用靜態方法
now() / now(zoneld zone)獲取當前的日期時間 - 實例化方式二:使用靜態方法
of()自定義時間,無 Date 中偏移量的問題
方法 :
-
now() / now(zoneld zone) -
of() -
getXxx()獲取相關屬性 -
withXxxx()設置相關屬性 -
plusXxx()在現有基礎上加上指定數據 -
minusXxx()在現有基礎上減去指定數據
說明 :
- 三個類都具有不可變性
- LocalDateTime 相較於 LocalDate , LocalTime 使用頻率更高
- 類似於 jdk8 之前的 Calendar 類
Demo:
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;/** * jdk 8 中的時間日期 api * * @author 13roky * @date 2021-05-10 7:05 */public class JDK8DateTimeTest { /* LocalDate、LocalTime、LocalDateTime 類的使用: */ @Test public void test01(){ // 實例化方式一:使用靜態方法 now() / now(zoneld zone) 獲取當前的日期時間 LocalDateTime localDateTime = LocalDateTime.now(); LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); System.out.println(localDateTime); System.out.println(localDate); System.out.println(localTime); // 實例化方式二:of() 可以自定義時間,無 Date 中偏移量的問題 LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 1, 4, 23, 43); System.out.println(localDateTime1); // getXxx() 獲取相關屬性 System.out.println(localDateTime.getDayOfMonth()); System.out.println(localDateTime.getDayOfWeek()); System.out.println(localDateTime.getMonth()); System.out.println(localDateTime.getMonthValue()); System.out.println(localDateTime.getMinute()); // withXxxx() 設置相關屬性, 具有不可變性 LocalDate localDate1 = localDate.withDayOfMonth(20); System.out.println(localDate1); LocalDateTime localDateTime2 = localDateTime.withHour(16); System.out.println(localDateTime); System.out.println(localDateTime2); //plusXxx() 在現有基礎上加上指定數據 LocalDateTime localDateTime3 = localDateTime.plusMonths(3); System.out.println(localDateTime); System.out.println(localDateTime3); // minusXxx() 在現有基礎上減去指定數據 LocalDateTime localDateTime4 = localDateTime.minusMonths(3); System.out.println(localDateTime); System.out.println(localDateTime4); }}
4.2 Instant 類的使用
- Instant : 時間線上的瞬時點. 這可能被用來記錄應用程序中的事件時間戳.
方法 :
now()靜態方法, 返回 UTC 時區的 Instant 類對象atOffset()添加 默認時區 與 當前需要時區 的 時間 的 偏移量toEpochMilli()獲取 1970年1月1日0時0分0秒 (UTC) 開始的毫秒數ofEpochMilli()靜態方法, 通過給定的毫秒數獲取 Instant 的實例
Demo :
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.time.*;/** * jdk 8 中的時間日期 api * * @author 13roky * @date 2021-05-10 7:05 */public class JDK8DateTimeTest { /* Instant 的使用 */ @Test public void test02() { // now : 獲取本初子午線的時間 Instant instant = Instant.now(); //格林威治時間 System.out.println(instant); // 添加 默認時區 與 當前需要時區 的 時間 的 偏移量 OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8)); System.out.println(offsetDateTime); // 獲取 1970年1月1日0時0分0秒 (UTC) 開始的毫秒數 long milli = instant.toEpochMilli(); System.out.println(milli); // ofEpochMilli 通過給定的毫秒數獲取 Instant 的實例 Instant instant1 = Instant.ofEpochMilli(1620783200875L); System.out.println(instant1); }}
4.3 DateTimeFormatter 類
用於格式化和解析 LocalDate、LocalTime、LocalDateTime
類似於 SimpleDateFormat
格式化方式 :
- 預定義的標准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME;
- 本地化相關的格式。如:ofLocalizedDateTime(FormatStyle.LONG);
- 自定義的格式。如:ofPattern("yyyy-MM-dd hh:mm:ss E");
解析方式 :
parse()方法
Demo :
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.time.*;import java.time.format.DateTimeFormatter;import java.time.format.FormatStyle;import java.time.temporal.TemporalAccessor;/** * jdk 8 中的時間日期 api * * @author 13roky * @date 2021-05-10 7:05 */public class JDK8DateTimeTest { /* DateTimeFormatter:格式化或解析日期、時間 類似於SimpleDateFormat */ @Test public void test03() { // 方式一:預定義的標准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME; DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); String s = formatter.format(localDateTime); System.out.println(s); // 因為使用標准格式進行格式化,所以 localDateTime 格式化前后的值基本沒有變化,但是類型變變為了 String // 解析:字符串-->日期 TemporalAccessor parse = formatter.parse("2021-05-12T20:48:52.1539765"); System.out.println(parse); // 方式二: // 本地化相關的格式。如:ofLocalizedDateTime(FormatStyle.LONG); // FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 適用於LocalDateTime DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM); String s1 = formatter1.format(localDateTime); System.out.println(s1); // 本地化相關的格式。如:ofLocalizedDate() // FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 適用於LocalDateTime DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL); String s2 = formatter2.format(LocalDate.now()); System.out.println(s2); /* 可能會報錯 : java.time.DateTimeException: Unable to extract ZoneId from temporal 參考:https://stackoverflow.com/questions/59531046/java-time-datetimeexception-unable-to-extract-zoneid-from-temporal */ // 方式三:自定義的格式。如:ofPattern("yyyy-MM-dd hh:mm:ss E"); DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"); String s3 = formatter3.format(localDateTime); System.out.println(s3); // 解析 TemporalAccessor parse1 = formatter3.parse("2021-05-12 09:24:47"); System.out.println(parse1); }}
4.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 的實現。
5. Comparable 和 Comparator 接口
5.1 Comparable 接口 自然排序
用於對象與對象的比較, Comparable屬於自然排序
說明:
Java中的對象, 正常情況下, 只能進行比較:==或!= 不能使用>或<
但是在開發場景中, 我們需要對多個對象進行排序, 言外之意, 就需要比較對象的大小
使用兩個接口中的任何一個來實現: Comparable 或 Comparator
Comparable 接口的使用舉例 :
1. 像 String, 包裝類等實現了 Comparable 接口, 重寫了 `compareTo(obj)` 方法, 給出了比較兩個對象
2. 像 String, 包裝類重寫了`compareTo()`方法以后, 進行了從小到大的排列
3. 重寫 `compareTo(obj)` 的規則:
如果當前對象 this 等於形參對象 obj, 則返回為零
如果當前對象 this 小於形參對象 obj, 則返回負整數
如果當前對象 this 大於形參對象 obj, 則返回正整數
4. **對於自定義類來說**, 如果需要排序, 我們可以讓自定義類實現 Comparable 接口, 重寫 `compareTo(obj)` 方法並在 `compareTO(obj)` 方法中指明如何排序
Demo:
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.util.Arrays;/** * 1) 說明: Java中的對象, 正常情況下, 只能進行比較:==或!= 不能使用>或< * 但是在開發場景中, 我們需要對多個對象進行排序, 言外之意, 就需要比較對象的大小 * 如何實現? 使用兩個接口中的任何一個: Comparable 或 Comparator * 2) Comparable 接口的使用 * * @author 13roky * @date 2021-05-12 22:15 */public class CompareTest { /* Comparable 接口的使用舉例: 自然排序 1. 像 String, 包裝類等實現了 Comparable 接口, 重寫了 compareTo(obj) 方法, 給出了比較兩個對象 2. 像 String, 包裝類重寫了compareTo()方法以后,進行了從小到大的排列 3. 重寫 compareTo(obj) 的規則: 如果當前對象 this 等於形參對象 obj, 則返回為零 如果當前對象 this 小於形參對象 obj, 則返回負整數 如果當前對象 this 大於形參對象 obj, 則返回正整數 4. 對於自定義類來說, 如果需要排序, 我們可以讓自定義類實現 Comparable 接口, 重寫compareTo(obj) 方法 在 compareTO(obj) 方法中知名如何排序 */ @Test public void test01(){ String[] arr = new String[]{"aa","cc","kk","mm","gg","jj","dd"}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); } @Test public void test02() { Goods[] arr = new Goods[4]; 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[3] = new Goods("MicroSoftiMouse",12); // 根據arr所對應類的CompareTo方法排序 Arrays.sort(arr); System.out.println(Arrays.toString(arr)); }}
package com.broky.commonClass;/** * 商品類 實現Comparable方法 * * @author 13roky * @date 2021-05-12 22:42 */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 { // 字符串類型的本身就有 compareTo 方法 return this.name.compareTo(goods.name); // return -this.name.compareTo(goods.name); 加了負號變成了從高到低排 } // 方式二 //return Double.compare(this.price,goods.price); } throw new RuntimeException("傳入的數據類型不一致"); }}
5.2 Comparator 接口 定制排序
根據定制的規則進行比較, Comparator屬於定制排序
當元素的類型沒有實現java.lang.Comparable 接口而又不方便修改代碼,或者實現了java.lang.Comparable 接口的排序規則不適合當前的操作, 那么可以使用 Compare(obj o1,obj o2)方法, 比較o1和o2的大小
說明 :
- 當元素的類型沒有實現java.lang.Comparable接口而又不方便修改代碼, 或者實現了java.lang.Comparable接口的排序規則不適合當前的操作,那么可以考慮使用 Comparator 的對象來排序,強行對多個對象進行整體排序的比較。
使用 :
- 在
Arrays.sort()方法中使用匿名內部類的方法實現定制排序 (詳情見Demo)
**Comparable 接口與 Comparator 的使用的對比 : **
-
Comparable 接口的方式一旦實現,保證 Comparable 接口實現類的對象在任何位置都可以比較大小
-
Comparator 接口屬於臨時性的比較.
Demo :
package com.broky.commonClass;import org.junit.jupiter.api.Test;import java.util.Arrays;import java.util.Comparator;/** * 1) 說明: Java中的對象, 正常情況下, 只能進行比較:==或!= 不能使用>或< * 但是在開發場景中, 我們需要對多個對象進行排序, 言外之意, 就需要比較對象的大小 * 如何實現? 使用兩個接口中的任何一個: Comparable 或 Comparator * 2) Comparable 接口與 Comparator 的使用的對比 * Comparable 接口的方式一旦實現,保證 Comparable 接口實現類的對象在任何位置都可以比較大小 * Comparator 接口屬於臨時性的比較. * * @author 13roky * @date 2021-05-12 22:15 */public class CompareTest { /* Comparator 接口的使用: 定制排序 1. 背景 當元素的類型沒有實現java.lang.Comparable 接口而又不方便修改代碼, 或者實現了java.lang.Comparable 接口的排序規則不適合當前的操作 那么可以使用 Compare(obj o1,obj o2)方法, 比較o1和o2的大小 2. 重寫 Compare(obj o1,obj o2) 方法, 比較o1和o2的大小 如果方法返回正數,則表示o1大於o2 如果方法返回負數,則表示01小於02 如果方法返回0, 則表示相等 */ @Test public void test03(){ // 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("輸入的類型不一致"); } }); System.out.println(Arrays.toString(arr)); } @Test public void test04() { Goods[] arr = new Goods[5]; arr[0] = new Goods("lenovoMouse",34); arr[1] = new Goods("huaweiMouse",43); arr[2] = new Goods("xiaomiMouse",12); arr[3] = new Goods("huaweiMouse",65); arr[4] = new Goods("microSoftiMouse",12); 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()); } } throw new RuntimeException("輸入的數據類型不一致"); } }); System.out.println(Arrays.toString(arr)); }}
6. System 類
System類代表系統,系統級的很多屬性和控制方法都放置在該類的內部。 該類位於java.lang包。
由於該類的構造器是private的,所以無法創建該類的對象,也就是無法實 例化該類。其內部的成員變量和成員方法都是static的,所以也可以很方便 的進行調用。
成員方法 native long currentTimeMillis(): 該方法的作用是返回當前的計算機時間,時間的表達格式為當前計算機時 間和GMT時間(格林威治時間)1970年1月1號0時0分0秒所差的毫秒數。 void exit(int status): 該方法的作用是退出程序。其中status的值為0代表正常退出,非零代表 異常退出。使用該方法可以在圖形界面編程中實現程序的退出功能等。
成員變量 :
- System類內部包含in、out和err三個成員變量,分別代表標准輸入流 (鍵盤輸入),標准輸出流(顯示器)和標准錯誤輸出流(顯示器)。
成員方法 :
- native long currentTimeMillis(): 該方法的作用是返回當前的計算機時間,時間的表達格式為當前計算機時 間和GMT時間(格林威治時間)1970年1月1號0時0分0秒所差的毫秒數。
- void exit(int status): 該方法的作用是退出程序。其中status的值為0代表正常退出,非零代表 異常退出。使用該方法可以在圖形界面編程中實現程序的退出功能等。
- void gc(): 該方法的作用是請求系統進行垃圾回收。至於系統是否立刻回收,則 取決於系統中垃圾回收算法的實現以及系統執行時的情況。
- String getProperty(String key): 該方法的作用是獲得系統中屬性名為key的屬性對應的值。系統中常見 的屬性名以及屬性的作用如下表所示:

7. Math類
java.lang.Math提供了一系列靜態方法用於科學計算。
其方法的參數和返回 值類型一般為double型。
方法 :
- abs 絕對值
- acos,asin,atan,cos,sin,tan 三角函數
- sqrt 平方根
- pow(double a,doble b) a的b次冪
- log 自然對數
- exp e為底指數
- max(double a,double b)
- min(double a,double b)
- random() 返回0.0到1.0的隨機數
- long round(double a) double型數據a轉換為long型(四舍五入)
- toDegrees(double angrad) 弧度—>角度
- toRadians(double angdeg) 角度—>弧度
8. BigInteger 與 BigDecimal 類
用於操作較大的整數
8.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 對象
常用方法 :
public BigInteger abs():返回此 BigInteger 的絕對值的 BigInteger。
BigInteger add(BigInteger val) :返回其值為 (this + val) 的 BigInteger
BigInteger subtract(BigInteger val) :返回其值為 (this - val) 的 BigInteger
BigInteger multiply(BigInteger val) :返回其值為 (this * val) 的 BigInteger
BigInteger divide(BigInteger val) :返回其值為 (this / val) 的 BigInteger。整數 相除只保留整數部分。
BigInteger remainder(BigInteger val) :返回其值為 (this % val) 的 BigInteger。
BigInteger[] divideAndRemainder(BigInteger val):返回包含 (this / val) 后跟 (this % val) 的兩個 BigInteger 的數組。
BigInteger pow(int exponent) :返回其值為 (thisexponent) 的 BigInteger。
8.2 BigDecimal 類
類似於浮點型
說明 :
- 一般的Float類和Double類可以用來做科學計算或工程計算,但在商業計算中, 要求數字精度比較高,故用到java.math.BigDecimal類。
- BigDecimal 類支持不可變的、任意精度的有符號十進制定點數。
構造器 :
-
public BigDecimal(double val)
-
public BigDecimal(String val)
常用方法 :
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
Demo :
package com.broky.commonClass;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* @author 13roky
* @date 2021-05-13 12:56
*/
public class OtherClassTest {
@Test
public void testBigInteger() {
BigInteger bi = new BigInteger("12433241123");
BigDecimal bd = new BigDecimal("12435.351");
BigDecimal bd2 = new BigDecimal("11");
System.out.println(bi);
// BigDecimal.ROUND_HALF_UP 四舍五入
System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));
System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP));
}
}
