第十一章 常用類的概述和使用
11.1 常用包
11.1.1 包名和名稱
java.lang 包硅确,由虛擬機(jī)自動導(dǎo)入
java.util 包目溉,包含集合框架明肮,一些國際化支持類,服務(wù)加載程序停做,屬性晤愧,隨機(jī)數(shù)生成,字符串解析和掃描類蛉腌,base64編碼和解碼官份,位數(shù)組以及幾個其他實用程序類。
java.math 包烙丛,提供用于執(zhí)行任意精度整數(shù)算術(shù)(BigInteger)和任意精度十進(jìn)制算術(shù)(BigDecimal)的類
java.nio 定義緩沖區(qū)舅巷,緩沖區(qū)是數(shù)據(jù)的容器,并提供其他NIO包的概述河咽。
java.io包钠右, 通過數(shù)據(jù)流,序列化和文件系統(tǒng)提供系統(tǒng)輸入和輸出
11.2 Object類(重點)
11.2.1 基本概述
Object類是所有類的基類忘蟹,所有對象和數(shù)組都繼承實現(xiàn)Object類的方法飒房。
public class MyClass{}
等價于
public class MyClass extends Object {}
11.2.2 equals方法
-
public boolean equals?(Object obj)
返回其他某個對象是否“等于”該對象的比較結(jié)果
-
代碼測試
創(chuàng)建student類
public class Student { private String name; private int id; public Student(String name, int id) { this.name = name; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public boolean equals(Object obj) { //當(dāng)如果兩個對象指向同一個地址引用的時候,一定為true if (this == obj) { return true; } //當(dāng)傳入的對象為null時候媚值,一定是為false if (obj == null) { return false; } //重寫equals方法用來實現(xiàn)兩個對象ID的比較 if (obj instanceof Student) { Student flag = (Student) obj; return this.id == flag.getId(); } return false; } @Override public int hashCode() { return getId(); } }
測試代碼
//創(chuàng)建兩個student對象
Student student1 = new Student("fuyi", 1000);
Student student2 = new Student("fuyi", 1000);
Student student3 = student1;
System.out.println("-------------------------equals()--------------------------");
//1. 調(diào)用Object類中equals方法
//2. 通過下面兩種方式進(jìn)行測試Object類的equals方法狠毯,用來比較的是兩個對象的引用是否相等
//3. Object類源碼層次
/**
* public boolean equals(Object obj) {
* return (this == obj);
* }
*/
//4. 如果通過equals方法比較兩個對象的id是否相等,則需要重寫Object基類的equals方法
System.out.println(student1.equals(student2)); //false -> true
System.out.println(student1 == student2); //false
System.out.println(student3 == student1); //true
內(nèi)存分析
11.2.3 hashCode方法
-
public int hashCode()
返回對象的哈希碼值褥芒。支持此方法是為了使哈希表(例如HashMap提供的哈希表)提供協(xié)助功能嚼松。就是在后面集合HashMap存儲元素的時候會調(diào)用該方法。
-
代碼測試
重寫自定義類中的hashCode()方法
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return id == student.id && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(name, id); }
運行測試
System.out.println("------------------------hashCode()--------------------------"); //1. 調(diào)用Object類中的hashCode()方法 //2. Java官方常規(guī)約束锰扶,調(diào)用equals()方法比較的結(jié)果的相同献酗,那么調(diào)用hashCode()獲取兩個對象的結(jié)果也應(yīng)該相同,所以我們需要重寫基類中的hashCode()方法 //3. 這里只要求約束為equals比較結(jié)果相等的兩個對象坷牛,調(diào)用hashCode方法結(jié)果也相等就可以了 System.out.println(student1.hashCode()); //1300109446 -> 1000 System.out.println(student2.hashCode()); //1020371697 -> 1000
11.2.3 toString方法
-
public String toString()
返回對象的字符串表示形式罕偎。 通常,toString方法返回一個“以文本形式表示”此對象的字符串漓帅。 結(jié)果應(yīng)該是簡潔易懂的表示形式锨亏,便于人們閱讀。
建議所有子類都重寫此方法忙干。 Object類的toString方法返回一個字符串,該字符串包括該對象是其實例的類的名稱浪藻,符號字符“ @”以及該對象的
哈希碼的無符號十六進(jìn)制表示形式捐迫。 換句話說,此方法返回的字符串等于:
getClass().getName() + '@' + Integer.toHexString(hashCode()) -
代碼測試
重寫Student類中toString()方法
@Override public String toString() { return "Student{" + "name='" + name + '\'' + ", id=" + id + '}'; }
運行打印
System.out.println("------------------------toString()---------------------------"); //1. 調(diào)用Object類中的toString()方法 //2. 為了返回更有意義的字符串信息需要重寫toString()方法 //3. 直接打印對象和字符串拼接爱葵,默認(rèn)調(diào)用toString方法 System.out.println(student1.toString()); //com.ryan.stage1.model3.task11.Student@3e8 -> Student{name='fuyi', id=1000} System.out.println(student2.toString()); //com.ryan.stage1.model3.task11.Student@3e8 -> Student{name='fuyi', id=1000} System.out.println(student1); //com.ryan.stage1.model3.task11.Student@3e8 -> Student{name='fuyi', id=1000} System.out.println(student2); //com.ryan.stage1.model3.task11.Student@3e8 -> Student{name='fuyi', id=1000} System.out.println("打印結(jié)果:" + student1); //打印結(jié)果:com.ryan.stage1.model3.task11.Student@3e8 -> 打印結(jié)果:Student{name='fuyi', id=1000} System.out.println("打印結(jié)果:" + student2); //打印結(jié)果:com.ryan.stage1.model3.task11.Student@3e8 -> 打印結(jié)果:Student{name='fuyi', id=1000}
11.2.4 getClass方法
-
public final Class<?> getClass()
返回此對象的運行時類施戴。返回的Class對象是被表示的類的靜態(tài)同步方法鎖定的對象
-
代碼demo
System.out.println("------------------------getClass()----------------------------"); //1. 獲取該對象的實例反浓,常用于反射機(jī)制 System.out.println(student1.getClass()); //class com.ryan.stage1.model3.task11.Student System.out.println(student2.getClass()); //class com.ryan.stage1.model3.task11.Student
11.2.5 自動重寫equals、hashCode和toString方法
-
Idea編輯器快捷鍵
window:alt + insert快捷鍵
11.3 包裝類(熟悉)
-
背景
在 Java 的設(shè)計中提倡一種思想赞哗,即一切皆對象雷则。但是從數(shù)據(jù)類型的劃分中,我們知道 Java 中的數(shù)據(jù)類型分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型肪笋,
但是基本數(shù)據(jù)類型怎么能夠稱為對象呢月劈?于是 Java 為每種基本數(shù)據(jù)類型分別設(shè)計了對應(yīng)的類,稱之為包裝類(Wrapper Classes)藤乙,也有地方稱為外覆類或數(shù)據(jù)類型類猜揪。
11.3.1 基本概念
Java給每一種基本數(shù)據(jù)類型進(jìn)一步封裝成了一個類,這個類就叫做包裝類坛梁。
-
映射關(guān)系
byte -> Byte short -> Short int -> Integer long -> Long char -> Character float -> Float double -> Double boolean -> Boolean
11.3.2 裝箱與拆箱
基本數(shù)據(jù)類型轉(zhuǎn)換為包裝類的過程稱為裝箱而姐,例如把 int 包裝成 Integer 類的對象(int -> Integer);
包裝類變?yōu)榛緮?shù)據(jù)類型的過程稱為拆箱划咐,例如把 Integer 類的對象重新簡化為 int(Integer -> int)拴念。
11.3.3 Integer類的構(gòu)造方式
-
代碼demo
System.out.println("-------------------Integer類常見屬性成員---------------------"); System.out.println("占用字節(jié)數(shù):" + Integer.BYTES); //占用字節(jié)數(shù):4 System.out.println("最大表示正數(shù):" + Integer.MAX_VALUE); //最大表示正數(shù):2147483647 System.out.println("最大表示負(fù)數(shù):" + Integer.MIN_VALUE); //最大表示負(fù)數(shù):-2147483648 System.out.println("用于表示二進(jìn)制補碼二進(jìn)制形式的int值的位數(shù):" + Integer.SIZE); //用于表示二進(jìn)制補碼二進(jìn)制形式的int值的位數(shù):32 System.out.println("表示原始類型int的Class實例:" + Integer.TYPE); //表示原始類型int的Class實例:int System.out.println("-------------------Integer構(gòu)造方法-----------------------"); //1. Integer(int i)構(gòu)造 //2. Integer(String s) 構(gòu)造 //3. 上述兩種構(gòu)造在JDK9已經(jīng)被遺棄,提供了靜態(tài)工廠構(gòu)造方法valueOf(int i)和valueOf(String s) Integer integer1 = new Integer(123456); Integer integer2 = new Integer("789"); Integer integer3 = Integer.valueOf(123456); Integer integer4 = Integer.valueOf("789");
11.3.4 Integer類的裝箱和拆箱機(jī)制
-
代碼demo
System.out.println("-----------------Integer類的裝箱和拆箱機(jī)制-----------------------------------------------"); //JDK5 新增自動拆裝箱機(jī)制 //1. int -> Integer 裝箱 //自動裝箱 Integer integer5 = 100; //2. Integer -> int 拆箱 //自動拆箱 int i5 = integer5;
-
筆試考點
//3. 筆試考點 //主要考察自動裝箱池機(jī)制褐缠,JVM自動將-128到127的正數(shù)進(jìn)行提前裝箱政鼠,當(dāng)調(diào)用到時,直接賦引用地址調(diào)用池中的對象送丰,提高效率 //Double類沒有自動裝箱池 Integer integer6 = 127; //128 -> 127 Integer integer7 = 127; //128 -> 127 Integer integer8 = new Integer(127); //128 -> 127 Integer integer9 = new Integer(127); //128 -> 127 System.out.println(integer6 == integer7); //false -> true System.out.println(integer6.equals(integer7)); //true -> true System.out.println(integer8 == integer9); //false -> false System.out.println(integer8.equals(integer9)); //true -> true
11.3.5 Integer缔俄、int和String類型之間轉(zhuǎn)換
-
代碼demo
System.out.println("------------------Integer、int和String類型之間轉(zhuǎn)換-------------------------------"); //1. Integer和int之間轉(zhuǎn)換器躏,int轉(zhuǎn)成Integer使用構(gòu)造方法進(jìn)行轉(zhuǎn)換 int intValue = integer1.intValue(); System.out.println("Integer -> int :" + intValue); //Integer -> int :123456 //2. Integer -> String String s = integer2.toString(); System.out.println("Integer -> String :" + s); //Integer -> String :789 //3. String -> int int i = Integer.parseInt("345"); System.out.println("String -> int :" + i); //String -> int :345 //4. int -> String System.out.println("int -> String :" + Integer.toString(98)); //int -> String :98 System.out.println("int -> String :" + Integer.toBinaryString(98)); //int -> String :1100010
11.3.5 Double類
各個基本數(shù)據(jù)類型的包裝類的方法都大同小異俐载,就不再加以論述了。
-
常用方法
System.out.println("---------------------常用方法------------------------"); //1. 判斷是否為非數(shù)值 Double double1 = new Double(187.293847); double v = Double.parseDouble("18.983"); System.out.println("是否為非數(shù)值:" + double1.isNaN()); //是否為非數(shù)值:false System.out.println("是否為非數(shù)值:" + Double.isNaN(v)); //是否為非數(shù)值:false
11.3.6 Boolean類
-
Boolean類的自動裝箱和自動拆箱
System.out.println("----------------Boolean類的自動裝箱和自動拆箱----------------"); //1. JDK5之前 //裝箱 Boolean boolean1 = Boolean.valueOf("true"); System.out.println(boolean1); //true //拆箱 boolean b = boolean1.booleanValue(); System.out.println(b); //true //2. JDK5之后 //自動裝箱和自動拆箱 Boolean boolean2 = false; boolean b2 = boolean2; System.out.println(b2); //false
11.3.7 wrapper類總結(jié)
基本類型轉(zhuǎn)換為包裝類的方式:調(diào)用構(gòu)造和靜態(tài)方法登失;
獲取包裝類中的基本數(shù)據(jù)類型方式:調(diào)用包裝類中xxxValue方法即可遏佣;
字符串轉(zhuǎn)基本數(shù)據(jù)類型的方式:調(diào)用包裝類中的parseXxx方法
11.4 數(shù)學(xué)處理類(熟悉)
11.4.1 Math類概念
用于提供執(zhí)行數(shù)學(xué)運算的方法
11.4.2 BigDecimal類
-
背景
通常平時我們使用double和float類型做加減乘除運算的時候不能很精確拐辽,BigDecimal類就可以很好的解決這個問題霹菊。
-
構(gòu)造方法
System.out.println("-----------------構(gòu)造方法--------------------"); BigDecimal bigDecimal1 = new BigDecimal("1.5"); BigDecimal bigDecimal2 = new BigDecimal("1.25");
-
常用方法
System.out.println("-----------------常用方法--------------------"); System.out.println("加法運算:" + bigDecimal1.add(bigDecimal2)); //2.75 System.out.println("減法運算:" + bigDecimal1.subtract(bigDecimal2)); //0.25 System.out.println("乘法運算:" + bigDecimal1.multiply(bigDecimal2)); //1.875 System.out.println("除法運算:" + bigDecimal1.divide(bigDecimal2)); //1.2
-
注意事項
System.out.println("-----------------注意事項---------------------"); BigDecimal bigDecimal3 = new BigDecimal("1.5"); BigDecimal bigDecimal4 = new BigDecimal("1.3"); System.out.println("除不盡小數(shù)處理:" + bigDecimal3.divide(bigDecimal4, RoundingMode.HALF_UP)); //1.2
11.4.3 BigInteger類概念
-
背景
有些時候long類型不能表示數(shù)可以使用BigInteger類進(jìn)行,畢竟long類型表示的范圍是有限的伏蚊。
-
構(gòu)造方法
System.out.println("-----------------構(gòu)造方法--------------------"); BigInteger bigInteger1 = new BigInteger("5"); BigInteger bigInteger2 = new BigInteger("3");
-
常用方法
System.out.println("-----------------常用方法--------------------"); System.out.println("加法運算:" + bigInteger1.add(bigInteger2)); //8 System.out.println("減法運算:" + bigInteger1.subtract(bigInteger2)); //2 System.out.println("乘法運算:" + bigInteger1.multiply(bigInteger2)); //15 System.out.println("除法運算:" + bigInteger1.divide(bigInteger2)); //1 BigInteger[] bigIntegers = bigInteger1.divideAndRemainder(bigInteger2); System.out.println("除法運算一次性獲取商和小數(shù):"); for (BigInteger bigInteger : bigIntegers) { System.out.println(bigInteger.floatValue()); //1.0 2.0 }
第十二章 String類的概述和常用方法使用
12.1 String類的概念(重點)
String類表示字符串馅巷。 Java程序中的所有字符串文字(例如“ abc”)都實現(xiàn)為此類的實例膛虫。 字符串是常量; 它們的值在創(chuàng)建后無法更改钓猬。 字符串緩沖區(qū)支持可變字符串稍刀。 由于String對象是不可變的,因此可以共享它們。 例如:
String str = "abc";
等價于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
12.2 常量池的概念(原理)
因為字符串是通過final關(guān)鍵字修飾的常量账月,因此JVM將首次出現(xiàn)的字符串放入到常量池里面综膀,如果后續(xù)代碼中再次出現(xiàn)相同的字符串,直接使用常量池里面的對象局齿,從而避免申請空間再次創(chuàng)建對象剧劝,節(jié)省資源開銷和提高性能。從另一方面可以得出String類字符串在底層是實現(xiàn)資源共享機(jī)制的抓歼。
12.3 常用構(gòu)造方法(熟練)
-
代碼demo
System.out.println("----------------常用構(gòu)造方法------------------"); //1. 無參構(gòu)造方法 //結(jié)果:創(chuàng)建了對象讥此,但是對象里面沒有內(nèi)容 String str1 = new String(); System.out.println("無參構(gòu)造打印:" + str1); //"" //2. 通過字節(jié)數(shù)組構(gòu)造 byte[] arr = {97, 98, 99, 100, 101}; //abcde String str2 = new String(arr); System.out.println("字節(jié)數(shù)組構(gòu)造:" + str2); //abcde String str3 = new String(arr, 2, 2);//cd System.out.println("字節(jié)數(shù)組構(gòu)造:" + str3); //3. 通過字符數(shù)組構(gòu)造 char[] brr = {'a', 'b', 'c', 'd', 'e'}; String str4 = new String(brr); System.out.println("字符數(shù)組構(gòu)造:" + str2); //abcde String str5 = new String(brr, 2, 3); System.out.println("字符數(shù)組構(gòu)造:" + str5); //cde //4. 字符串構(gòu)造方法 String str6 = new String("hello world"); System.out.println("字符串?dāng)?shù)組構(gòu)造:" + str6); //hello world
12.4 String類筆試考點
-
代碼demo
System.out.println("------------------筆試扯Р浚考內(nèi)容------------------"); //1. 常量池和堆區(qū)的內(nèi)容比較 String str1 = "abcd"; //該過程創(chuàng)建一個對象 String str2 = "abcd"; String str3 = new String("abcd"); //該過程創(chuàng)建兩個對象(1個在常量池中暂论,1個在堆區(qū)里面) String str4 = new String("abcd"); System.out.println(str1 == str2); //true System.out.println(str1.equals(str2)); //true System.out.println(str3 == str4); //false System.out.println(str3.equals(str4)); //true System.out.println(str1 == str3); //false System.out.println(str1.equals(str3)); //true System.out.println("----------------------------------------------------"); //2. 字符串拼接比較 String str5 = "abcd"; String str6 = "abc" + "d"; System.out.println(str5 == str6); //true System.out.println(str5.equals(str6)); //true System.out.println(str6 == str3); //false System.out.println(str6.equals(str3)); //true System.out.println("----------------------------------------------------"); //3. 變量與常量拼接比較 String str7 = "ab"; String str8 = str7 + "cd"; System.out.println(str1 == str8); //false System.out.println(str8.equals(str1)); //true System.out.println(str8 == str3); //false System.out.println(str8.equals(str3)); //true
12.5 String回文判斷
-
代碼demo
System.out.println("------------String回文判斷--------------"); String str1 = "上海自來水來自海上"; for (int i = 0; i < str1.length()/2; i++) { if (str1.charAt(i) != str1.charAt(str1.length()-1-i)) { System.out.println("字符串" + str1 + "不是回文"); return; } } System.out.println("字符串" + str1 + "是回文");
12.6 String實現(xiàn)字符串之間大小比較
-
代碼demo
String str1 = "hello"; System.out.println(str1.compareTo("hetto")); // 76-84 = -8 System.out.println(str1.compareTo("gto")); // 72-71 = 1 System.out.println(str1.compareToIgnoreCase("HELLO")); //0
12.7 String、byte數(shù)組和char數(shù)組間轉(zhuǎn)換
-
代碼demo
System.out.println("------------------String拌禾、byte數(shù)組和char數(shù)組間轉(zhuǎn)換-----------------------"); System.out.println("------------------String -> byte數(shù)組-----------------------"); //1. String -> byte[] String str1 = "fuyi"; byte[] brr = str1.getBytes(); for (byte b : brr) { System.out.println(b); } System.out.println("------------------String -> char數(shù)組-----------------------"); //2. String -> char[] char[] crr = str1.toCharArray(); for (char c : crr) { System.out.println(c); }
12.8 字符與字符串查找
-
代碼demo
String str1 = "Good Good study, Day Day up!"; String str3 = str1 + "bn"; int g = str1.indexOf('g'); System.out.println(g); int g1 = str1.indexOf("G"); System.out.println(g1); int g2 = str1.indexOf('G', 1); System.out.println(g2); //2. 查找字符串 int day = str1.indexOf("Day"); System.out.println(day); //第一次出現(xiàn)的位置 System.out.println("----------通過上述字符串中出現(xiàn)指定字符串的所有位置--------"); int pos = 0; while ((pos = str1.indexOf("Day", pos)) != -1) { System.out.println("pos = " + pos); pos += "Day".length(); } System.out.println("-----實現(xiàn)字符串的反向查找-----------"); int g3 = str1.lastIndexOf('G'); System.out.println(g3); int g4 = str1.lastIndexOf('G', 5); System.out.println(g4); int day1 = str1.lastIndexOf("Day"); System.out.println(day1); int day2 = str1.lastIndexOf("Day", 5); System.out.println(day2);
12.9 subString()方法
-
代碼demo
String str1 = "Happy Life"; //1. 從下標(biāo)為3開始截取字符串 String substring = str1.substring(3); System.out.println(substring); //2. 截取指定范圍內(nèi)的子字符串 String substring1 = str1.substring(3, 5); System.out.println(substring1);
12.10 正則表達(dá)式(了解)
- 概念:本質(zhì)是一個規(guī)則字符串取胎,對字符串?dāng)?shù)據(jù)進(jìn)行格式校驗驗證、以及匹配替換湃窍、查找等操作闻蛀。該字符通常使用^運算符作為開頭標(biāo)志,使用$運算符作為結(jié)尾標(biāo)志您市,當(dāng)然也可以省略
12.11 正則表達(dá)式相關(guān)的方法(熟悉)
-
正則表達(dá)式校驗
System.out.println("------正則表達(dá)式校驗----------"); //正則表達(dá)式只能對數(shù)據(jù)格式進(jìn)行驗證觉痛,無法對數(shù)據(jù)內(nèi)容的正確性進(jìn)行驗證 //描述銀行卡密碼的規(guī)則:由6位數(shù)字組成 String reg = "[0-9]{6}"; //要求非0開頭的5~15為數(shù)字組成 String reg2 = "[1-9]\\d{4,14}"; //6位代表地區(qū),4位代表年茵休,2位代表月薪棒,2位代表日期,3位代表個人榕莺,最后一位有可能是X俐芯,共18位 String reg3 = "(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9|X])"; //2. 提示用戶從控制臺輸入 Scanner scanner = new Scanner(System.in); while (true) { System.out.println("請輸入銀行卡密碼:"); String next = scanner.next(); //3. 判斷用戶輸入的銀行卡是否滿足條件 if (next.matches(reg)) { System.out.println("輸入的銀行卡密碼符合要求"); break; } else { System.out.println("輸入的銀行卡密碼不符合要求"); } } }
-
替換
String str1 = "i am fuyi"; String[] sArr = str1.split(" "); for (String s : sArr) { System.out.println(s); } System.out.println("------------匹配替換----------"); //將出現(xiàn)的替換字符串全部轉(zhuǎn)換 String str2 = "i am handsome boy"; String replace = str2.replace("boy", "girl"); System.out.println(replace); System.out.println("-------------replaceFirst()-------"); String str3 = "ajdfjaljsldjfljsljfdl"; String str4 = str3.replaceFirst("j", "4"); System.out.println(str4); String str5 = str3.replaceAll("j", "4"); System.out.println(str5);
第十三章 可變長字符串和日期相關(guān)類
13.1 可變長字符串類(重點)
13.1.1 基本概念
背景:因為String類描述的字符串內(nèi)容是個常量不可以改變,但是有的時候我們需要描述大量長度變動的字符串時钉鸯,
只能單純的申請內(nèi)存吧史,此時會造成空間上的浪費。
解決問題:StringBuilder和StringBuffer類可以描述可以改變的字符串唠雕。
區(qū)別:StringBuffer是1.0存在贸营,線程安全,效率低岩睁;StringBuilder是1.5提出钞脂,線程不安全,效率高捕儒。
13.1.2 StringBuilder常用構(gòu)造方法
StringBuilder()
StringBuilder(int capacity)
StringBuilder(String str)
-
代碼demo
System.out.println("------StringBuilder類方法-------"); //1. 無參構(gòu)造 StringBuilder stringBuilder1 = new StringBuilder(); System.out.println("stringBuilder1 = " + stringBuilder1); System.out.println("容量是:" + stringBuilder1.capacity()); System.out.println("長度是:" + stringBuilder1.length()); //2. 指定容量構(gòu)造 System.out.println("----------指定容量構(gòu)造------------"); StringBuilder stringBuilder2 = new StringBuilder(20); System.out.println("stringBuilder2 = " + stringBuilder2); System.out.println("容量是:" + stringBuilder2.capacity()); System.out.println("長度是:" + stringBuilder2.length()); //3. 指定字符串構(gòu)造 System.out.println("---------- 指定字符串構(gòu)造------------"); StringBuilder stringBuilder3 = new StringBuilder("jlsjljg"); System.out.println("stringBuilder3 = " + stringBuilder3); System.out.println("容量是:" + stringBuilder3.capacity()); System.out.println("長度是:" + stringBuilder3.length());
13.1.3 StringBuilder常用成員方法和StringBuilder與String之間的轉(zhuǎn)換
-
常用方法
//3. 指定字符串構(gòu)造 System.out.println("---------- 指定字符串構(gòu)造------------"); StringBuilder stringBuilder3 = new StringBuilder("jlsjljg"); System.out.println("stringBuilder3 = " + stringBuilder3); System.out.println("容量是:" + stringBuilder3.capacity()); System.out.println("長度是:" + stringBuilder3.length()); //4. 插入和追加字符串內(nèi)容 System.out.println("---------- 插入和追加字符串內(nèi)容------------"); StringBuilder stringBuilder4 = stringBuilder3.insert(0, "fuyi"); System.out.println("stringBuilder4 = " + stringBuilder4); System.out.println(stringBuilder3 == stringBuilder4); //末尾追加字符串 stringBuilder4.append("china"); System.out.println(stringBuilder3); //5. 刪除字符串 System.out.println("----------刪除字符串 ------------"); //每次刪除一個字符芳肌,后面的字符會在往前補位,下標(biāo)會發(fā)生變化 stringBuilder3.deleteCharAt(0); System.out.println(stringBuilder3); //刪除下標(biāo)為0-3的字符 stringBuilder3.delete(0, 3); System.out.println(stringBuilder3); //6. 替換內(nèi)容和字符串翻轉(zhuǎn) System.out.println("---------替換內(nèi)容和字符串翻轉(zhuǎn)--------"); stringBuilder3.setCharAt(0, 'F'); System.out.println(stringBuilder3); // 修改字符串 stringBuilder3.replace(0, 3, "fu"); System.out.println(stringBuilder3); // 翻轉(zhuǎn)字符串 stringBuilder3.reverse(); System.out.println(stringBuilder3);
-
StringBuilder與String之間的轉(zhuǎn)換
//3. 指定字符串構(gòu)造 System.out.println("---------- 指定字符串構(gòu)造------------"); StringBuilder stringBuilder3 = new StringBuilder("jlsjljg"); System.out.println("stringBuilder3 = " + stringBuilder3); System.out.println("容量是:" + stringBuilder3.capacity()); System.out.println("長度是:" + stringBuilder3.length()); //7. StringBuilder <-> String String s = stringBuilder3.toString(); StringBuilder stringBuilder = new StringBuilder(s); StringBuilder stringBuilder5 = new StringBuilder("1"); StringBuilder stringBuilder6 = new StringBuilder("2"); StringBuilder append = stringBuilder5.append(stringBuilder6); stringBuilder6 = stringBuilder5; System.out.println(stringBuilder5); System.out.println(stringBuilder6);
13.1.4 StringBuilder擴(kuò)容機(jī)制
默認(rèn)擴(kuò)容機(jī)制:原始用量*2+2
13.1.5 筆試考點
- StringBuilder類對象本身可以修改肋层,為什么成員方法還有返回值呢亿笤?
為了鏈?zhǔn)骄幊蹋喕a
如何實現(xiàn)StringBuilder與String對象間轉(zhuǎn)換栋猖?
-
String净薛、StringBuilder和StringBuffer三者效率問題?
String < StringBuffer < StringBuilder
-
Idea快捷鍵
Ctrl+Alt+左右方向鍵 返回代碼的上次位置
13.2 JDK8之前的日期相關(guān)類(熟悉)
13.2.1 System類
作用:提供有用的類字段和方法
-
常用方法:
- static long currentTimeMillis() 獲取距離1970.01.01.00.00.00的毫秒數(shù)(通常用于測試代碼的執(zhí)行效率)
13.2.2 Date類
作用:Date類表示特定的時間瞬間蒲拉,精度為毫秒
-
常見構(gòu)造方法
//1. 無參構(gòu)造 Date date1 = new Date(); System.out.println(date1); //Tue Nov 24 11:08:31 CST 2020 //2. 指定毫秒數(shù)構(gòu)造 Date date2 = new Date(30000); System.out.println(date2); //Thu Jan 01 08:00:30 CST 1970
-
常用方法:
Date()
Date(long date)
long getTime()
void setTime(long time)
-
代碼demo
//1. 無參構(gòu)造 Date date1 = new Date(); System.out.println(date1); //Tue Nov 24 11:08:31 CST 2020 //3. 獲取距離1970.01.01.00:00:00的毫秒數(shù) long time = date1.getTime(); System.out.println(time); //1606187311955 //4. 設(shè)置調(diào)用對象為距離基準(zhǔn)時間多少毫秒的時間點 date1.setTime(1000); System.out.println(date1); //Thu Jan 01 08:00:01 CST 1970
13.2.3 SimpleDateFormat類
作用:實現(xiàn)日期和文本之間的轉(zhuǎn)換
-
常用方法
SimpleDate()
SimpleDateFormat(String pattern)
format(Date date) 日期 -> 文本
Date parse(String source) 文本 -> 日期
//1. 獲取當(dāng)前時間 Date date = new Date(); //2. 構(gòu)造SimpleDateFormat類型并指定格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //3. 日期 -> 文本 String format = simpleDateFormat.format(date); System.out.println(format);
13.2.4 Calendar類
作用:取代Date()肃拜,指定年月日時分秒構(gòu)造對象
-
常用方法:
- getInstance() 獲取實例對象
-
代碼demo
//1. 獲取Calendar類型的引用 Calendar instance = Calendar.getInstance(); System.out.println(instance); //2. 設(shè)置指定年月日時分秒信息 instance.set(2020, 9-1, 9, 9, 9, 9); //3. 轉(zhuǎn)化為Date類型對象 Date time = instance.getTime(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = simpleDateFormat.format(time); System.out.println(format); System.out.println("------------向指定字段設(shè)置指定值-----------"); //1. 設(shè)置年為2021 instance.set(Calendar.YEAR, 2021); Date time1 = instance.getTime(); System.out.println(simpleDateFormat.format(time1)); //2. 設(shè)置月增加2 instance.add(Calendar.MONTH, 2); Date time2 = instance.getTime(); System.out.println(simpleDateFormat.format(time2));
考點
Calendar既然是個抽象類不能創(chuàng)建對象,那為什么還能通過getInstance獲取Calendar類型的引用呢雌团?
解析:追溯getInstance()方法底層源碼燃领,底層實現(xiàn)多態(tài)。返回的是實現(xiàn)Calendar的子類锦援。
13.3 JDK8中的日期相關(guān)類
13.3.1 JDK8日期類由來
JDK8之前的日期類不能很好的兼容國際性猛蔽,所以JDK8退出新的日期類
13.3.2 JDK8日期類概述
java.time.LocalDate類主要用于描述年-月-日格式的日期信息,該類不表示時間和時區(qū)信息灵寺。
java.time.LocalTime 類主要用于描述時間信息曼库,可以描述時分秒以及納秒。
java.time.LocalDateTime類主要用于描述ISO-8601日歷系統(tǒng)中沒有時區(qū)的日期時間略板,如2007-12-03T10:15:30毁枯。
13.3.3 LocalDate類、LocalTime類和LocalDateTime類
-
代碼demo
//1. 當(dāng)前日期 LocalDate now = LocalDate.now(); System.out.println(now); //2. 當(dāng)前時間 LocalTime now1 = LocalTime.now(); System.out.println(now1); //3. 獲取當(dāng)前日期和時間 LocalDateTime now2 = LocalDateTime.now(); System.out.println(now2); //4. 使用參數(shù)指定日期時間 LocalDateTime localDateTime = LocalDateTime.of(2020, 9, 9, 9, 9, 9); System.out.println("獲取當(dāng)前月的第幾天:" + localDateTime.getDayOfMonth()); System.out.println("當(dāng)前星期的第幾天" + localDateTime.getDayOfWeek()); System.out.println("當(dāng)前年的第幾天" + localDateTime.getDayOfYear()); System.out.println("當(dāng)前年份" + localDateTime.getYear()); System.out.println("當(dāng)前月份" + localDateTime.getMonthValue()); System.out.println("當(dāng)前小時" + localDateTime.getHour()); System.out.println("當(dāng)前分鐘" + localDateTime.getMinute()); System.out.println("當(dāng)前秒數(shù)" + localDateTime.getSecond()); System.out.println("-----------設(shè)置年月日時分秒--------------"); //1. 設(shè)置年 LocalDateTime localDateTime1 = localDateTime.withYear(2021); System.out.println(localDateTime1); //輸入結(jié)果為false叮称,可以看出與String類似种玛,當(dāng)設(shè)置年份后,會重新創(chuàng)建一個對象瓤檐,原來的對象不改變赂韵。 System.out.println(localDateTime == localDateTime1); //false //2. 增加操作 LocalDateTime localDateTime2 = localDateTime.plusMonths(3); System.out.println(localDateTime2); //2020-12-09T09:09:09 //3. 減少操作 LocalDateTime localDateTime3 = localDateTime.minusDays(5); System.out.println(localDateTime3); //2020-09-04T09:09:09
-
Idea快捷鍵
Ctrl + F12查找該類中的所有方法
13.3.4 Instant類
描述瞬間的時間點信息
-
代碼demo
//1. 獲取當(dāng)前系統(tǒng)時間 并不是當(dāng)前系統(tǒng)的默認(rèn)時區(qū) Instant now = Instant.now(); System.out.println(now); //2. 加上時區(qū)的8小時 OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8)); System.out.println("加上偏移后的時間為:" + offsetDateTime); //3. 獲取當(dāng)前對象距離基準(zhǔn)時間的毫秒數(shù) long l = now.toEpochMilli(); System.out.println(l); //4. 指定毫秒數(shù)進(jìn)行構(gòu)造對象 Instant instant = Instant.ofEpochMilli(l); System.out.println(instant);
13.3.5 DateTimeFormatter類
作用:用于打印和解析日期時間對象的格式化
-
代碼demo
//1. 獲取當(dāng)前時間 LocalDateTime now = LocalDateTime.now(); //2. 創(chuàng)建指定時間格式的DateTimeFormatter類 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); //3. 格式化時間輸出 String format = dateTimeFormatter.format(now); System.out.println(format); //4. String -> Date TemporalAccessor parse = dateTimeFormatter.parse(format); System.out.println(parse);
第十四章 集合類庫
14.1 集合的概述(重點)
14.1.1 集合的由來
- 記錄多個類型不同的對象數(shù)據(jù)
14.1.2 集合的框架結(jié)構(gòu)
collection集合 基本單位是單個元素
Map集合 基本單位是單對元素(key-value)
結(jié)構(gòu)圖
14.2 collection集合(重點)
14.2.1 基本概念
java.util.Collection接口是List接口、Queue 接口以及Set接口的父接口距帅,因此該接口里定義的方法
既可用于操作List集合右锨,也可用于操作Queue集合和Set集合。
14.2.2 常用方法
-
代碼demo
//1. 創(chuàng)建一個collection集合 Collection collection1 = new ArrayList<>(); System.out.println(collection1); //[] System.out.println("--------------增加元素----------"); //2. 添加元素 //添加String類型 collection1.add(new String("fuyi")); System.out.println(collection1); //添加基本數(shù)據(jù)類型 collection1.add(23); System.out.println(collection1); //添加自定義類型 collection1.add(new Student("Sam", 2, "guangzhou")); System.out.println(collection1); //3. 添加多個元素 Collection collection2 = new ArrayList<>(); collection2.add(45); collection2.add("Lucy"); collection1.addAll(collection2); System.out.println(collection1); //[fuyi, 23, Student{name='Sam', id=2, address='guangzhou'}, 45, Lucy] //4. 注意 collection1.add(collection2); System.out.println(collection1); //[fuyi, 23, Student{name='Sam', id=2, address='guangzhou'}, 45, Lucy, [45, Lucy]] System.out.println("------------collection常用方法----------------"); //1. contains方法 boolean contains = collection1.contains(23); System.out.println(contains); //true boolean fuyi = collection1.contains(new String("fuyi")); System.out.println(fuyi); //true //這里打印結(jié)果為false碌秸,要了解contains方法對于引用類型的判斷 //contains工作原理:Objects.equals(o,e) //底層源碼 /** * public boolean contains(Object o) { * return indexOf(o) >= 0; * } * public int indexOf(Object o) { * if (o == null) { * for (int i = 0; i < size; i++) * if (elementData[i]==null) * return i; * } else { * for (int i = 0; i < size; i++) * if (o.equals(elementData[i])) * return i; * } * return -1; * } * * public static boolean equals(Object a, Object b) { * return (a == b) || (a != null && a.equals(b)); * } */ /** * 因為這里使用了多態(tài)绍移,該子類是ArrayList的引用,因此這里查看ArrayList的contains方法的代碼實現(xiàn) * 邏輯讥电,在indexOf方法中蹂窖,o代表的是傳進(jìn)來的對象,elementData里面存放的是collection中所有元素 * 可以清楚的看到形參o調(diào)用equals方法進(jìn)行和collection中元素進(jìn)行比對恩敌。所以要實現(xiàn)自定義類的equals * 方法瞬测。其實最終的工作原理是調(diào)用Objects.equals(o,e)方法進(jìn)行比較 */ boolean contains1 = collection1.contains(new Student("Sam", 2, "guangzhou")); System.out.println(contains1); //false -> true //2. containsAll方法,只要需要比較的集合里面有一個元素不包含都會返回false System.out.println(collection1); System.out.println("是否包含collection2中的所有元素" + collection1.containsAll(collection2)); collection2.add("noncontain"); System.out.println("是否包含collection2中的所有元素" + collection1.containsAll(collection2)); //3. retainAll方法,取兩個集合的交集部分月趟,如果返回true灯蝴,原本的集合內(nèi)容將會被覆蓋 System.out.println(); System.out.println(collection1); //[fuyi, 23, Student{name='Sam', id=2, address='guangzhou'}, 45, Lucy, [45, Lucy, noncontain]] System.out.println(collection2); //[45, Lucy, noncontain] boolean b = collection1.retainAll(collection1); System.out.println(b); //false System.out.println(collection1); //[fuyi, 23, Student{name='Sam', id=2, address='guangzhou'}, 45, Lucy, [45, Lucy, noncontain]] boolean b1 = collection1.retainAll(collection2); System.out.println(b1); //true System.out.println(collection1); //[45, Lucy] System.out.println(collection1); //4. 查看collection1中元素長度 System.out.println(collection1.size()); //5. 判斷collection1是否為空 System.out.println(collection1.isEmpty()); //6. 清空collection1中所有的元素 //collection1.clear(); System.out.println(collection1); System.out.println("------------集合向數(shù)組轉(zhuǎn)換-------"); //1. collection -> array Object[] objects = collection1.toArray(); for (Object object : objects) { System.out.println(object); } //2. Array -> collection Collection collection2 = Arrays.asList(objects); System.out.println(collection2);
14.3 Iterator接口
14.3.1 基本概念
Iterator接口主要用于描述迭代器對象,可以遍歷Collection集合中的所有元素
Collection接口繼承Iterator接口孝宗,因此實現(xiàn)Collection接口的實現(xiàn)類都可以使用迭代器對象
14.3.2 常用方法
-
代碼demo
Collection collection1 = new ArrayList(); collection1.add(2); collection1.add("fjdjsl"); collection1.add(77485); System.out.println(collection1); System.out.println("----使用迭代器遍歷collection-----"); Iterator iterator1 = collection1.iterator(); //1. 判斷是否有下一個元素 System.out.println(iterator1.hasNext()); //2. 取出一個元素并且指向下一個 //System.out.println(iterator1.next()); //3. 刪除最后訪問的一個元素 while (iterator1.hasNext()) { Object next = iterator1.next(); //collection1.remove(next); //Exception in thread "main" java.util.ConcurrentModificationException并發(fā)修改異常 //iterator1.remove(); } System.out.println(collection1);
14.4 foreach循環(huán)(重點)
14.4.1 基本概念
JDK5推出增強型for循環(huán)語句穷躁,可以應(yīng)用數(shù)組和集合的遍歷,是迭代的簡化版
14.4.2 格式
for(元素類型 變量名 : 數(shù)組/集合) {
循環(huán)體因妇;
}
14.4.3 執(zhí)行流程
不斷從數(shù)組/集合里面取出元素賦值給變量執(zhí)行循環(huán)體问潭,直至取完所有元素。
-
代碼demo
Collection collection1 = new ArrayList(); collection1.add(2); collection1.add("fjdjsl"); collection1.add(77485); System.out.println(collection1); System.out.println("-----使用foreach方法進(jìn)行遍歷collection------"); for (Object o : collection1) { System.out.println(o); } collection1.forEach(item -> { System.out.println(item); });
14.5 List集合
14.5.1 基本概念
java.util.List集合是Collection集合的子集合婚被,該集合中允許有重復(fù)的元素并且有先后放入次序狡忙。
該集合的主要實現(xiàn)類有:ArrayList類、LinkedList類址芯、Stack類灾茁、Vector類。
其中ArrayList類的底層是采用動態(tài)數(shù)組進(jìn)行數(shù)據(jù)管理的是复,支持下標(biāo)訪問删顶,增刪元素不方便。
其中LinkedList類的底層是采用雙向鏈表進(jìn)行數(shù)據(jù)管理的淑廊,訪問不方便逗余,增刪元素方便。
可以認(rèn)為ArrayList和LinkedList的方法在邏輯上完全一樣季惩,只是在性能上有一定的差別录粱,ArrayList更適合于隨
機(jī)訪問而LinkedList更適合于插入和刪除;在性能要求不是特別苛刻的情形下可以忽略這個差別画拾。其中Stack類的底層是采用動態(tài)數(shù)組進(jìn)行數(shù)據(jù)管理的啥繁,該類主要用于描述一種具有后進(jìn)先出特征的
數(shù)據(jù)結(jié)構(gòu),叫做棧(last in first out LIFO)青抛。其中Vector類的底層是采用動態(tài)數(shù)組進(jìn)行數(shù)據(jù)管理的旗闽,該類與ArrayList類相比屬于線程安全的
類,效率比較低蜜另,以后開發(fā)中基本不用适室。
14.5.2 基本方法
void add(int index, E element) 向集合中指定位置添加元素
boolean addAll(int index, Collection<? extends E> c) 向集合中添加所有元素
E get(int index) 從集合中獲取指定位置元素
int indexOf(Object o) 查找參數(shù)指定的對象
int lastIndexOf(Object o) 反向查找參數(shù)指定的對象
E set(int index, E element) 修改指定位置的元素
E remove(int index) 刪除指定位置的元素
List subList(int fromIndex, int toIndex) 用于獲取子List
14.6 Queue集合
14.6.1 基本概念
java.util.Queue集合是Collection集合的子集合,與List集合屬于平級關(guān)系举瑰。
該集合的主要用于描述具有先進(jìn)先出特征的數(shù)據(jù)結(jié)構(gòu)捣辆,叫做隊列(first in first out FIFO)。
該集合的主要實現(xiàn)類是LinkedList類此迅,因為該類在增刪方面比較有優(yōu)勢汽畴。
14.6.2 常用方法
boolean offer(E e) 將一個對象添加至隊尾旧巾,若添加成功則返回true
E poll() 從隊首刪除并返回一個元素
E peek() 返回隊首的元素(但并不刪除)
第十五章 集合類庫
15.1 泛型機(jī)制
15.1.1 基本概念
背景:由于集合中增加一個元素,集合都是以O(shè)bject類型進(jìn)行存儲的忍些,當(dāng)取出元素的時候放回的數(shù)據(jù)
類型也是Object類型鲁猩,如果要想得到某個具體的類型必須進(jìn)行類型強轉(zhuǎn),而強轉(zhuǎn)這個過程很容易發(fā)生類型
轉(zhuǎn)化異常坐昙。解決方案:為了解決上述問題绳匀,JDK5提出了泛型的機(jī)制,也就是在創(chuàng)建集合的時候指定一個泛型類型炸客,
類型取決于存儲數(shù)據(jù)的時候,是什么類型就是什么類型戈钢。如果放入的是其他類型編譯的時候就會出錯痹仙,
通過這個參數(shù)限制操作的數(shù)據(jù)類型,從而保證類型轉(zhuǎn)換的絕對安全殉了。泛型機(jī)制在編譯時期區(qū)分類型开仰,而在運行的時候是不區(qū)分類型的
15.1.2 底層原理
本質(zhì):參數(shù)化類型,也就是將數(shù)據(jù)類型作為參數(shù)進(jìn)行傳遞
敘述:比如很多List<E>薪铜、ArrayList<E>等集合來說众弓,<E>相當(dāng)于一個占位符,一個形式參數(shù)隔箍。就好比一個方法體里面需要
傳遞參數(shù)谓娃,只不過這里的傳遞的參數(shù)有點特別,傳的是數(shù)據(jù)類型蜒滩。
15.1.3 自定義泛型接口
- 自定義泛型接口與普通接口的區(qū)別在于接口名后面是否有<E,T...>
15.1.4 自定義泛型類
同樣的道理自定義泛型類和普通類的區(qū)別也是在于類名后面是否有<E,T....>
- 語法格式
public class class_name<data_type1,data_type2,…>{}
- 泛型類的繼承
代碼分析
package com.ryan.stage1.model3.task15;
public class SubStudent extends Student{ //子類不保留父類的泛型滨达,此時父類中的泛型被解析為Object類型
public class SubStudent extends Student<String> { //子類不保留父類的泛型,指定父類中的泛型為String類型
public class SubStudent<T> extends Student<T> { //子類保留了父類的泛型并且父類中的泛型字段的類型取決于子類傳入的類型參數(shù)
public class SubStudent<T, E> extends Student<T> { //子類保留了父類的泛型并且增加了一個新的泛型
}
測試代碼
package com.ryan.stage1.model3.task15;
public class SubStudentTest {
public static void main(String[] args) {
System.out.println("---------不保留泛型且不指定類型---------");
SubStudent subStudent1 = new SubStudent();
subStudent1.setId(1);
subStudent1.setName("Sam");
subStudent1.setGender("boy");
Object gender1 = subStudent1.getGender();
System.out.println(subStudent1);
System.out.println(gender1);
System.out.println("---------不保留泛型且指定了類型---------");
SubStudent subStudent2 = new SubStudent();
subStudent2.setId(2);
subStudent2.setName("Lucy");
subStudent2.setGender("girl");
System.out.println(subStudent2);
String gender2 = subStudent2.getGender();
System.out.println(gender2);
System.out.println("---------保留泛型且由子類決定類型---------");
SubStudent<Boolean> subStudent3 = new SubStudent();
subStudent3.setId(3);
subStudent3.setName("KangKang");
subStudent3.setGender(true);
System.out.println(subStudent3);
Boolean gender3 = subStudent3.getGender();
System.out.println(gender3);
System.out.println("---------保留泛型且由子類增加類型---------");
SubStudent<Boolean, Double> subStudent4 = new SubStudent();
subStudent4.setId(4);
subStudent4.setName("John");
subStudent4.setGender(true);
System.out.println(subStudent4);
Boolean gender4 = subStudent4.getGender();
System.out.println(gender4);
}
}
15.1.5 自定義泛型方法
概念:類型參數(shù)化的方法稱為泛型方法俯艰;是否擁有泛型方法捡遍,與其所在的類是不是泛型沒有關(guān)系。
語法格式
[訪問權(quán)限修飾符][static][final]<類型參數(shù)列表>返回值類型方法名([形式參數(shù)列表])
-
代碼分析
//自定義泛型方法 public static <T> void genericPrint(T[] arr) { for (T t : arr) { System.out.println(t); } }
-
代碼測試
System.out.println("---------自定義泛型方法---------"); Integer[] arr = new Integer[] {1, 2, 5, 9, 198}; Student.genericPrint(arr);
-
運行結(jié)果
---------自定義泛型方法--------- 1 2 5 9 198
15.1.6 通配符的使用
背景:在平時我們經(jīng)常會使用到類的繼承竹握,而父類和子類分別作為泛型傳入所得到的兩個集合是不存在繼承關(guān)系的画株。
-
代碼分析
Person類
public class Person {}
Teacher類
import com.ryan.stage1.model3.task15.Person; public class Teacher extends Person {}
-
測試代碼
System.out.println("---------驗證父子類泛型集合是否存在繼承關(guān)系--------"); List<Person> list1 = new LinkedList<>(); List<Teacher> list2 = new LinkedList<>(); //編譯報錯 //list1 = list2; //Error: 不兼容類型
解決方案:對于上述出現(xiàn)的問題,Java提供了通配符去解決
在 Java 中默認(rèn)可以使用任何類型來實例化一個泛型類對象啦辐。當(dāng)然也可以對泛型類實例的類型進(jìn)行限制谓传,語法格式如下:
//限制泛型類型T必須是實現(xiàn)某個接口類的
class 類名稱<T extends anyClass>
Java 中的泛型還支持使用類型通配符,它的作用是在創(chuàng)建一個泛型類對象時限制這個泛型類的類型必須實現(xiàn)或繼承某個接口或類昧甘。
語法格式
泛型類名稱<? extends List>a = null;
或者是
泛型類名稱<? super List>a = null;
-
代碼分析
System.out.println("---------通配符解決方案-------"); //1. 使用通配符作為泛型的公共父類 List<?> list3 = new LinkedList<>(); List<?> list4 = new LinkedList<>(); list1.add(new Person()); list2.add(new Teacher()); list3 = list1; list4 = list2; //編譯錯誤良拼,使用?通配符是不能進(jìn)行增加元素的 //list3.add(new Person()); System.out.println(list3.get(0)); //com.ryan.stage1.model3.task15.Person@4d7e1886 //2. 使用有限制的通配符 上限是Person類 List<? extends Person> list5 = new LinkedList<>(); //編譯錯誤充边,還是不可以增加元素 //list5.add(new Person()); //list5.add(new Teacher()); list5 = list2; Person person = list5.get(0); System.out.println(person); //com.ryan.stage1.model3.task15.Teacher@47089e5f //3. 使用<? super Person>庸推,下限時Person類 List<? super Person> list6 = new LinkedList<>(); list6.add(new Person()); System.out.println(list6); //[com.ryan.stage1.model3.task15.Person@4f47d241]
15.2 Set集合(熟悉)
15.2.1 概念
放入元素沒有先后次序常侦,不可重復(fù)
實現(xiàn)類:HashSet、TreeSet和LinkedHashSet
HashSet底層是由哈希表進(jìn)行管理
TreeSet底層是由紅黑樹管理實現(xiàn)
LinkedHashSet是在HashSet的基礎(chǔ)上使用雙向鏈表進(jìn)行維護(hù)贬媒,有順序的取放數(shù)據(jù)聋亡。
15.2.2 HashSet和LinkedHashSet的使用
15.2.3 TreeSet集合
二叉樹主要指每個節(jié)點最多只有兩個子節(jié)點的樹形結(jié)構(gòu)。
-
滿足以下3個特征的二叉樹叫做有序二叉樹际乘。
a.左子樹中的任意節(jié)點元素都小于根節(jié)點元素值坡倔;
b.右子樹中的任意節(jié)點元素都大于根節(jié)點元素值;
c.左子樹和右子樹的內(nèi)部也遵守上述規(guī)則脖含;
由于TreeSet集合的底層采用紅黑樹進(jìn)行數(shù)據(jù)的管理罪塔,當(dāng)有新元素插入到TreeSet集合時,需要使
用新元素與集合中已有的元素依次比較來確定新元素的合理位置养葵。-
比較元素大小的規(guī)則有兩種方式:
使用元素的自然排序規(guī)則進(jìn)行比較并排序征堪,讓元素類型實現(xiàn)java.lang.Comparable接口;
使用比較器規(guī)則進(jìn)行比較并排序关拒,構(gòu)造TreeSet集合時傳入java.util.Comparator接口佃蚜;
自然排序的規(guī)則比較單一,而比較器的規(guī)則比較多元化着绊,而且比較器優(yōu)先于自然排序谐算;
自然排序:TreeSet 類同時實現(xiàn)了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口归露,可以實現(xiàn)對集合進(jìn)行自然排序洲脂,因此使用 TreeSet 類實現(xiàn)的 Set 接口默認(rèn)情況下是自然排序的,這里的自然排序指的是升序排序靶擦。
代碼分析
//1. 準(zhǔn)備一個TreeSet集合
Set treeSet = new TreeSet();
treeSet.add("aa");
treeSet.add("cc");
treeSet.add("bb");
//由于TreeSet底層使用的紅黑樹實現(xiàn)腮考,因此有大小上排序,默認(rèn)從小到大
System.out.println(treeSet); //[aa, bb, cc]
- 自定義排序:TreeSet 只能對實現(xiàn)了 Comparable 接口的類對象進(jìn)行排序玄捕,因為 Comparable 接口中有一個 compareTo(Object o) 方法用于比較兩個對象的大小踩蔚。有的時候需要對自定義的類進(jìn)行排序和存儲,所以要實現(xiàn)
代碼分析
//2. 使用Set的引用指向TreeSet的對象
Set<School> schoolSet = new TreeSet<>();
/**
* 如果指定的類型沒有事項Comparable接口枚粘,打印輸出會拋出下面的異常馅闽,這是因為使用TreeSet集合進(jìn)行
* 存儲數(shù)據(jù),底層紅黑樹需要對兩個對象進(jìn)行比較存入馍迄,所以有兩種解決方案:
* 第一:就是School類實現(xiàn)java.java.lang.Comparable接口
* 第二:就是通過構(gòu)造方法進(jìn)行TreeSet?(Comparator<? super E> comparator)實現(xiàn)比較
* throws:Exception in thread "main" java.lang.ClassCastException: com.ryan.stage1.model3.task15.School cannot be cast to java.lang.Comparable
*/
//1. School類實現(xiàn)java.java.lang.Comparable接口
schoolSet.add(new School("zhaoqing", 20));
schoolSet.add(new School("guangzhou", 2));
System.out.println(schoolSet); //[School{name='guangzhou', rank=2}, School{name='zhaoqing', rank=20}]
//2. TreeSet?(Comparator<? super E> comparator)實現(xiàn)比較
Comparator<School> schoolComparable = new Comparator<School>() {
@Override
public int compare(School o1, School o2) {
return o2.getName().compareTo(o1.getName());
}
};
//JDK8之后的lambda表達(dá)式(參數(shù)列表) -> {方法體}
Comparator<School> schoolComparable2 = (School o1, School o2) -> {
return o2.getName().compareTo(o1.getName());
};
Set<School> schoolSet1 = new TreeSet<>(schoolComparable);
schoolSet1.add(new School("zhaoqing", 20));
schoolSet1.add(new School("guangzhou", 2));
System.out.println(schoolSet1); //[School{name='zhaoqing', rank=20}, School{name='guangzhou', rank=2}]
//直接匿名內(nèi)部類
Set schoolSet3 = new TreeSet<>((School o1, School o2) -> {
return o2.getName().compareTo(o1.getName());
});
schoolSet3.add(new School("zhaoqing", 20));
schoolSet3.add(new School("guangzhou", 2));
System.out.println(schoolSet3); //[School{name='zhaoqing', rank=20}, School{name='guangzhou', rank=2}]
15.3 Map集合
15.3.1 基本概念
-
java.util.Map<K,V>集合中存取元素的基本單位是:單對元素福也,其中類型參數(shù)如下:
K - 此映射所維護(hù)的鍵(Key)的類型,相當(dāng)于目錄攀圈。
V - 映射值(Value)的類型暴凑,相當(dāng)于內(nèi)容。
該集合中key是不允許重復(fù)的赘来,而且一個key只能對應(yīng)一個value现喳。
-
該集合的主要實現(xiàn)類有:HashMap類凯傲、TreeMap類、LinkedHashMap類嗦篱、Hashtable類冰单、Properties類。
其中HashMap類的底層是采用哈希表進(jìn)行數(shù)據(jù)管理的灸促。
其中TreeMap類的底層是采用紅黑樹進(jìn)行數(shù)據(jù)管理的诫欠。
其中LinkedHashMap類與HashMap類的不同之處在于內(nèi)部維護(hù)了一個雙向鏈表,鏈表中記錄了
元素的迭代順序浴栽,也就是元素插入集合中的先后順序荒叼,因此便于迭代。其中Hashtable類是古老的Map實現(xiàn)類吃度,與HashMap類相比屬于線程安全的類甩挫,且不允許null作 為key或者value的數(shù)值。
其中Properties類是Hashtable類的子類椿每,該對象用于處理屬性文件,key和value都是String類
型的英遭。 Map集合是面向查詢優(yōu)化的數(shù)據(jù)結(jié)構(gòu), 在大數(shù)據(jù)量情況下有著優(yōu)良的查詢性能间护。經(jīng)常用于根據(jù)key檢索value的業(yè)務(wù)場景。
15.3.2 常用方法
V put(K key, V value) 將Key-Value對存入Map挖诸,若集合中已經(jīng)包含該Key汁尺,則替換該Key所對應(yīng)的Value,返回值為該Key原來所對應(yīng)的Value多律,若沒有則返回null
V get(Object key) 返回與參數(shù)Key所對應(yīng)的Value對象痴突,如果不存在則返回null
boolean containsKey(Object key); 判斷集合中是否包含指定的Key
boolean containsValue (Object value);判斷集合中是否包含指定的Value
V remove(Object key) 根據(jù)參數(shù)指定的key進(jìn)行刪除
Set keySet() 返回此映射中包含的鍵的Set視圖
Collection values() 返回此映射中包含的值的Set視圖
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set視圖
15.3.3 HashMap存儲原理
使用元素的key調(diào)用hashCode方法獲取對應(yīng)的哈希碼值,再由某種哈希算法計算在數(shù)組中的索引位置狼荞。
若該位置沒有元素辽装,則將該鍵值對直接放入即可。
若該位置有元素相味,則使用key與已有元素依次比較哈希值拾积,若哈希值不相同,則將該元素直接放入丰涉。
若key與已有元素的哈希值相同拓巧,則使用key調(diào)用equals方法與已有元素依次比較。
若相等則將對應(yīng)的value修改一死,否則將鍵值對直接放入即可肛度。
15.3.4 HashMap常量
DEFAULT_INITIAL_CAPACITY : HashMap的默認(rèn)容量是16。
DEFAULT_LOAD_FACTOR:HashMap的默認(rèn)加載因子是0.75投慈。
threshold:擴(kuò)容的臨界值承耿,該數(shù)值為:容量*填充因子冠骄,也就是12。
TREEIFY_THRESHOLD:若Bucket中鏈表長度大于該默認(rèn)值則轉(zhuǎn)化為紅黑樹存儲瘩绒,該數(shù)值是8猴抹。
MIN_TREEIFY_CAPACITY:桶中的Node被樹化時最小的hash表容量,該數(shù)值是64锁荔。
15.4 Collection類
15.4.1 基本概念
java.util.Collections類主要提供了對集合操作或者返回集合的靜態(tài)方法蟀给。
15.4.2 常用方法
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 根據(jù)元素的自然順序返回給定集合的最大元素
static T max(Collection<? extends T> coll, Comparator<? super T> comp) 根據(jù)指定比較器引發(fā)的順序返回給定集合的最大元素
static <T extends Object & Comparable<?super T>> T min(Collection<? extends T> coll) 根據(jù)元素的自然順序返回給定集合的最小元素
static T min(Collection<? extends T> coll, Comparator<? super T> comp) 根據(jù)指定比較器引發(fā)的順序返回給定集合的最小元素
static void copy(List<? super T> dest, List<? extends T> src) 將一個列表中的所有元素復(fù)制到另一個列表中
static void reverse(List<?> list) 反轉(zhuǎn)指定列表中元素的順序
static void shuffle(List<?> list) 使用默認(rèn)的隨機(jī)源隨機(jī)置換指定的列表
static <T extends Comparable<? super T>> void sort(List list) 根據(jù)其元素的自然順序?qū)⒅付斜戆瓷蚺判?
static void sort(List list, Comparator<? super T> c) 根據(jù)指定比較器指定的順序?qū)χ付斜磉M(jìn)行排序
static void swap(List<?> list, int i, int j) 交換指定列表中指定位置的元素
-
代碼demo
List<Integer> integers = Arrays.asList(new Integer[]{23, 45, 67, 89, 198, 54, 24}); //1. 獲取集合中最值 Integer max = Collections.max(integers); System.out.println(max); System.out.println(Collections.min(integers)); //2. 將集合進(jìn)行排序 Collections.sort(integers); System.out.println(integers); //3. 將集合進(jìn)行翻轉(zhuǎn) Collections.reverse(integers); System.out.println(integers); //4. 隨機(jī)置換 Collections.shuffle(integers); System.out.println(integers); //5. 交換元素(首尾兩個位置元素交換) Collections.swap(integers, 0, integers.size() - 1); System.out.println(integers); //6. 集合間進(jìn)行拷貝 List<Integer> copyList = Arrays.asList(new Integer[10]); Collections.copy(copyList, integers); System.out.println(copyList);