首頁技術(shù)文章正文

集合的總結(jié)與常見問題解析

更新時(shí)間:2018-11-26 來源:黑馬程序員 瀏覽量:

  1、如何定義Collection?

  Collection是一個(gè)集合體系的頂層接口,此接口中的方法都是:public abstract。

  可以進(jìn)行增刪改查的操作:

  增加: -->> boolean add(Object o) 一次添加一個(gè)元素,元素可以是Object 的子類,返回true

  boolean addAll(Collection c) 一次添加一批元素,參數(shù)是Collection類型的

  刪除: -->> void clear() 清空集合

  boolean remove(Object o) 一次刪除一個(gè)元素,成功刪除,返回true

  boolean removeAll(Collection c) 一次刪除一批,成功,返回true

  查找: -->> boolean contains(Obejct o) 判斷集合中是否包含指定元素

  boolean containsAll(Collection c) 是否包含一批

  boolean isEmpty() 判斷集合是否為空

  int size() 獲取集合中的個(gè)數(shù)

  修改: -->> clear() 清空集合中的所有元素

  獲?。?-->> int size() 返回集合容器的大小

  集合轉(zhuǎn)換為數(shù)組:

  Object[] toArray(); 該方法將集合轉(zhuǎn)為數(shù)組,集合中的每一個(gè)元素,作為了數(shù)組一個(gè)的元素

  【注意:集合中存儲(chǔ)的是對(duì)象的引用,而不是對(duì)象本身】

  【注意:接口與接口之間屬于:繼承關(guān)系】

  2、錄入用戶在控制臺(tái)輸入的信息,可以使用Scanner類

  Scanner sc = new Scanner();

  3、List接口: ---->> public interface List extends Collection

  List是一個(gè)繼承了Collection接口的接口,具備了比Collection多的功能。

  特點(diǎn): ---->> 有序、有角標(biāo)、可重復(fù)。

  此接口的用戶可以對(duì)List接口中每個(gè)元素的插入位置進(jìn)行精確地控制。(通過角標(biāo)獲取集合中的元素)

  增:

  void add(int index,Object element) 指定元素添加的角標(biāo),增加一個(gè)元素

  boolean addAll(int index,Collection c) 指定位置,增加一批

  刪:

  Element remove(int index) 刪除指定位置的元素,并且返回該元素

  改:

  Element set(int index,Object element) 替換指定位置的元素,需要確定該元素的位置和新元素,返回就元素。

  ListsubList(int fromIndex,int toIndex) 截取子結(jié)合,返回一個(gè)List,包含頭,不包含尾。

  查:

  Object get(int index) 獲取List結(jié)合指定位置的元素

  int indexOf(Object o) 返回此列表中第一次出現(xiàn)的指定元素的索引

  int lastIndexOf(Object o) 倒序查找指定元素的位置

  【注意角標(biāo)越界:IndexOutOfBoundException // 找不到返回:-1】

  【Object set = new list.get(list.size()-1);】

  【List集合特有的增刪改查方法都跟角標(biāo)有關(guān)系!!!!】

  【問:如何取出List集合中的元素?】

  通過for循環(huán),并使用size()和set()方法可取出List集合中的每一個(gè)元素。

  4、ArrayList -->> 是一個(gè)List接口的實(shí)現(xiàn)類

  具備List集合的特點(diǎn):有序、有角標(biāo)、可重復(fù)。

  該類內(nèi)部,維護(hù)了一個(gè)數(shù)組, 數(shù)組的元素是Object 類.

  在ArrayList 類的構(gòu)造函數(shù)中初始化的該數(shù)組, 如果沒有顯示的指定數(shù)組的長(zhǎng)度,【默認(rèn)長(zhǎng)度是10】

  也就是說: 使用無參數(shù)構(gòu)造,new ArraList(), 自動(dòng)創(chuàng)建的數(shù)組長(zhǎng)度是60%.

  ArrayList 在添加元素時(shí),都會(huì)檢測(cè)數(shù)組是否已滿,如果滿了,自動(dòng)擴(kuò)容(創(chuàng)建一個(gè)新數(shù)組),

  【新數(shù)組長(zhǎng)度的是老數(shù)組的1.6倍】

  并且將老數(shù)組中的元素拷貝到了新數(shù)組,使用新數(shù)組繼續(xù)增加元素.

  5、ArrayList使用什么實(shí)現(xiàn)的?其優(yōu)缺點(diǎn)是什么?

  ArrayList是使用數(shù)組實(shí)現(xiàn)的。

  優(yōu)點(diǎn):內(nèi)存地址連續(xù),查找快;

  缺點(diǎn):增加和刪除元素,需要設(shè)計(jì)數(shù)組的擴(kuò)容或者拷貝,效率很低。

  ---->> 總結(jié): 數(shù)組實(shí)現(xiàn),查找快,增刪慢。

  ArrayList中的方法:

  boolean contains(Object o) 判斷集合是否包含指定的元素,涉及了元素的比較(對(duì)象的比較)

  內(nèi)部使用了元素的equals()方法。

  String類 重寫了equals()方法

  6、LinkedList ---->> List接口的實(shí)現(xiàn)類,具備:有序、有角標(biāo)、元素可重復(fù)的特點(diǎn)?!竞虯rrayList類似】

  LinkedList是一個(gè)雙向鏈表,該集合提供了方便操作集合頭和集合尾的方法。

  【如果集合中沒有元素可以獲取或者刪除,則拋:NoSuchElementException】

  LinkedList特有的方法:

  增加:

  void addFirst(Element e)

  void addLast(Element e)

  刪除:

  Object getFirst()

  Object getLast()

  查找:

  Object removeFirst() 移除并返回此列表的第一個(gè)元素

  Object removeLast() 移除并返回此列表的最后一個(gè)元素

  數(shù)據(jù)結(jié)構(gòu):

  堆棧:

  void push(Element e) 將元素推入此列表所表示的堆棧

  Element pop() 從此列表所表示的堆棧處彈出一個(gè)元素

  【壓棧和彈棧:先進(jìn)后出,后進(jìn)先出】

  隊(duì)列:

  boolean offer(Element e) 將指定元素添加到此列表的末尾(最后一個(gè)元素)

  Element poll() 獲取并移除此列表的頭(第一個(gè)元素)

  Element peek() 獲取但不移除列表的頭(第一個(gè)元素)

  【隊(duì)列的數(shù)據(jù)結(jié)構(gòu):先進(jìn)先出】

  返回逆序的迭代器對(duì)象:

  descendingIterator() 返回逆序的迭代器對(duì)象

  7、LinkedList的實(shí)現(xiàn)原理是什么?其優(yōu)缺點(diǎn)?

  LinkedList的實(shí)現(xiàn)原理是:鏈表實(shí)現(xiàn),其內(nèi)存地址是不連續(xù)的。

  優(yōu)點(diǎn):相對(duì)于數(shù)組,增加元素快;

  缺點(diǎn);由于內(nèi)存地址不連續(xù),查找性能低。

  8、集合與數(shù)組有什么區(qū)別?

  相同點(diǎn):數(shù)組和集合都是容器

  數(shù)組和集合中存放的都是【對(duì)象的引用】而非對(duì)象本身

  不同點(diǎn):數(shù)組存儲(chǔ)【基本數(shù)據(jù)類型】,是單一的。而且一旦聲明好長(zhǎng)度后,長(zhǎng)度不可變;

  集合【只能】?jī)?chǔ)存【對(duì)象】,但是可以是任意類型的對(duì)象,其長(zhǎng)度可變。

  【集合的分類】

  ----|Iterable:接口

  Iterator iterator()

  ----|Collection:?jiǎn)瘟屑?/p>

  ----|List: 有序存儲(chǔ)順序,可重復(fù)

  ----|ArrayList: 數(shù)組實(shí)現(xiàn),查找快、增刪慢

  由于是數(shù)組實(shí)現(xiàn),在增和刪的時(shí)候會(huì)牽扯到數(shù)組增容,以及拷貝元素,所以慢;

  數(shù)組是可以直接按索引查找的,所以查找時(shí)比較快。

  ----|LinkedList: 鏈表實(shí)現(xiàn),增刪快、查找慢

  由于鏈表實(shí)現(xiàn),增加時(shí)只要讓前一個(gè)元素記住自己就可以了,刪除時(shí)讓前一個(gè)元

  素記住后一個(gè)元素,后一個(gè)元素記住前一個(gè)元素,這樣的增刪效率高;

  但查詢時(shí)需要一個(gè)一個(gè)的遍歷,所以效率比較低。

  ----|Vector: 多線程安全、效率略低 【ArrayList單線程效率高,但是多線程要使用Vector】

  ----|set: 無序存儲(chǔ),不可重復(fù)

  ----|HashSet 線程不安全,存取速度快

  底層是以hash表實(shí)現(xiàn)的

  ----|TreeSet 紅-黑樹的數(shù)據(jù)結(jié)構(gòu),默認(rèn)對(duì)元素進(jìn)行自然排序(String)

  【TreeSet自身具備排序功能】

  ----|Comparable

  ----|compareTo(Object o) 元素自身具備比較性

  ----|Comparator

  ----|compare(Object o1,Object o2) 給容器傳入比較器

  如果在比較的時(shí)候兩個(gè)對(duì)象返回值是【0】,那么這兩個(gè)元素【重復(fù)】

  【當(dāng)Comparable和Comparator比較方式同時(shí)存在時(shí),以Comparator比較方式為主】

  ----|LinkedHashSet 會(huì)保存插入的順序

  ----|Map: 將鍵映射到值的對(duì)象。一個(gè)映射不能包含重復(fù)的鍵,每個(gè)鍵最多只能映射一個(gè)值。

  interface Map

  ----|TreeMap 底層是二叉樹數(shù)據(jù)結(jié)構(gòu),可以對(duì)map集合中的鍵進(jìn)行排序

  需要使用Comparable或者Comparator進(jìn)行比較排序。

  【return 0 判斷鍵的唯一性】

  ----|HashTable 底層是哈希表數(shù)據(jù)結(jié)構(gòu),線程是【同步】的 -->> 不可以存入null鍵、null值

  效率較低,故被【HashMap】替代

  ----|HashMap 采用哈希表實(shí)現(xiàn) -->> 【無序】

  底層是哈希表數(shù)據(jù)結(jié)構(gòu),線程是【不同步】的 -->> 可以存入null鍵、null值

  【要保證鍵的唯一性,需要覆蓋hashCode()方法和equals()方法】

  ----|LinkedHashMap

  【常用方法:】

  添加: V put(K key,V value) 可以是相同的key值,但是添加的value值會(huì)覆蓋前面的

  putAll(Map m)

  從指定映射中將所有映射關(guān)系復(fù)制到此映射中(可選操作)

  刪除: remove(Object key) 刪除關(guān)聯(lián)對(duì)象,指定key對(duì)象

  clear() 清空集合對(duì)象

  獲取: value get(Object key) 可以用于判斷鍵是否存在的情況。

  判斷: boolean isEmpty() 如果此映射不包含鍵-值映射關(guān)系【即長(zhǎng)度為0】,則返回true,否則返回false

  boolean containsKey(Object key)

  判斷集合中是否包含指定的key

  boolean containsValue(Object value)

  判斷集合中是否包含指定的value

  當(dāng)指定的鍵不存在的時(shí)候,返回的是null

  長(zhǎng)度: int size() 返回此映射中的鍵-值映射關(guān)系數(shù)

  9、在什么時(shí)候該使用什么樣的集合?

  Collection 當(dāng)我們需要保存若干個(gè)對(duì)象的時(shí)候使用集合

  -->> List 如果需要保留存儲(chǔ)順序、并且重復(fù)元素時(shí),使用List

  -->> 如果查詢較多,使用ArrayList;

  如果存取較多,使用LinkedList;

  如果需要線程安全,使用Vector。

  -->> Set 如果不需要保留存儲(chǔ)順序,并且要去掉重復(fù)元素時(shí),使用Set

  -->> 如果需要將元素排序,使用TreeSet;

  如果不需要排序,使用HashSet 【HashSet比TreeSet效率高】

  如果需要保留存儲(chǔ)順序,同時(shí)要過濾重復(fù)元素,使用LinkedHashSet。

  10、自定義對(duì)象時(shí)為什么要重寫toString()和equals()方法?

  因?yàn)镺bject是自定義類的父類,Object類中的toString()方法返回的是哈希值;

  Object類中的equals()方法比較的是對(duì)象的地址值。

  【去除集合中重復(fù)的元素】

  代碼如下:

  public class Demo{

  public static void main(String[] args){

  ArrayList arr = new ArrayList();

  Person p1 = new Person("jack",20);

  Person p2 = new Person("rose",18);

  Person p3 = new Person("rose",18);

  arr.add(p1);

  arr.add(p2);

  arr.add(p3);

  System.out.println(arr);

  ArrayList arr2 = new ArrayList();

  for(int i=0;i<arr.size();i++){< p="">

  Object obj = arr.get(i);

  Person p = (Person)obj;

  if(!arr2.contains(p)){

  arr2.add(p);

  }

  }

  System.out.println(arr2);

  }

  }

  class Person{

  private String name;

  private int age;

  public Person(){

  }

  public Person(String name,int age){

  this.name = name;

  this.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;

  }

  public int hashcode(){

  return this.name.hashCode() + age*37;

  }

  public boolean equals(Object obj){

  if(!(obj instanceof Person)){

  return false;

  }

  Person p = (Person)obj;

  return this.name.equals(p.name) && this.age = p.age;

  }

  public String toString(){

  return "name:" + this.name + "age:" + this.age;

  }

  }

  11、Vector: 多線程安全、但是效率低 ---->> 描述的是一個(gè)線程安全的ArrayList。

  特有的方法:

  void addElement(E obj) 在集合末尾添加元素

  E elementAt(int index) 返回指定角標(biāo)的元素

  Enumeration element() 返回集合中的所有元素,封裝到Enumeration對(duì)象中

  Enumeration接口:

  boolean hasMoreElements() 測(cè)試此枚舉是否包含更多的元素

  E nextElement() 如果此枚舉對(duì)象至少還有一個(gè)可提供的元素,則返回此枚舉的下一個(gè)元素

  【代碼如下:】

  public static void main(String[] args){

  Vector v = new Vector();

  v.addElement("aaa");

  v.addElement("bbb");

  v.addElement("ccc");

  // System.out.println(v.elementAt(2));

  Enumeration ens = v.elements();

  while(ens.hasMorreElements()){

  System.out.println(ens.nextElement());

  }

  }

  12、Iterable: 是Collection的父接口,實(shí)現(xiàn)Iterable的類可以進(jìn)行迭代,并且支持增強(qiáng)for循環(huán)

  該接口只有一個(gè)方法,用于返回集合迭代器對(duì)象! 【獲取迭代器的方法iterator()】

  piblic interface Iterable

  Iteratoriterator():該類主要用于遍歷集合對(duì)象,并描述了遍歷集合的常見方法

  boolean hasNext() 判斷集合中是否有元素,如果有元素可以迭代,就返回true。

  E next() 返回迭代的下一個(gè)元素。

  如果沒有下一個(gè)元素,調(diào)用next()會(huì)拋出 -->> NoSuchElementException

  void remove() 從迭代器指向的集合中移除迭代器返回的最后一個(gè)元素

  【Iterator的for循環(huán)、清空】

  public class Demo{

  ArrayList list = new ArrayList();

  // 增加:add() 將指定對(duì)象存儲(chǔ)到容器中

  list.add("計(jì)算機(jī)網(wǎng)絡(luò)");

  list.add("現(xiàn)代操作系統(tǒng)");

  list.add("java編程思想");

  list.add("java核心技術(shù)");

  list.add("java語言程序設(shè)計(jì)");

  System.out.println(list);

  for(Iterator it = list.iterator();it.hasNext();){

  // 迭代器的next()方法返回值類型是Object,所有要記得【類型強(qiáng)轉(zhuǎn)】

  String next = (String)it.next();

  System.out.println(next);

  it.remove();

  }

  }

  【細(xì)節(jié)一:如果迭代器的指針已經(jīng)指向了集合的末尾,那么如果再調(diào)用next()會(huì)返回NoSuchElementException異常】

  【細(xì)節(jié)二:如果調(diào)用remove()之前沒有調(diào)用next()方法是不合法的,會(huì)拋出IllegalStateException異常】

  【細(xì)節(jié)三:當(dāng)一個(gè)集合在循環(huán)中即使用引用變量操作集合,又使用迭代器操作集合對(duì)象,會(huì)拋出ConcurrentModificationException異?!?/p>

  13、為什么next()方法的返回值類型是Object呢?

  為了可以接收任意類型的對(duì)象

  如果返回的時(shí)候不知道是什么類型的,就定義為object

  14、Iterator和ListIterator有什么關(guān)系?

  ListIterator是Iterator的子接口,是List集合特有的迭代器。

  Iterator在迭代時(shí),只能對(duì)元素進(jìn)行獲取【next()】和刪除【remove()】的操作;

  ListIterator在迭代list集合時(shí),還可以對(duì)元素進(jìn)行添加【add(obj)】和修改【set(obj)】的操作。

  15、List集合特有的迭代器ListIterator

  ---->> public interface ListIterator extends Iterator

  ListIteratorlistIteraotr()

  ----| Iterator

  hasNext()

  next()

  remove()

  ----| ListIterator

  add(E e) 將指定的元素插入列表(可選操作)。

  該元素直接插入到next()返回的下一個(gè)元素的前面(如果有)

  void set(E o) 用指定的元素替換next()或previous()返回的 【最后】 一個(gè)元素

  hasPrevious() 逆向遍歷列表,列表迭代器有多個(gè)元素,則返回true

  previous() 返回列表中的前一個(gè)元素

  16、HashSet是如何判斷兩個(gè)元素重復(fù)的?

  通過hashCode()方法和equals()方法來保證元素的唯一性,add()方法返回的是boolean類型

  【調(diào)用原理:HashSet集合在判斷元素是否相同,先判斷hashCode()方法,相同才會(huì)判斷equals()方法;不相同不會(huì)調(diào)用equals()】

  17、HashSet和ArrayList集合在判斷元素時(shí)是否有相同的方法?

  有:boolean contains(Object o)

  HashSet使用hashCode()和equals()方法,ArrayList使用eqauls()方法。

  18、給TreeSet指定排序規(guī)則:

  方式一:【元素自身】具備比較性

  元素自身具備比較性,需要元素實(shí)現(xiàn)【Comparable接口】,重寫【compareTo方法】,

  也就是讓元素自身具備比較性,這種方式叫做元素的【自然排序】也叫做【默認(rèn)排序】。

  方式二:【容器】具備比較性

  當(dāng)元素自身不具備比較性,或者自身具備的比較性不是所需要的。

  那么此時(shí)可以讓容器自身具備。需要定義一個(gè)類實(shí)現(xiàn)【Comparator接口】,重寫【compare方法】,

  并將該接口的子類實(shí)例對(duì)象作為參數(shù)傳遞給【TreeSet集合】的【構(gòu)造方法】。

  注意:當(dāng)Comparable比較方式和Comparator比較方式同時(shí)存在時(shí),以【Comparator】的比較方式為主;

  注意:在重寫compareTo或者compare方法時(shí),必須要明確比較的主要條件相等時(shí)要比較次要條件。

  通過return 0 來判斷唯一性。

  19、為什么使用TreeSet存入字符串,字符串默認(rèn)輸出是按升序排列的?

  因?yàn)樽址畬?shí)現(xiàn)了一個(gè)接口,叫做【Comparable接口】,字符串重寫了該接口的【compareTo()方法】,

  所以String對(duì)象具備了比較性。

  【自定義的元素(比如Person類、Book類)想要存入TreeSet集合,就必須實(shí)現(xiàn)Comparable接口,也就是要讓自定義對(duì)象具備比較性】

  【存入TreeSet集合的元素都要具備比較性:要實(shí)現(xiàn)Comparable接口、并重寫該接口的compareTo()方法】

  20、總結(jié):

  看到array,就要想到角標(biāo)。

  看到link, 就要想到first,last。

  看到hash, 就要想到hashCode,equals.

  看到tree, 就要想到兩個(gè)接口。Comparable,Comparator。

  21、TreeSet是如何保證元素的唯一性的?

  通過【compareTo】或者【compare】方法來保證元素的唯一性。

  當(dāng)Comparable接口中的compareTo()函數(shù)返回值為【0】時(shí),說明兩個(gè)對(duì)象相等,此時(shí)該對(duì)象不會(huì)被添加進(jìn)來。

  22、使用TreeSet集合將字符串 String str = "8 10 15 5 2 7"; 的數(shù)值進(jìn)行排序。

  public class Demo{

  public static void main(String[] args){

  String str = "8 10 15 5 2 7";

  String strs = str.split(" ");

  TreeSet ts = new TreeSet();

  for(int x= 0;x<strs.length();x++){< p="">

  int y = Integer.parseInt(strs[x]);

  ts.add(y);

  }

  System.out.println(ts);

  }

  }

  23、遍歷Map集合的方式有哪些?

  方式一:使用keySet

  將Map轉(zhuǎn)成Set集合【keySet()】,通過Set的迭代器【Iterator】取出Set集合中的每一個(gè)元素,

  即Map集合中所有的鍵,再通過get()方法獲取鍵對(duì)應(yīng)的值

  Setks = map.keySet();

  Iteratorit = ks.iterator();

  while(it.hasNext()){

  Integer key = it.next();

  String value = map.get(key);

  }

  方式二:通過values獲取所有值,但是不能獲取到key對(duì)象

  Collectionvs = map.values();

  Iteratorit = vs.iterator();

  while(it.hasNext()){

  String value = it.next();

  }

  方式三:Map.Entry -->> public static interface Map.Entry

  通過Map中的entrySet()方法獲取存放Map.Entry對(duì)象的Set集合 -->> Set<map.entry> entrySet()

  Set<map.entry> entrySet = map.entrySet();

  Iterator<map.entry> it = entrySet.iterator();

  while(it.hasNext()){

  Map.Entryen = it.next();

  }

  Integer key = en.getKey();

  String value = en.getValue();



作者:黑馬程序員JavaEE培訓(xùn)學(xué)院

首發(fā): http://java.itheima.com

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!