Linux - sudo和su的區別
Java集合
目錄
- Java集合
- day28課堂筆記
- 程式碼
- Collection部分
- CollectionTest01——關於java.util.Collection介面中常用的方法
- CollectionTest02——關於集合遍歷/迭代專題(重點)
- CollectionTest03——關於集合的迭代/遍歷
- CollectionTest04——深入Collection集合的contains方法
- CollectionTest05——測試contains方法、remove方法
- CollectionTest06——關於集合元素的remove
- ListTest01——List介面中常用方法
- ArrayListTest01——ArrayList集合
- ArrayListTest02——集合ArrayList的構造方法
- LinkedListTest01——連結串列的原理以及優缺點
- 單鏈表的實現
- VectorTest——Vector集合原始碼分析
- GenericTest01——泛型
- GenericTest02——【泛型】自動型別推斷機制
- GenericTest03——自定義泛型
- ForEachTest01——增強for迴圈
- ForEachTest02——集合使用foreach
- HashSetTest01——HashSet集合【無序不可重複】
- Map部分
- Collection部分
day28課堂筆記
1、集合概述
1.1、什麼是集合?有什麼用? 陣列其實就是一個集合。集合實際上就是一個容器。可以來容納其它型別的資料。 集合為什麼說在開發中使用較多? 集合是一個容器,是一個載體,可以一次容納多個物件。 在實際開發中,假設連線資料庫,資料庫當中有10條記錄, 那麼假設把這10條記錄查詢出來,在java程式中會將10條 資料封裝成10個java物件,然後將10個java物件放到某一個 集合當中,將集合傳到前端,然後遍歷集合,將一個數據一個 資料展現出來。 1.2、集合不能直接儲存基本資料型別,另外集合也不能直接儲存java物件, 集合當中儲存的都是java物件的記憶體地址。(或者說集合中儲存的是引用。) list.add(100); //自動裝箱Integer 注意: 集合在java中本身是一個容器,是一個物件。 集合中任何時候儲存的都是“引用”。 1.3、在java中每一個不同的集合,底層會對應不同的資料結構。往不同的集合中 儲存元素,等於將資料放到了不同的資料結構當中。什麼是資料結構?資料儲存的 結構就是資料結構。不同的資料結構,資料儲存方式不同。例如: 陣列、二叉樹、連結串列、雜湊表... 以上這些都是常見的資料結構。 你往集合c1中放資料,可能是放到陣列上了。 你往集合c2中放資料,可能是放到二叉樹上了。 ..... 你使用不同的集合等同於使用了不同的資料結構。 你在java集合這一章節,你需要掌握的不是精通資料結構。java中已經將資料結構 實現了,已經寫好了這些常用的集合類,你只需要掌握怎麼用?在什麼情況下選擇 哪一種合適的集合去使用即可。 new ArrayList(); 建立一個集合,底層是陣列。 new LinkedList(); 建立一個集合物件,底層是連結串列。 new TreeSet(); 建立一個集合物件,底層是二叉樹。 ..... 1.4、集合在java JDK中哪個包下? java.util.*; 所有的集合類和集合介面都在java.util包下。 1.5、為了讓大家掌握集合這塊的內容,最好能將集合的繼承結構圖背會!!! 集合整個這個體系是怎樣的一個結構,你需要有印象。 1.6、在java中集合分為兩大類: 一類是單個方式儲存元素: 單個方式儲存元素,這一類集合中超級父介面:java.util.Collection; 一類是以鍵值對兒的方式儲存元素 以鍵值對的方式儲存元素,這一類集合中超級父介面:java.util.Map;
集合中儲存的是物件的記憶體地址:
- 集合中存放的是物件的引用。
- 集合中存放集合也是存放的是集合的引用。
2、總結重點:
第一個重點:把集合繼承結構圖背會。
第二個重點:把Collection介面中常用方法測試幾遍。
第三個重點:把迭代器弄明白。
第四個重點:Collection介面中的remove方法和contains方法底層都會呼叫equals,這個弄明白。
總結(所有的實現類):
ArrayList:底層是陣列。
LinkedList:底層是雙向連結串列。
Vector:底層是陣列,執行緒安全的,效率較低,使用較少。
HashSet:底層是HashMap,放到HashSet集合中的元素等同於放到HashMap集合key部分了。
TreeSet:底層是TreeMap,放到TreeSet集合中的元素等同於放到TreeMap集合key部分了。
n HashMap:底層是雜湊表。
Hashtable:底層也是雜湊表,只不過執行緒安全的,效率較低,使用較少。
Properties:是執行緒安全的,並且key和value只能儲存字串String。
TreeMap:底層是二叉樹。TreeMap集合的key可以自動按照大小順序排序。
List集合儲存元素的特點:
有序可重複
有序:存進去的順序和取出的順序相同,每一個元素都有下標。
可重複:存進去1,可以再儲存一個1.
Set(Map)集合儲存元素的特點:
無序不可重複
無序:存進去的順序和取出的順序不一定相同。另外Set集合中元素沒有下標。
不可重複:存進去1,不能再儲存1了。
SortedSet(SortedMap)集合儲存元素特點:
首先是無序不可重複的,但是SortedSet集合中的元素是可排序的。
無序:存進去的順序和取出的順序不一定相同。另外Set集合中元素沒有下標。
不可重複:存進去1,不能再儲存1了。
可排序:可以按照大小順序排列。
Map集合的key,就是一個Set集合。
往Set集合中放資料,實際上放到了Map集合的key部分。
程式碼
Collection部分
CollectionTest01——關於java.util.Collection介面中常用的方法
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
/*
關於java.util.Collection介面中常用的方法。
1、Collection中能存放什麼元素?
沒有使用“泛型”之前,Collection中可以儲存Object的所有子型別。
使用了“泛型”之後,Collection中只能儲存某個具體的型別。
集合後期我們會學習“泛型”語法。目前先不用管。Collection中什麼都能存,
只要是Object的子型別就行。(集合中不能直接儲存基本資料型別,也不能存
java物件,只是儲存java物件的記憶體地址。)
2、Collection中的常用方法
boolean add(Object e) 向集合中新增元素
int size() 獲取集合中元素的個數
void clear() 清空集合
boolean contains(Object o) 判斷當前集合中是否包含元素o,包含返回true,不包含返回false
boolean remove(Object o) 刪除集合中的某個元素。
boolean isEmpty() 判斷該集合中元素的個數是否為0
Object[] toArray() 呼叫這個方法可以把集合轉換成陣列。【作為了解,使用不多。】
*/
public class CollectionTest01 {
public static void main(String[] args) {
// 建立一個集合物件
//Collection c = new Collection(); // 介面是抽象的,無法例項化。
// 多型
Collection c = new ArrayList();
// 測試Collection介面中的常用方法
c.add(1200); // 自動裝箱(java5的新特性。),實際上是放進去了一個物件的記憶體地址。Integer x = new Integer(1200);
c.add(3.14); // 自動裝箱
c.add(new Object());
c.add(new Student());
c.add(true); // 自動裝箱
// 獲取集合中元素的個數
System.out.println("集合中元素個數是:" + c.size()); // 5
// 清空集合
c.clear();
System.out.println("集合中元素個數是:" + c.size()); // 0
// 再向集合中新增元素
c.add("hello"); // "hello"物件的記憶體地址放到了集合當中。
c.add("world");
c.add("浩克");
c.add("綠巨人");
c.add(1);
// 判斷集合中是否包含"綠巨人"
boolean flag = c.contains("綠巨人");
System.out.println(flag); // true
boolean flag2 = c.contains("綠巨人2");
System.out.println(flag2); // false
System.out.println(c.contains(1)); // true
System.out.println("集合中元素個數是:" + c.size()); // 5
// 刪除集合中某個元素
c.remove(1);
System.out.println("集合中元素個數是:" + c.size()); // 4
// 判斷集合是否為空(集合中是否存在元素)
System.out.println(c.isEmpty()); // false
// 清空
c.clear();
System.out.println(c.isEmpty()); // true(true表示集合中沒有元素了!)
c.add("abc");
c.add("def");
c.add(100);
c.add("helloworld!");
c.add(new Student());
// 轉換成陣列(瞭解,使用不多。)
Object[] objs = c.toArray();
for(int i = 0; i < objs.length; i++){
// 遍歷陣列
Object o = objs[i];
System.out.println(o);
}
}
}
class Student{
}
CollectionTest02——關於集合遍歷/迭代專題(重點)
迭代集合的原理:
圖1:
圖2:
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 關於集合遍歷/迭代專題。(重點:五顆星*****)
*/
public class CollectionTest02 {
public static void main(String[] args) {
// 注意:以下講解的遍歷方式/迭代方式,是所有Collection通用的一種方式。
// 在Map集合中不能用。在所有的Collection以及子類中使用。
// 建立集合物件
Collection c = new ArrayList(); // 後面的集合無所謂,主要是看前面的Collection介面,怎麼遍歷/迭代。
// 新增元素
c.add("abc");
c.add("def");
c.add(100);
c.add(new Object());
// 對集合Collection進行遍歷/迭代
// 第一步:獲取集合物件的迭代器物件Iterator
Iterator it = c.iterator();
// 第二步:通過以上獲取的迭代器物件開始迭代/遍歷集合。
/*
以下兩個方法是迭代器物件Iterator中的方法:
boolean hasNext()如果仍有元素可以迭代,則返回 true。
Object next() 返回迭代的下一個元素。
*/
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
// 一直取,不判斷,會出現異常:java.util.NoSuchElementException
/*while(true){
Object obj = it.next();
System.out.println(obj);
}*/
/*boolean hasNext = it.hasNext();
System.out.println(hasNext);
if(hasNext) {
// 不管你當初存進去什麼,取出來統一都是Object。
Object obj = it.next();
System.out.println(obj);
}
hasNext = it.hasNext();
System.out.println(hasNext);
if(hasNext) {
Object obj = it.next();
System.out.println(obj);
}
hasNext = it.hasNext();
System.out.println(hasNext);
if(hasNext) {
Object obj = it.next();
System.out.println(obj);
}
hasNext = it.hasNext();
System.out.println(hasNext);
if(hasNext) {
Object obj = it.next();
System.out.println(obj);
}
hasNext = it.hasNext();
System.out.println(hasNext);
if(hasNext) {
Object obj = it.next();
System.out.println(obj);
}*/
}
}
CollectionTest03——關於集合的迭代/遍歷
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
/*
關於集合的迭代/遍歷
*/
public class CollectionTest03 {
public static void main(String[] args) {
// 建立集合物件
Collection c1 = new ArrayList(); // ArrayList集合:有序可重複
// 新增元素
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(4);
c1.add(1);
// 迭代集合
Iterator it = c1.iterator();
while(it.hasNext()){
// 存進去是什麼型別,取出來還是什麼型別。
Object obj = it.next();
/*if(obj instanceof Integer){
System.out.println("Integer型別");
}*/
// 只不過在輸出的時候會轉換成字串。因為這裡println會呼叫toString()方法。
System.out.println(obj);
}
// HashSet集合:無序不可重複
Collection c2 = new HashSet();
// 無序:存進去和取出的順序不一定相同。
// 不可重複:儲存100,不能再儲存100.
c2.add(100);
c2.add(200);
c2.add(300);
c2.add(90);
c2.add(400);
c2.add(50);
c2.add(60);
c2.add(100);
Iterator it2 = c2.iterator();
while(it2.hasNext()){
System.out.println(it2.next());
}
}
}
CollectionTest04——深入Collection集合的contains方法
記憶體圖:
import java.util.ArrayList;
import java.util.Collection;
/*
深入Collection集合的contains方法:
boolean contains(Object o)
判斷集合中是否包含某個物件o
如果包含返回true, 如果不包含返回false。
contains方法是用來判斷集合中是否包含某個元素的方法,
那麼它在底層是怎麼判斷集合中是否包含某個元素的呢?
呼叫了equals方法進行比對。
equals方法返回true,就表示包含這個元素。
*/
public class CollectionTest04 {
public static void main(String[] args) {
// 建立集合物件
Collection c = new ArrayList();
// 向集合中儲存元素
String s1 = new String("abc"); // s1 = 0x1111
c.add(s1); // 放進去了一個"abc"
String s2 = new String("def"); // s2 = 0x2222
c.add(s2);
// 集合中元素的個數
System.out.println("元素的個數是:" + c.size()); // 2
// 新建的物件String
String x = new String("abc"); // x = 0x5555
// c集合中是否包含x?結果猜測一下是true還是false?
System.out.println(c.contains(x)); //判斷集合中是否存在"abc" true
}
}
CollectionTest05——測試contains方法、remove方法
重要結論:存放在一個集合中的型別,一定要重寫equals方法。
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
/*
測試contains方法
測試remove方法。
結論:存放在一個集合中的型別,一定要重寫equals方法。
*/
public class CollectionTest05 {
public static void main(String[] args) {
// 建立集合物件
Collection c = new ArrayList();
// 建立使用者物件
User u1 = new User("jack");
// 加入集合
c.add(u1);
// 判斷集合中是否包含u2
User u2 = new User("jack");
// 沒有重寫equals之前:這個結果是false
//System.out.println(c.contains(u2)); // false
// 重寫equals方法之後,比較的時候會比較name。
System.out.println(c.contains(u2)); // true
c.remove(u2);
System.out.println(c.size()); // 0
/*Integer x = new Integer(10000);
c.add(x);
Integer y = new Integer(10000);
System.out.println(c.contains(y)); // true*/
// 建立集合物件
Collection cc = new ArrayList();
// 建立字串物件
String s1 = new String("hello");
// 加進去。
cc.add(s1);
// 建立了一個新的字串物件
String s2 = new String("hello");
// 刪除s2
cc.remove(s2); // s1.equals(s2) java認為s1和s2是一樣的。刪除s2就是刪除s1。
// 集合中元素個數是?
System.out.println(cc.size()); // 0
}
}
class User{
private String name;
public User(){}
public User(String name){
this.name = name;
}
// 重寫equals方法
// 將來呼叫equals方法的時候,一定是呼叫這個重寫的equals方法。
// 這個equals方法的比較原理是:只要姓名一樣就表示同一個使用者。
public boolean equals(Object o) {
if(o == null || !(o instanceof User)) return false;
if(o == this) return true;
User u = (User)o;
// 如果名字一樣表示同一個人。(不再比較物件的記憶體地址了。比較內容。)
return u.name.equals(this.name);
}
}
CollectionTest06——關於集合元素的remove
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
關於集合元素的remove
重點:當集合的結構發生改變時,迭代器必須重新獲取,如果還是用以前老的迭代器,會出現
異常:java.util.ConcurrentModificationException
重點:在迭代集合元素的過程中,不能呼叫集合物件的remove方法,刪除元素:
c.remove(o); 迭代過程中不能這樣。
會出現:java.util.ConcurrentModificationException
重點:在迭代元素的過程當中,一定要使用迭代器Iterator的remove方法,刪除元素,
不要使用集合自帶的remove方法刪除元素。
*/
public class CollectionTest06 {
public static void main(String[] args) {
// 建立集合
Collection c = new ArrayList();
// 注意:此時獲取的迭代器,指向的是那是集合中沒有元素狀態下的迭代器。
// 一定要注意:集合結構只要發生改變,迭代器必須重新獲取。
// 當集合結構發生了改變,迭代器沒有重新獲取時,呼叫next()方法時:java.util.ConcurrentModificationException
Iterator it = c.iterator();
// 新增元素
c.add(1); // Integer型別
c.add(2);
c.add(3);
// 獲取迭代器
//Iterator it = c.iterator();
/*while(it.hasNext()){
// 編寫程式碼時next()方法返回值型別必須是Object。
// Integer i = it.next();
Object obj = it.next();
System.out.println(obj);
}*/
Collection c2 = new ArrayList();
c2.add("abc");
c2.add("def");
c2.add("xyz");
Iterator it2 = c2.iterator();
while(it2.hasNext()){
Object o = it2.next();
// 刪除元素
// 刪除元素之後,集合的結構發生了變化,應該重新去獲取迭代器
// 但是,迴圈下一次的時候並沒有重新獲取迭代器,所以會出現異常:java.util.ConcurrentModificationException
// 出異常根本原因是:集合中元素刪除了,但是沒有更新迭代器(迭代器不知道集合變化了)
//c2.remove(o); // 直接通過集合去刪除元素,沒有通知迭代器。(導致迭代器的快照和原集合狀態不同。)
// 使用迭代器來刪除可以嗎?
// 迭代器去刪除時,會自動更新迭代器,並且更新集合(刪除集合中的元素)。
it2.remove(); // 刪除的一定是迭代器指向的當前元素。
System.out.println(o);
}
System.out.println(c2.size()); //0
}
}
ListTest01——List介面中常用方法
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/*
測試List介面中常用方法
1、List集合儲存元素特點:有序可重複
有序:List集合中的元素有下標。
從0開始,以1遞增。
可重複:儲存一個1,還可以再儲存1.
2、List既然是Collection介面的子介面,那麼肯定List介面有自己“特色”的方法:
以下只列出List介面特有的常用的方法:
void add(int index, Object element)
Object set(int index, Object element)
Object get(int index)
int indexOf(Object o)
int lastIndexOf(Object o)
Object remove(int index)
以上幾個方法不需要死記硬背,可以自己編寫程式碼測試一下,理解一下,
以後開發的時候,還是要翻閱幫助文件。
*/
public class ListTest01 {
public static void main(String[] args) {
// 建立List型別的集合。
//List myList = new LinkedList();
//List myList = new Vector();
List myList = new ArrayList();
// 新增元素
myList.add("A"); // 預設都是向集合末尾新增元素。
myList.add("B");
myList.add("C");
myList.add("C");
myList.add("D");
//在列表的指定位置插入指定元素(第一個引數是下標)
// 這個方法使用不多,因為對於ArrayList集合來說效率比較低。
myList.add(1, "KING");
// 迭代
Iterator it = myList.iterator();
while(it.hasNext()){
Object elt = it.next();
System.out.println(elt);
}
// 根據下標獲取元素
Object firstObj = myList.get(0);
System.out.println(firstObj);
// 因為有下標,所以List集合有自己比較特殊的遍歷方式
// 通過下標遍歷。【List集合特有的方式,Set沒有。】
for(int i = 0; i < myList.size(); i++){
Object obj = myList.get(i);
System.out.println(obj);
}
// 獲取指定物件第一次出現處的索引。
System.out.println(myList.indexOf("C")); // 3
// 獲取指定物件最後一次出現處的索引。
System.out.println(myList.lastIndexOf("C")); // 4
// 刪除指定下標位置的元素
// 刪除下標為0的元素
myList.remove(0);
System.out.println(myList.size()); // 5
System.out.println("====================================");
// 修改指定位置的元素
myList.set(2, "Soft");
// 遍歷集合
for(int i = 0; i < myList.size(); i++){
Object obj = myList.get(i);
System.out.println(obj);
}
}
}
/*
計算機英語:
增刪改查這幾個單詞要知道:
增:add、save、new
刪:delete、drop、remove
改:update、set、modify
查:find、get、query、select
*/
ArrayListTest01——ArrayList集合
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.List;
/*
ArrayList集合:
1、預設初始化容量10(底層先建立了一個長度為0的陣列,當新增第一個元素的時候,初始化容量10。)
2、集合底層是一個Object[]陣列。
3、構造方法:
new ArrayList();
new ArrayList(20);
4、ArrayList集合的擴容:
增長到原容量的1.5倍。
ArrayList集合底層是陣列,怎麼優化?
儘可能少的擴容。因為陣列擴容效率比較低,建議在使用ArrayList集合
的時候預估計元素的個數,給定一個初始化容量。
5、陣列優點:
檢索效率比較高。(每個元素佔用空間大小相同,記憶體地址是連續的,知道首元素記憶體地址,
然後知道下標,通過數學表示式計算出元素的記憶體地址,所以檢索效率最高。)
6、陣列缺點:
隨機增刪元素效率比較低。
另外陣列無法儲存大資料量。(很難找到一塊非常巨大的連續的記憶體空間。)
7、向陣列末尾新增元素,效率很高,不受影響。
8、面試官經常問的一個問題?
這麼多的集合中,你用哪個集合最多?
答:ArrayList集合。
因為往陣列末尾新增元素,效率不受影響。
另外,我們檢索/查詢某個元素的操作比較多。
7、ArrayList集合是非執行緒安全的。(不是執行緒安全的集合。)
*/
public class ArrayListTest01 {
public static void main(String[] args) {
// 預設初始化容量是10
// 陣列的長度是10
List list1 = new ArrayList();
// 集合的size()方法是獲取當前集合中元素的個數。不是獲取集合的容量。
System.out.println(list1.size()); // 0
// 指定初始化容量
// 陣列的長度是20
List list2 = new ArrayList(20);
// 集合的size()方法是獲取當前集合中元素的個數。不是獲取集合的容量。
System.out.println(list2.size()); // 0
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
list1.add(6);
list1.add(7);
list1.add(8);
list1.add(9);
list1.add(10);
System.out.println(list1.size());
// 再加一個元素
list1.add(11);
System.out.println(list1.size()); // 11個元素。
/*
int newCapacity = ArraysSupport.newLength(oldCapacity,minCapacity - oldCapacity,oldCapacity >> 1);
*/
// 100 二進位制轉換成10進位制: 00000100右移一位 00000010 (2) 【4 / 2】
// 原先是4、現在增長:2,增長之後是6,增長之後的容量是之前容量的:1.5倍。
// 6是4的1.5倍
}
}
ArrayListTest02——集合ArrayList的構造方法
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/*
集合ArrayList的構造方法
*/
public class ArrayListTest02 {
public static void main(String[] args) {
// 預設初始化容量10
List myList1 = new ArrayList();
// 指定初始化容量100
List myList2 = new ArrayList(100);
// 建立一個HashSet集合
Collection c = new HashSet();
// 新增元素到Set集合
c.add(100);
c.add(200);
c.add(900);
c.add(50);
// 通過這個構造方法就可以將HashSet集合轉換成List集合。
List myList3 = new ArrayList(c);
for(int i = 0; i < myList3.size(); i++){
System.out.println(myList3.get(i));
}
}
}
LinkedListTest01——連結串列的原理以及優缺點
https://www.bilibili.com/video/BV1mE411x7Wt?p=211
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/*
連結串列的優點:
由於連結串列上的元素在空間儲存上記憶體地址不連續。
所以隨機增刪元素的時候不會有大量元素位移,因此隨機增刪效率較高。
在以後的開發中,如果遇到隨機增刪集合中元素的業務比較多時,建議
使用LinkedList。
連結串列的缺點:
不能通過數學表示式計算被查詢元素的記憶體地址,每一次查詢都是從頭
節點開始遍歷,直到找到為止。所以LinkedList集合檢索/查詢的效率
較低。
ArrayList:把檢索發揮到極致。(末尾新增元素效率還是很高的。)
LinkedList:把隨機增刪發揮到極致。
加元素都是往末尾新增,所以ArrayList用的比LinkedList多。
*/
public class LinkedListTest01 {
public static void main(String[] args) {
// LinkedList集合底層也是有下標的。
// 注意:ArrayList之所以檢索效率比較高,不是單純因為下標的原因。是因為底層陣列發揮的作用。
// LinkedList集合照樣有下標,但是檢索/查詢某個元素的時候效率比較低,因為只能從頭節點開始一個一個遍歷。
List list = new LinkedList();
list.add("a");
list.add("b");
list.add("c");
for(int i = 0; i <list.size(); i++){
Object obj = list.get(i);
System.out.println(obj);
}
// LinkedList集合有初始化容量嗎?沒有。
// 最初這個連結串列中沒有任何元素。first和last引用都是null。
// 不管是LinkedList還是ArrayList,以後寫程式碼時不需要關心具體是哪個集合。
// 因為我們要面向介面程式設計,呼叫的方法都是介面中的方法。
//List list2 = new ArrayList(); // 這樣寫表示底層你用了陣列。
List list2 = new LinkedList(); // 這樣寫表示底層你用了雙向連結串列。
// 以下這些方法你面向的都是介面程式設計。
list2.add("123");
list2.add("456");
list2.add("789");
for(int i = 0; i < list2.size(); i++){
System.out.println(list2.get(i));
}
}
}
單鏈表的實現
Node
package com.bjpowernode.javase.danlink;
/*
單鏈表中的節點。
節點是單向連結串列中基本的單元。
每一個節點Node都有兩個屬性:
一個屬性:是儲存的資料。
另一個屬性:是下一個節點的記憶體地址。
*/
public class Node {
// 儲存的資料
Object data;
// 下一個節點的記憶體地址
Node next;
public Node(){
}
public Node(Object data, Node next){
this.data = data;
this.next = next;
}
}
Link
package com.bjpowernode.javase.danlink;
/*
連結串列類。(單向連結串列)
*/
public class Link<E> {
public static void main(String[] args) {
Link<String> link = new Link<>();
link.add("abc");
// 型別不匹配。
//link.add(123);
}
// 頭節點
Node header;
int size = 0;
public int size(){
return size;
}
// 向連結串列中新增元素的方法(向末尾新增)
public void add(E data){
//public void add(Object data){
// 建立一個新的節點物件
// 讓之前單鏈表的末尾節點next指向新節點物件。
// 有可能這個元素是第一個,也可能是第二個,也可能是第三個。
if(header == null){
// 說明還沒有節點。
// new一個新的節點物件,作為頭節點物件。
// 這個時候的頭節點既是一個頭節點,又是一個末尾節點。
header = new Node(data, null);
}else {
// 說明頭不是空!
// 頭節點已經存在了!
// 找出當前末尾節點,讓當前末尾節點的next是新節點。
Node currentLastNode = findLast(header);
currentLastNode.next = new Node(data, null);
}
size++;
}
/**
* 專門查詢末尾節點的方法。
*/
private Node findLast(Node node) {
if(node.next == null) {
// 如果一個節點的next是null
// 說明這個節點就是末尾節點。
return node;
}
// 程式能夠到這裡說明:node不是末尾節點。
return findLast(node.next); // 遞迴演算法!
}
// 刪除連結串列中某個資料的方法
public void remove(Object obj){
}
// 修改連結串列中某個資料的方法
public void modify(Object newObj){
}
// 查詢連結串列中某個元素的方法。
public int find(Object obj){
return 1;
}
}
Test
package com.bjpowernode.javase.danlink;
public class Test {
public static void main(String[] args) {
// 建立了一個集合物件
Link link = new Link();
// 往集合中新增元素
link.add("abc");
link.add("def");
link.add("xyz");
// 獲取元素個數
System.out.println(link.size());
}
}
VectorTest——Vector集合原始碼分析
https://www.bilibili.com/video/BV1mE411x7Wt?p=212
import java.util.*;
/*
Vector:
1、底層也是一個數組。
2、初始化容量:10
3、怎麼擴容的?
擴容之後是原容量的2倍。
10--> 20 --> 40 --> 80
4、ArrayList集合擴容特點:
ArrayList集合擴容是原容量1.5倍。
5、Vector中所有的方法都是執行緒同步的,都帶有synchronized關鍵字,
是執行緒安全的。效率比較低,使用較少了。
6、怎麼將一個執行緒不安全的ArrayList集合轉換成執行緒安全的呢?
使用集合工具類:
java.util.Collections;
java.util.Collection 是集合介面。
java.util.Collections 是集合工具類。
*/
public class VectorTest {
public static void main(String[] args) {
// 建立一個Vector集合
List vector = new Vector();
//Vector vector = new Vector();
// 新增元素
// 預設容量10個。
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
vector.add(6);
vector.add(7);
vector.add(8);
vector.add(9);
vector.add(10);
// 滿了之後擴容(擴容之後的容量是20.)
vector.add(11);
Iterator it = vector.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
// 這個可能以後要使用!!!!
List myList = new ArrayList(); // 非執行緒安全的。
// 變成執行緒安全的
Collections.synchronizedList(myList); // 這裡沒有辦法看效果,因為多執行緒沒學,你記住先!
// myList集合就是執行緒安全的了。
myList.add("111");
myList.add("222");
myList.add("333");
}
}
GenericTest01——泛型
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
1、JDK5.0之後推出的新特性:泛型
2、泛型這種語法機制,只在程式編譯階段起作用,只是給編譯器參考的。(執行階段泛型沒用!)
3、使用了泛型好處是什麼?
第一:集合中儲存的元素型別統一了。
第二:從集合中取出的元素型別是泛型指定的型別,不需要進行大量的“向下轉型”!
4、泛型的缺點是什麼?
導致集合中儲存的元素缺乏多樣性!
大多數業務中,集合中元素的型別還是統一的。所以這種泛型特性被大家所認可。
*/
public class GenericTest01 {
public static void main(String[] args) {
/*
// 不使用泛型機制,分析程式存在缺點
List myList = new ArrayList();
// 準備物件
Cat c = new Cat();
Bird b = new Bird();
// 將物件新增到集合當中
myList.add(c);
myList.add(b);
// 遍歷集合,取出每個Animal,讓它move
Iterator it = myList.iterator();
while(it.hasNext()) {
// 沒有這個語法,通過迭代器取出的就是Object
//Animal a = it.next();
Object obj = it.next();
//obj中沒有move方法,無法呼叫,需要向下轉型!
if(obj instanceof Animal){
Animal a = (Animal)obj;
a.move();
}
}
*/
// 使用JDK5之後的泛型機制
// 使用泛型List<Animal>之後,表示List集合中只允許儲存Animal型別的資料。
// 用泛型來指定集合中儲存的資料型別。
List<Animal> myList = new ArrayList<Animal>();
// 指定List集合中只能儲存Animal,那麼儲存String就編譯報錯了。
// 這樣用了泛型之後,集合中元素的資料型別更加統一了。
//myList.add("abc");
Cat c = new Cat();
Bird b = new Bird();
myList.add(c);
myList.add(b);
// 獲取迭代器
// 這個表示迭代器迭代的是Animal型別。
Iterator<Animal> it = myList.iterator();
while(it.hasNext()){
// 使用泛型之後,每一次迭代返回的資料都是Animal型別。
//Animal a = it.next();
// 這裡不需要進行強制型別轉換了。直接呼叫。
//a.move();
// 呼叫子型別特有的方法還是需要向下轉換的!
Animal a = it.next();
if(a instanceof Cat) {
Cat x = (Cat)a;
x.catchMouse();
}
if(a instanceof Bird) {
Bird y = (Bird)a;
y.fly();
}
}
}
}
class Animal {
// 父類自帶方法
public void move(){
System.out.println("動物在移動!");
}
}
class Cat extends Animal {
// 特有方法
public void catchMouse(){
System.out.println("貓抓老鼠!");
}
}
class Bird extends Animal {
// 特有方法
public void fly(){
System.out.println("鳥兒在飛翔!");
}
}
GenericTest02——【泛型】自動型別推斷機制
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
JDK1.8之後引入了:自動型別推斷機制。(又稱為鑽石表示式)
*/
public class GenericTest02 {
public static void main(String[] args) {
// ArrayList<這裡的型別會自動推斷>(),前提是JDK8之後才允許。
// 自動型別推斷,鑽石表示式!
List<Animal> myList = new ArrayList<>();
myList.add(new Animal());
myList.add(new Cat());
myList.add(new Bird());
// 遍歷
Iterator<Animal> it = myList.iterator();
while(it.hasNext()){
Animal a = it.next();
a.move();
}
List<String> strList = new ArrayList<>();
// 型別不匹配。
//strList.add(new Cat());
strList.add("http://www.126.com");
strList.add("http://www.baidu.com");
strList.add("http://www.bjpowernode.com");
// 型別不匹配。
//strList.add(123);
//System.out.println(strList.size());
// 遍歷
Iterator<String> it2 = strList.iterator();
while(it2.hasNext()){
// 如果沒有使用泛型
/*
Object obj = it2.next();
if(obj instanceof String){
String ss = (String)obj;
ss.substring(7);
}
*/
// 直接通過迭代器獲取了String型別的資料
String s = it2.next();
// 直接呼叫String類的substring方法擷取字串。
String newString = s.substring(7);
System.out.println(newString);
}
}
}
GenericTest03——自定義泛型
package com.bjpowernode.javase.collection;
/*
自定義泛型可以嗎?可以
自定義泛型的時候,<> 尖括號中的是一個識別符號,隨便寫。
java原始碼中經常出現的是:
<E>和<T>
E是Element單詞首字母。
T是Type單詞首字母。
*/
public class GenericTest03<識別符號隨便寫> {
public void doSome(識別符號隨便寫 o){
System.out.println(o);
}
public static void main(String[] args) {
// new物件的時候指定了泛型是:String型別
GenericTest03<String> gt = new GenericTest03<>();
// 型別不匹配
//gt.doSome(100);
gt.doSome("abc");
// =============================================================
GenericTest03<Integer> gt2 = new GenericTest03<>();
gt2.doSome(100);
// 型別不匹配
//gt2.doSome("abc");
MyIterator<String> mi = new MyIterator<>();
String s1 = mi.get();
MyIterator<Animal> mi2 = new MyIterator<>();
Animal a = mi2.get();
// 不用泛型就是Object型別。
/*GenericTest03 gt3 = new GenericTest03();
gt3.doSome(new Object());*/
}
}
class MyIterator<T> {
public T get(){
return null;
}
}
ForEachTest01——增強for迴圈
語法:
for(元素型別
變數名
: 陣列或集合
){
System.out.println(變數名
);
}
package com.bjpowernode.javase.collection;
/*
JDK5.0之後推出了一個新特性:叫做增強for迴圈,或者叫做foreach
*/
public class ForEachTest01 {
public static void main(String[] args) {
// int型別陣列
int[] arr = {432,4,65,46,54,76,54};
// 遍歷陣列(普通for迴圈)
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 增強for(foreach)
// 以下是語法
/*for(元素型別 變數名 : 陣列或集合){
System.out.println(變數名);
}*/
System.out.println("======================================");
// foreach有一個缺點:沒有下標。在需要使用下標的迴圈中,不建議使用增強for迴圈。
for(int data : arr) {
// data就是陣列中的元素(陣列中的每一個元素。)
System.out.println(data);
}
}
}
ForEachTest02——集合使用foreach
遍歷集合的三種方式:
- 使用迭代器方式
- 使用下標方式(只針對於有下標的集合)
- 使用foreach
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
集合使用foreach
*/
public class ForEachTest02 {
public static void main(String[] args) {
// 建立List集合
List<String> strList = new ArrayList<>();
// 新增元素
strList.add("hello");
strList.add("world!");
strList.add("kitty!");
// 遍歷,使用迭代器方式
Iterator<String> it = strList.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
// 使用下標方式(只針對於有下標的集合)
for(int i = 0; i < strList.size(); i++){
System.out.println(strList.get(i));
}
// 使用foreach
for(String s : strList){ // 因為泛型使用的是String型別,所以是:String s
System.out.println(s);
}
List<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
list.add(300);
for(Integer i : list){ // i代表集合中的元素
System.out.println(i);
}
}
}
HashSetTest01——HashSet集合【無序不可重複】
package com.bjpowernode.javase.collection;
import java.util.HashSet;
import java.util.Set;
/*
HashSet集合:
無序不可重複。
*/
public class HashSetTest01 {
public static void main(String[] args) {
// 演示一下HashSet集合特點
Set<String> strs = new HashSet<>();
// 新增元素
strs.add("hello3");
strs.add("hello4");
strs.add("hello1");
strs.add("hello2");
strs.add("hello3");
strs.add("hello3");
strs.add("hello3");
strs.add("hello3");
// 遍歷
/*
hello1
hello4
hello2
hello3
1、儲存時順序和取出的順序不同。
2、不可重複。
3、放到HashSet集合中的元素實際上是放到HashMap集合的key部分了。
*/
for(String s : strs){
System.out.println(s);
}
}
}
TreeSetTest01——TreeSet集合【無序不可重複,可排序集合】
package com.bjpowernode.javase.collection;
import java.util.Set;
import java.util.TreeSet;
/*
TreeSet集合儲存元素特點:
1、無序不可重複的,但是儲存的元素可以自動按照大小順序排序!
稱為:可排序集合。
2、無序:這裡的無序指的是存進去的順序和取出來的順序不同。並且沒有下標。
*/
public class TreeSetTest01 {
public static void main(String[] args) {
// 建立集合物件
Set<String> strs = new TreeSet<>();
// 新增元素
strs.add("A");
strs.add("B");
strs.add("Z");
strs.add("Y");
strs.add("Z");
strs.add("K");
strs.add("M");
// 遍歷
/*
A
B
K
M
Y
Z
從小到大自動排序!
*/
for(String s : strs){
System.out.println(s);
}
}
}
Map部分
MapTest01——java.util.Map介面中常用的方法
package com.bjpowernode.javase.collection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/*
java.util.Map介面中常用的方法:
1、Map和Collection沒有繼承關係。
2、Map集合以key和value的方式儲存資料:鍵值對
key和value都是引用資料型別。
key和value都是儲存物件的記憶體地址。
key起到主導的地位,value是key的一個附屬品。
3、Map介面中常用方法:
V put(K key, V value) 向Map集合中新增鍵值對
V get(Object key) 通過key獲取value
void clear() 清空Map集合
boolean containsKey(Object key) 判斷Map中是否包含某個key
boolean containsValue(Object value) 判斷Map中是否包含某個value
boolean isEmpty() 判斷Map集合中元素個數是否為0
V remove(Object key) 通過key刪除鍵值對
int size() 獲取Map集合中鍵值對的個數。
Collection<V> values() 獲取Map集合中所有的value,返回一個Collection
Set<K> keySet() 獲取Map集合所有的key(所有的鍵是一個set集合)
Set<Map.Entry<K,V>> entrySet()
將Map集合轉換成Set集合
假設現在有一個Map集合,如下所示:
map1集合物件
key value
----------------------------
1 zhangsan
2 lisi
3 wangwu
4 zhaoliu
Set set = map1.entrySet();
set集合物件
1=zhangsan 【注意:Map集合通過entrySet()方法轉換成的這個Set集合,Set集合中元素的型別是 Map.Entry<K,V>】
2=lisi 【Map.Entry和String一樣,都是一種型別的名字,只不過:Map.Entry是靜態內部類,是Map中的靜態內部類】
3=wangwu
4=zhaoliu ---> 這個東西是個什麼?Map.Entry
*/
public class MapTest01 {
public static void main(String[] args) {
// 建立Map集合物件
Map<Integer, String> map = new HashMap<>();
// 向Map集合中新增鍵值對
map.put(1, "zhangsan"); // 1在這裡進行了自動裝箱。
map.put(2, "lisi");
map.put(3, "wangwu");
map.put(4, "zhaoliu");
// 通過key獲取value
String value = map.get(2);
System.out.println(value);
// 獲取鍵值對的數量
System.out.println("鍵值對的數量:" + map.size());
// 通過key刪除key-value
map.remove(2);
System.out.println("鍵值對的數量:" + map.size());
// 判斷是否包含某個key
// contains方法底層呼叫的都是equals進行比對的,所以自定義的型別需要重寫equals方法。
System.out.println(map.containsKey(new Integer(4))); // true
// 判斷是否包含某個value
System.out.println(map.containsValue(new String("wangwu"))); // true
// 獲取所有的value
Collection<String> values = map.values();
// foreach
for(String s : values){
System.out.println(s);
}
// 清空map集合
map.clear();
System.out.println("鍵值對的數量:" + map.size());
// 判斷是否為空
System.out.println(map.isEmpty()); // true
}
}
MapTest02——Map集合的遍歷【非常重要】
package com.bjpowernode.javase.collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
Map集合的遍歷。【非常重要】
*/
public class MapTest02 {
public static void main(String[] args) {
// 第一種方式:獲取所有的key,通過遍歷key,來遍歷value
Map<Integer, String> map = new HashMap<>();
map.put(1, "zhangsan");
map.put(2, "lisi");
map.put(3, "wangwu");
map.put(4, "zhaoliu");
// 遍歷Map集合
// 獲取所有的key,所有的key是一個Set集合
Set<Integer> keys = map.keySet();
// 遍歷key,通過key獲取value
// 迭代器可以
/*Iterator<Integer> it = keys.iterator();
while(it.hasNext()){
// 取出其中一個key
Integer key = it.next();
// 通過key獲取value
String value = map.get(key);
System.out.println(key + "=" + value);
}*/
// foreach也可以
for(Integer key : keys){
System.out.println(key + "=" + map.get(key));
}
// 第二種方式:Set<Map.Entry<K,V>> entrySet()
// 以上這個方法是把Map集合直接全部轉換成Set集合。
// Set集合中元素的型別是:Map.Entry
Set<Map.Entry<Integer,String>> set = map.entrySet();
// 遍歷Set集合,每一次取出一個Node
// 迭代器
/*Iterator<Map.Entry<Integer,String>> it2 = set.iterator();
while(it2.hasNext()){
Map.Entry<Integer,String> node = it2.next();
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key + "=" + value);
}*/
// foreach
// 這種方式效率比較高,因為獲取key和value都是直接從node物件中獲取的屬性值。
// 這種方式比較適合於大資料量。
for(Map.Entry<Integer,String> node : set){
System.out.println(node.getKey() + "--->" + node.getValue());
}
}
}
HashMapTest01——HashMap集合底層原理
https://www.bilibili.com/video/BV1mE411x7Wt?p=224
https://www.bilibili.com/video/BV1mE411x7Wt?p=225
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
HashMap集合:
1、HashMap集合底層是雜湊表/散列表的資料結構。
2、雜湊表是一個怎樣的資料結構呢?
雜湊表是一個數組和單向連結串列的結合體。
陣列:在查詢方面效率很高,隨機增刪方面效率很低。
單向連結串列:在隨機增刪方面效率較高,在查詢方面效率很低。
雜湊表將以上的兩種資料結構融合在一起,充分發揮它們各自的優點。
3、HashMap集合底層的原始碼:
public class HashMap{
// HashMap底層實際上就是一個數組。(一維陣列)
Node<K,V>[] table;
// 靜態的內部類HashMap.Node
static class Node<K,V> {
final int hash; // 雜湊值(雜湊值是key的hashCode()方法的執行結果。hash值通過雜湊函式/演算法,可以轉換儲存成陣列的下標。)
final K key; // 儲存到Map集合中的那個key
V value; // 儲存到Map集合中的那個value
Node<K,V> next; // 下一個節點的記憶體地址。
}
}
雜湊表/散列表:一維陣列,這個陣列中每一個元素是一個單向連結串列。(陣列和連結串列的結合體。)
4、最主要掌握的是:
map.put(k,v)
v = map.get(k)
以上這兩個方法的實現原理,是必須掌握的。
5、HashMap集合的key部分特點:
無序,不可重複。
為什麼無序? 因為不一定掛到哪個單向連結串列上。
不可重複是怎麼保證的? equals方法來保證HashMap集合的key不可重複。
如果key重複了,value會覆蓋。
放在HashMap集合key部分的元素其實就是放到HashSet集合中了。
所以HashSet集合中的元素也需要同時重寫hashCode()+equals()方法。
6、雜湊表HashMap使用不當時無法發揮性能!
假設將所有的hashCode()方法返回值固定為某個值,那麼會導致底層雜湊表變成了
純單向連結串列。這種情況我們成為:雜湊分佈不均勻。
什麼是雜湊分佈均勻?
假設有100個元素,10個單向連結串列,那麼每個單向連結串列上有10個節點,這是最好的,
是雜湊分佈均勻的。
假設將所有的hashCode()方法返回值都設定為不一樣的值,可以嗎,有什麼問題?
不行,因為這樣的話導致底層雜湊表就成為一維陣列了,沒有連結串列的概念了。
也是雜湊分佈不均勻。
雜湊分佈均勻需要你重寫hashCode()方法時有一定的技巧。
7、重點:放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同時重寫hashCode和equals方法。
8、HashMap集合的預設初始化容量是16,預設載入因子是0.75
這個預設載入因子是當HashMap集合底層陣列的容量達到75%的時候,陣列開始擴容。
重點,記住:HashMap集合初始化容量必須是2的次冪(方便求雜湊值用的),這也是官方推薦的,
這是因為達到雜湊均勻,為了提高HashMap集合的存取效率,所必須的。
*/
public class HashMapTest01 {
public static void main(String[] args) {
// 測試HashMap集合key部分的元素特點
// Integer是key,它的hashCode和equals都重寫了。
Map<Integer,String> map = new HashMap<>();
map.put(1111, "zhangsan");
map.put(6666, "lisi");
map.put(7777, "wangwu");
map.put(2222, "zhaoliu");
map.put(2222, "king"); //key重複的時候value會自動覆蓋。
System.out.println(map.size()); // 4
// 遍歷Map集合
Set<Map.Entry<Integer,String>> set = map.entrySet();
for(Map.Entry<Integer,String> entry : set){
// 驗證結果:HashMap集合key部分元素:無序不可重複。
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
HashMapTest02——重寫equals方法和hashCode方法
package com.bjpowernode.javase.bean;
import java.util.HashSet;
import java.util.Set;
/*
1、向Map集合中存,以及從Map集合中取,先封裝成Node,都是先呼叫key的hashCode方法,然後再呼叫equals方法!
equals方法有可能呼叫,也有可能不呼叫。
拿put(k,v)舉例,什麼時候equals不會呼叫?
k.hashCode()方法返回雜湊值,
雜湊值經過雜湊演算法轉換成陣列下標。
陣列下標位置上如果是null,equals不需要執行。
拿get(k)舉例,什麼時候equals不會呼叫?
k.hashCode()方法返回雜湊值,
雜湊值經過雜湊演算法轉換成陣列下標。
陣列下標位置上如果是null,equals不需要執行。
2、注意:如果一個類的equals方法重寫了,那麼hashCode()方法必須重寫。
並且equals方法返回如果是true,hashCode()方法返回的值必須一樣。
equals方法返回true表示兩個物件相同,在同一個單向連結串列上比較。
那麼對於同一個單向連結串列上的節點來說,他們的雜湊值都是相同的。
所以hashCode()方法的返回值也應該相同。
3、hashCode()方法和equals()方法不用研究了,直接使用IDEA工具生成,但是這兩個方法需要同時生成。
4、終極結論:
放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同時重寫hashCode方法和equals方法。
5、對於雜湊表資料結構來說:
如果o1和o2的hash值相同,一定是放到同一個單向連結串列上。
當然如果o1和o2的hash值不同,但由於雜湊演算法執行結束之後轉換的陣列下標可能相同,此時會發生“雜湊碰撞”。
*/
public class HashMapTest02 {
public static void main(String[] args) {
Student s1 = new Student("zhangsan");
Student s2 = new Student("zhangsan");
// 重寫equals方法之前是false
//System.out.println(s1.equals(s2)); // false
// 重寫equals方法之後是true
System.out.println(s1.equals(s2)); //true (s1和s2表示相等)
//返回的是物件的記憶體地址
System.out.println("s1的hashCode=" + s1.hashCode()); //284720968 (重寫hashCode之後-1432604525)
System.out.println("s2的hashCode=" + s2.hashCode()); //122883338 (重寫hashCode之後-1432604525)
// s1.equals(s2)結果已經是true了,表示s1和s2是一樣的,相同的,那麼往HashSet集合中放的話,
// 按說只能放進去1個。(HashSet集合特點:無序不可重複)
Set<Student> students = new HashSet<>();
students.add(s1);
students.add(s2);
System.out.println(students.size()); // 這個結果按說應該是1. 但是結果是2.顯然不符合HashSet集合儲存特點。怎麼辦?
}
}
Student
package com.bjpowernode.javase.bean;
import java.util.Objects;
public class Student {
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// hashCode
// equals(如果學生名字一樣,表示同一個學生。)
/*public boolean equals(Object obj){
if(obj == null || !(obj instanceof Student)) return false;
if(obj == this) return true;
Student s = (Student)obj;
return this.name.equals(s.name);
}*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
HashMapTest03——HashMap集合key部分允許null嗎?
package com.bjpowernode.javase.bean;
import java.util.HashMap;
import java.util.Map;
/*
HashMap集合key部分允許null嗎?
允許
但是要注意:HashMap集合的key null值只能有一個。
有可能面試的時候遇到這樣的問題。
*/
public class HashMapTest03 {
public static void main(String[] args) {
Map map = new HashMap();
// HashMap集合允許key為null
map.put(null, null);
System.out.println(map.size()); // 1
// key重複的話value是覆蓋!
map.put(null, 100);
System.out.println(map.size()); //1
// 通過key獲取value
System.out.println(map.get(null)); // 100
}
}
HashtableTest01——Hashtable的key可以為null嗎?
package com.example.javase.bean;
import java.util.Hashtable;
import java.util.Map;
/*
Hashtable的key可以為null嗎?
Hashtable的key和value都是不能為null的。
HashMap集合的key和value都是可以為null的。
Hashtable方法都帶有synchronized:執行緒安全的。
執行緒安全有其它的方案,這個Hashtable對執行緒的處理
導致效率較低,使用較少了。
Hashtable和HashMap一樣,底層都是雜湊表資料結構。
Hashtable的初始化容量是11,預設載入因子是:0.75f
Hashtable的擴容是:原容量 * 2 + 1
*/
public class HashtableTest01 {
public static void main(String[] args) {
Map map = new Hashtable();
//map.put(null, "123");
map.put(100, null);
}
}
PropertiesTest01——Properties屬性類物件的相關方法
package com.example.javase.collection;
import java.util.Properties;
/*
目前只需要掌握Properties屬性類物件的相關方法即可。
Properties是一個Map集合,繼承Hashtable,Properties的key和value都是String型別。
Properties被稱為屬性類物件。
Properties是執行緒安全的。
*/
public class PropertiesTest01 {
public static void main(String[] args) {
// 建立一個Properties物件
Properties pro = new Properties();
// 需要掌握Properties的兩個方法,一個存,一個取。
pro.setProperty("url", "jdbc:mysql://localhost:3306/example");
pro.setProperty("driver","com.mysql.jdbc.Driver");
pro.setProperty("username", "root");
pro.setProperty("password", "123");
// 通過key獲取value
String url = pro.getProperty("url");
String driver = pro.getProperty("driver");
String username = pro.getProperty("username");
String password = pro.getProperty("password");
System.out.println(url);
System.out.println(driver);
System.out.println(username);
System.out.println(password);
}
}