一、Collection集合
1、集合:集合是java中提供的一種容器,可以用來存儲多個數據。
2、集合和數組既然都是容器,它們有什麼區別呢?
數組的長度是固定的。集合的長度是可變的。
數組中存儲的是同一類型的元素,可以存儲基本數據類型值。集合存儲的都是對象。而且對象的類型可以不一致。在開發中一般當對象多的時候,使用集合進行存儲。
3、集合按照其存儲結構可以分爲兩大類,分別是單列集合java.util.Collection
和雙列集合java.util.Map
。
Collection:單列集合類的根接口,用於存儲一系列符合某種規則的元素,它有兩個重要的子接口,分別是java.util.List
和java.util.Set
。其中,List
的特點是元素有序、元素可重複。Set
的特點是元素無序,而且不可重複。List
接口的主要實現類有java.util.ArrayList
和java.util.LinkedList
,Set
接口的主要實現類有java.util.HashSet
和java.util.TreeSet
。
具體如圖所示:
4、List接口介紹:
1)它是一個元素存取有序的集合。例如,存元素的順序是11、22、33。那麼集合中,元素的存儲就是按照11、22、33的順序完成的)。
2)它是一個帶有索引的集合,通過索引就可以精確的操作集合中的元素(與數組的索引是一個道理)。
3)集合中可以有重複的元素,通過元素的equals方法,來比較是否爲重複的元素。
5、ArrayList集合。java.util.ArrayList
集合數據存儲的結構是數組結構。元素增刪慢,查找快,由於日常開發中使用最多的功能爲查詢數據、遍歷數據,所以ArrayList
是最常用的集合。
許多程序員開發時非常隨意地使用ArrayList完成任何需求,並不嚴謹,這種用法是不提倡的。
6、LinkedList集合。java.util.LinkedList
集合數據存儲的結構是鏈表結構。方便元素添加、刪除的集合。
LinkedList是一個雙向鏈表,如下圖:
LinkedList是List的子類,List中的方法LinkedList都是可以使用,這裏就不做詳細介紹,我們只需要瞭解LinkedList的特有方法即可。在開發時,LinkedList集合也可以作爲堆棧,隊列的結構使用。(瞭解即可)
7、Set接口介紹:
java.util.Set
接口和java.util.List
接口一樣,同樣繼承自Collection
接口,它與Collection
接口中的方法基本一致,並沒有對Collection
接口進行功能上的擴充,只是比Collection
接口更加嚴格了。與List
接口不同的是,Set
接口中元素無序,並且都會以某種規則保證存入的元素不出現重複。
Set
集合有多個子類,這裏我們介紹其中的java.util.HashSet
、java.util.LinkedHashSet
這兩個集合。
8、HashSet集合。HashSet
是根據對象的哈希值來確定元素在集合中的存儲位置,因此具有良好的存取和查找性能。保證元素唯一性的方式依賴於:hashCode
與equals
方法。HashSet集合存儲數據的結構(哈希表)。
哈希值:是一個十進制的整數,由系統隨機給出(就是對象的地址值,是一個邏輯地址,是模擬出來得到地址,不是數據實際存儲的物理地址)。 在Object類有一個方法,可以獲取對象的哈希值。 int hashCode() 返回該對象的哈希碼值。hashCode方法的源碼:public native int hashCode(); 其中 native:代表該方法調用的是本地操作系統的方法。
9、HashS集合內部如何實現?
在JDK1.8之前,哈希表底層採用數組+鏈表實現,即使用鏈表處理衝突,同一hash值的鏈表都存儲在一個鏈表裏。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。而JDK1.8中,哈希表存儲採用數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換爲紅黑樹,這樣大大減少了查找時間。
簡單的來說,哈希表是由數組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實現的,如下圖所示。
總而言之,JDK1.8引入紅黑樹大程度優化了HashMap的性能,那麼對於我們來講保證HashSet集合元素的唯一,其實就是根據對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那麼保證其唯一,就必須複寫hashCode和equals方法建立屬於當前對象的比較方式。
10、可變參數。
可變參數:是JDK1.5之後出現的新特性。
使用前提:
當方法的參數列表數據類型已經確定,但是參數的個數不確定,就可以使用可變參數。
使用格式:定義方法時使用
修飾符 返回值類型 方法名(數據類型…變量名){}
可變參數的原理:
可變參數底層就是一個數組,根據傳遞參數個數不同,會創建不同長度的數組,來存儲這些參數。
傳遞的參數個數,可以是0個(不傳遞),1,2…多個。
代碼演示:
public class ChangeArgs {
public static void main(String[] args) {
int[] arr = { 1, 4, 62, 431, 2 };
int sum = getSum(arr);
System.out.println(sum);
// 6 7 2 12 2121
// 求 這幾個元素和 6 7 2 12 2121
int sum2 = getSum(6, 7, 2, 12, 2121);
System.out.println(sum2);
}
/*
* 完成數組 所有元素的求和 原始寫法
public static int getSum(int[] arr){
int sum = 0;
for(int a : arr){
sum += a;
}
return sum;
}
*/
//可變參數寫法
public static int getSum(int... arr) {
int sum = 0;
for (int a : arr) {
sum += a;
}
return sum;
}
}
11、說到排序,簡單的說就是兩個對象之間比較大小,那麼在JAVA中提供了兩種比較實現的方式,一種是比較死板的 採用 java.lang.Comparable 接口去實現,一種是靈活的當我需要做排序的時候在去選擇的 java.util.Comparator 接口完成。
12、簡述Comparable和Comparator兩個接口的區別?
Comparable:強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序,類的compareTo方法被稱爲它的自然比較方法。只能在類中實現compareTo()一次,不能經常修改類的代碼實現自己想要的排序。實現此接口的對象列表(和數組)可以通過Collections.sort(和Arrays.sort)進行自動排序,對象可以用作有序映射中的鍵或有序集合中的元素,無需指定比較器。
Comparator強行對某個對象進行整體排序。可以將Comparator 傳遞給sort方法(如Collections.sort或 Arrays.sort),從而允許在排序順序上實現精確控制。還可以使用Comparator來控制某些數據結構(如有序set或有序映射)的順序,或者爲那些沒有自然順序的對象collection提供排序。
Collections.sort(list02, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年齡升序排序
int result = o1.getAge()-o2.getAge();
//如果兩個人年齡相同,再使用姓名的第一個字比較
if(result==0){
result = o1.getName().charAt(0)-o2.getName().charAt(0);
}
return result;
}
});
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重寫排序的規則
@Override
public int compareTo(Person o) {
//return 0;//認爲元素都是相同的
//自定義比較的規則,比較兩個人的年齡(this,參數Person)
//return this.getAge() - o.getAge();//年齡升序排序
return o.getAge() - this.getAge();//年齡升序排序
}
}
可以說一個是自已完成比較,一個是外部程序實現比較的差別而已。
二、Iterator迭代器
1、在程序開發中,經常需要遍歷集合中的所有元素。針對這種需求,JDK專門提供了一個接口java.util.Iterator
。Iterator
接口也是Java集合中的一員,但它與Collection
、Map
接口有所不同,Collection
接口與Map
接口主要用於存儲元素,而Iterator
主要用於迭代訪問(即遍歷)Collection
中的元素,因此Iterator
對象也被稱爲迭代器。
2、當遍歷集合時,首先通過調用t集合的iterator()方法獲得迭代器對象,然後使用hashNext()方法判斷集合中是否存在下一個元素,如果存在,則調用next()方法將元素取出,否則說明已到達了集合末尾,停止遍歷元素。
Iterator迭代器對象在遍歷集合時,內部採用指針的方式來跟蹤集合中的元素,接下來通過一個圖例來演示Iterator對象迭代元素的過程:
3、增強for:增強for循環(也稱for each循環)是JDK1.5以後出來的一個高級for循環,專門用來遍歷數組和集合的。它的內部原理其實是個Iterator迭代器,所以在遍歷的過程中,不能對集合中的元素進行增刪操作。
格式:
for(元素的數據類型 變量 : Collection集合or數組){
//寫操作代碼
}
它用於遍歷Collection和數組。通常只進行遍歷元素,不要在遍歷的過程中對集合元素進行增刪操作。
遍歷數組:
public class NBForDemo1 {
public static void main(String[] args) {
int[] arr = {3,5,6,87};
//使用增強for遍歷數組
for(int a : arr){//a代表數組中的每個元素
System.out.println(a);
}
}
}
遍歷集合:
public class NBFor {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<String>();
coll.add("小河神");
coll.add("老河神");
coll.add("神婆");
//使用增強for遍歷
for(String s :coll){//接收變量s代表 代表被遍歷到的集合元素
System.out.println(s);
}
}
}
三、泛型
1、泛型:可以在類或方法中預支地使用未知的類型。
2、使用泛型的好處:
- 將運行時期(run運行的時候)的ClassCastException,轉移到了編譯時期(寫代碼的時候)變成了編譯失敗。
- 避免了類型強轉的麻煩,存儲什麼類型,取出就是什麼類型,不用做類型轉換。