今日內容介紹
一、List接口
二、Set接口
三、判斷集合惟一性原理java
很是重要的關係圖面試
xmind下載地址數組
連接:https://pan.baidu.com/s/1kx0XabmT27pt4Ll9AqzVog 密碼:bjgt安全
A:List接口的特色:數據結構
a:它是一個元素存取有序的集合。 例如,存元素的順序是十一、2二、33。那麼集合中,元素的存儲就是按照十一、2二、33的順序完成的)。 b:它是一個帶有索引的集合,經過索引就能夠精確的操做集合中的元素(與數組的索引是一個道理)。 c:集合中能夠有重複的元素,經過元素的equals方法,來比較是否爲重複的元素。 d:List接口的經常使用子類有: ArrayList集合 LinkedList集合
A:List接口的特有方法(帶索引的方法) a:增長元素方法 add(Object e):向集合末尾處,添加指定的元素 add(int index, Object e) 向集合指定索引處,添加指定的元素,原有元素依次後移 /* * add(int index, E) * 將元素插入到列表的指定索引上 * 帶有索引的操做,防止越界問題 * java.lang.IndexOutOfBoundsException * ArrayIndexOutOfBoundsException * StringIndexOutOfBoundsException */ public static void function(){ List<String> list = new ArrayList<String>(); list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); System.out.println(list); list.add(1, "itcast"); System.out.println(list); } b:刪除元素刪除 remove(Object e):將指定元素對象,從集合中刪除,返回值爲被刪除的元素 remove(int index):將指定索引處的元素,從集合中刪除,返回值爲被刪除的元素 /* * E remove(int index) * 移除指定索引上的元素 * 返回被刪除以前的元素 */ public static void function_1(){ List<Double> list = new ArrayList<Double>(); list.add(1.1); list.add(1.2); list.add(1.3); list.add(1.4); Double d = list.remove(0); System.out.println(d); System.out.println(list); } c:替換元素方法 set(int index, Object e):將指定索引處的元素,替換成指定的元素,返回值爲替換前的元素 /* * E set(int index, E) * 修改指定索引上的元素 * 返回被修改以前的元素 */ public static void function_2(){ List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(4); Integer i = list.set(0, 5); System.out.println(i); System.out.println(list); } d:查詢元素方法 get(int index):獲取指定索引處的元素,並返回該元素
A:迭代器的併發修改異常 /* * 迭代器的併發修改異常 java.util.ConcurrentModificationException * 就是在遍歷的過程當中,使用了集合方法修改了集合的長度,不容許的 */ public class ListDemo1 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); //對集合使用迭代器進行獲取,獲取時候判斷集合中是否存在 "abc3"對象 //若是有,添加一個元素 "ABC3" Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); //對獲取出的元素s,進行判斷,是否是有"abc3" if(s.equals("abc3")){ list.add("ABC3"); } System.out.println(s); } } } 運行上述代碼發生了錯誤 java.util.ConcurrentModificationException這是什麼緣由呢? 在迭代過程當中,使用了集合的方法對元素進行操做。 致使迭代器並不知道集合中的變化,容易引起數據的不肯定性。 併發修改異常解決辦法: 在迭代時,不要使用集合的方法操做元素。 或者經過ListIterator迭代器操做元素是能夠的,ListIterator的出現,解決了使用Iterator迭代過程當中可能會發生的錯誤狀況。
A:數據的存儲結構 a:棧結構:後進先出/先進後出(手槍彈夾) FILO (first in last out) b:隊列結構:先進先出/後進後出(銀行排隊) FIFO(first in first out) c:數組結構: 查詢快:經過索引快速找到元素 增刪慢:每次增刪都須要開闢新的數組,將老數組中的元素拷貝到新數組中 開闢新數組耗費資源 d:鏈表結構 查詢慢:每次都須要從鏈頭或者鏈尾找起 增刪快:只須要修改元素記錄的下個元素的地址值便可不須要移動大量元素
A:ArrayList集合的自身特色併發
底層採用的是數組結構 ArrayList al=new ArrayList();//建立了一個長度爲0的Object類型數組 al.add("abc");//底層會建立一個長度爲10的Object數組 Object[] obj=new Object[10] //obj[0]="abc" //若是添加的元素的超過10個,底層會開闢一個1.5*10的長度的新數組 //把原數組中的元素拷貝到新數組,再把最後一個元素添加到新數組中 原數組: a b c d e f g h k l 添加m: a b c d e f g h k l m null null null null
A:LinkedList集合的自身特色性能
底層採用鏈表結構,每次查詢都要從鏈頭或鏈尾找起,查詢相對數組較慢 可是刪除直接修改元素記錄的地址值便可,不要大量移動元素 LinkedList的索引決定是從鏈頭開始找仍是從鏈尾開始找 若是該元素小於元素長度一半,從鏈頭開始找起,若是大於元素長度的一半,則從鏈尾找起
*A:LinkedList特有方法:獲取,添加,刪除測試
/* * LinkedList 鏈表集合的特有功能 * 自身特色: 鏈表底層實現,查詢慢,增刪快 * * 子類的特有功能,不能多態調用 */ public class LinkedListDemo { public static void main(String[] args) { function_3(); } /* * E removeFirst() 移除並返回鏈表的開頭 * E removeLast() 移除並返回鏈表的結尾 */ public static void function_3(){ LinkedList<String> link = new LinkedList<String>(); link.add("1"); link.add("2"); link.add("3"); link.add("4"); String first = link.removeFirst(); String last = link.removeLast(); System.out.println(first); System.out.println(last); System.out.println(link); } /* * E getFirst() 獲取鏈表的開頭 * E getLast() 獲取鏈表的結尾 */ public static void function_2(){ LinkedList<String> link = new LinkedList<String>(); link.add("1"); link.add("2"); link.add("3"); link.add("4"); if(!link.isEmpty()){ String first = link.getFirst(); String last = link.getLast(); System.out.println(first); System.out.println(last); } } public static void function_1(){ LinkedList<String> link = new LinkedList<String>(); link.addLast("a"); link.addLast("b"); link.addLast("c"); link.addLast("d"); link.addFirst("1"); link.addFirst("2"); link.addFirst("3"); System.out.println(link); } /* * addFirst(E) 添加到鏈表的開頭 * addLast(E) 添加到鏈表的結尾 */ public static void function(){ LinkedList<String> link = new LinkedList<String>(); link.addLast("heima"); link.add("abc"); link.add("bcd"); link.addFirst("itcast"); System.out.println(link); } }
*A:Vector類的特色this
Vector集合數據存儲的結構是數組結構,爲JDK中最先提供的集合,它是線程同步的 Vector中提供了一個獨特的取出方式,就是枚舉Enumeration,它其實就是早期的迭代器。 此接口Enumeration的功能與 Iterator 接口的功能是相似的。 Vector集合已被ArrayList替代。枚舉Enumeration已被迭代器Iterator替代。
A:Set接口的特色
a:它是個不包含重複元素的集合。
b:Set集合取出元素的方式能夠採用:迭代器、加強for。
c:Set集合有多個子類,這裏咱們介紹其中的HashSet、LinkedHashSet這兩個集合。線程
A:Set集合存儲和迭代
/* * Set接口,特色不重複元素,沒索引 * * Set接口的實現類,HashSet (哈希表) * 特色: 無序集合,存儲和取出的順序不一樣,沒有索引,不存儲重複元素 * 代碼的編寫上,和ArrayList徹底一致 */ public class HashSetDemo { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("cn"); set.add("heima"); set.add("java"); set.add("java"); set.add("itcast"); Iterator<String> it = set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("=============="); for(String s : set){ System.out.println(s); } } }
A:哈希表的數據結構:(參見圖解)
加載因子:表中填入的記錄數/哈希表的長度 例如: 加載因子是0.75 表明: 數組中的16個位置,其中存入16*0.75=12個元素 若是在存入第十三個(>12)元素,致使存儲鏈子過長,會下降哈希表的性能, 那麼此時會擴充哈希表(在哈希),底層會開闢一個長度爲原長度2倍的數組,把老元素拷貝到新 數組中,再把新元素添加數組中 當存入元素數量>哈希表長度*加載因子,就要擴容,所以加載因子決定擴容時機
A:字符串對象的哈希值 /* * 對象的哈希值,普通的十進制整數 * 父類Object,方法 public int hashCode() 計算結果int整數 */ public class HashDemo { public static void main(String[] args) { Person p = new Person(); int i = p.hashCode(); System.out.println(i); String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); /*System.out.println("重地".hashCode()); System.out.println("通話".hashCode());*/ } } //String類重寫hashCode()方法 //字符串都會存儲在底層的value數組中{'a','b','c'} public int hashCode() { int h = hash;//hash初值爲0 if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
A:哈希表的存儲過程
public static void main(String[] args) { HashSet<String> set = new HashSet<String>(); set.add(new String("abc")); set.add(new String("abc")); set.add(new String("bbc")); set.add(new String("bbc")); System.out.println(set); }
存取原理:
每存入一個新的元素都要走如下三步: 1.首先調用本類的hashCode()方法算出哈希值 2.在容器中找是否與新元素哈希值相同的老元素, 若是沒有直接存入 若是有轉到第三步 3.新元素會與該索引位置下的老元素利用equals方法一一對比 一旦新元素.equals(老元素)返回true,中止對比,說明重複,再也不存入 若是與該索引位置下的老元素都經過equals方法對比返回false,說明沒有重複,存入
A:哈希表的存儲自定義對象
/* * HashSet集合的自身特色: * 底層數據結構,哈希表 * 存儲,取出都比較快 * 線程不安全,運行速度快 */ public class HashSetDemo1 { public static void main(String[] args) { //將Person對象中的姓名,年齡,相同數據,看做同一個對象 //判斷對象是否重複,依賴對象本身的方法 hashCode,equals HashSet<Person> setPerson = new HashSet<Person>(); setPerson.add(new Person("a",11)); setPerson.add(new Person("b",10)); setPerson.add(new Person("b",10)); setPerson.add(new Person("c",25)); setPerson.add(new Person("d",19)); setPerson.add(new Person("e",17));//每一個對象的地址值都不一樣,調用Obejct類的hashCode方法返回不一樣哈希值,直接存入 System.out.println(setPerson); } } public class Person { private String name; private int 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; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person(){} public String toString(){ return name+".."+age; } }
A:自定義對象重寫hashCode和equals /* * HashSet集合的自身特色: * 底層數據結構,哈希表 * 存儲,取出都比較快 * 線程不安全,運行速度快 */ public class HashSetDemo1 { public static void main(String[] args) { //將Person對象中的姓名,年齡,相同數據,看做同一個對象 //判斷對象是否重複,依賴對象本身的方法 hashCode,equals HashSet<Person> setPerson = new HashSet<Person>(); setPerson.add(new Person("a",11)); setPerson.add(new Person("b",10)); setPerson.add(new Person("b",10)); setPerson.add(new Person("c",25)); setPerson.add(new Person("d",19)); setPerson.add(new Person("e",17)); System.out.println(setPerson); } } public class Person { private String name; private int age; /* * 沒有作重寫父類,每次運行結果都是不一樣整數 * 若是子類重寫父類的方法,哈希值,自定義的 * 存儲到HashSet集合的依據 * * 儘量讓不一樣的屬性值產生不一樣的哈希值,這樣就不用再調用equals方法去比較屬性 * */ public int hashCode(){ return name.hashCode()+age*55; } //方法equals重寫父類,保證和父類相同 //public boolean equals(Object obj){} public boolean equals(Object obj){ if(this == obj) return true; if(obj == null) return false; if(obj instanceof Person){ Person p = (Person)obj; return name.equals(p.name) && age==p.age; } return false; } 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; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person(){} public String toString(){ return name+".."+age; } }
A:LinkedHashSet集合 /* * LinkedHashSet 基於鏈表的哈希表實現 * 繼承自HashSet * * LinkedHashSet 自身特性,具備順序,存儲和取出的順序相同的 * 線程不安全的集合,運行速度塊 */ public class LinkedHashSetDemo { public static void main(String[] args) { LinkedHashSet<Integer> link = new LinkedHashSet<Integer>(); link.add(123); link.add(44); link.add(33); link.add(33); link.add(66); link.add(11); System.out.println(link); } }
A:ArrayList,HashSet判斷對象是否重複的緣由
a:ArrayList的contains方法原理:底層依賴於equals方法 ArrayList的contains方法會使用調用方法時, 傳入的元素的equals方法依次與集合中的舊元素所比較, 從而根據返回的布爾值判斷是否有重複元素。 此時,當ArrayList存放自定義類型時,因爲自定義類型在未重寫equals方法前, 判斷是否重複的依據是地址值,因此若是想根據內容判斷是否爲重複元素,須要重寫元素的equals方法。 b:HashSet的add()方法和contains方法()底層都依賴 hashCode()方法與equals方法() Set集合不能存放重複元素,其添加方法在添加時會判斷是否有重複元素,有重複不添加,沒重複則添加。 HashSet集合因爲是無序的,其判斷惟一的依據是元素類型的hashCode與equals方法的返回結果。規則以下: 先判斷新元素與集合內已經有的舊元素的HashCode值 若是不一樣,說明是不一樣元素,添加到集合。 若是相同,再判斷equals比較結果。返回true則相同元素;返回false則不一樣元素,添加到集合。 因此,使用HashSet存儲自定義類型,若是沒有重寫該類的hashCode與equals方法,則判斷重複時,使用的是地址值,若是想經過內容比較元素是否相同,須要重寫該元素類的hashcode與equals方法。
A:hashCode和equals的面試題 /* * 兩個對象 Person p1 p2 * 問題: 若是兩個對象的哈希值相同 p1.hashCode()==p2.hashCode() * 兩個對象的equals必定返回true嗎 p1.equals(p2) 必定是true嗎 * 正確答案:不必定 * * 若是兩個對象的equals方法返回true,p1.equals(p2)==true * 兩個對象的哈希值必定相同嗎 * 正確答案: 必定 */ 在 Java 應用程序執行期間, 1.若是根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每一個對象調用 hashCode 方法都必須生成相同的整數結果。 2.若是根據 equals(java.lang.Object) 方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不 要求必定生成不一樣的整數結果。 兩個對象不一樣(對象屬性值不一樣) equals返回false=====>兩個對象調用hashCode()方法哈希值相同 兩個對象調用hashCode()方法哈希值不一樣=====>equals返回true 兩個對象不一樣(對象屬性值不一樣) equals返回false=====>兩個對象調用hashCode()方法哈希值不一樣 兩個對象調用hashCode()方法哈希值相同=====>equals返回true 因此說兩個對象哈希值不管相同仍是不一樣,equals均可能返回true
一、分析如下需求,並用代碼實現:
(1)有以下代碼: public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("f"); list.add("b"); list.add("c"); list.add("a"); list.add("d"); } (2)利用HashSet對list集合去重(最終結果:list中沒有重複元素)
二、:本身寫出contains 方法
三、分析如下需求,並用代碼實現: (1)編寫一個泛形方法,實現指定位置數組元素的交換 (2)編寫一個泛形方法,接收一個任意數組,並反轉數組中的全部元素
4.將"goOd gooD stUdy dAy dAy up"
每一個單詞的首字母轉換成大寫其他仍是小寫字母(不準直接輸出good good study day day up 要用代碼實現)