A:List接口的特色:
a:它是一個元素存取有序的集合。java
例如,存元素的順序是十一、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:鏈表結構 查詢慢:每次都須要從鏈頭或者鏈尾找起 增刪快:只須要修改元素記錄的下個元素的地址值便可不須要移動大量元素
=======================第二節課開始=============================================this
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的長度的新數組 //把原數組中的元素拷貝到新數組,再把最後一個元素添加到新數組中
原數組:code
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類的特色
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
描述的是:集合和迭代器同時持有同一個對象,當集合在添加,和刪除集合元素時(修改呢),迭代器並不知道,因此會發生併發修改異常 注意:加強for也會產生併發修改異常 如何解決: 第一: 使用普通for循環 第二(重點):使用listIterator -->是List 特有的,其餘集合不能使用 代碼:
a、 E set(int index, E) 修改指定索引上的元素,返回被修改以前的元素 b、 E remove(int index) 移除指定索引上的元素,返回被刪除以前的元素 c、 add(int index, E)將元素插入到列表的指定索引上,其餘元素順移 d、remove(int index) 刪除並返回元素
棧 : 手槍的彈夾 : 手槍的壓棧 ---> 喝酒 --->先進後出,後進先出 隊列 : 超市的購物,先排隊,先處理 ---> 喝酒 --->先進去,先出來,後進去,後出來 數組 : 查找快:由於底層有索引,而且是連續 增刪慢: 數組的長度的是固定的,當咱們在進行增刪時,會建立一個新的數組,而且將老數組中的值拷貝到新數組中 鏈表: 查找慢(底層是鏈表,兩兩相連,依次往下找,直到找到爲止) --->linkedList 採用二分法查找 增刪快 :緣由在於他僅僅只須要改變相鄰元素的地址值
底層是可變數組查找快:由於底層有索引,而且是連續
查找慢(底層是鏈表,兩兩相連,依次往下找,直到找到爲止) Vector : 已經被淘汰,是線程安全的,效率低,其餘和arrayList 一致
我想本身實現一個棧結構:-->先進後出,後進先出