Java學(xué)習(xí)筆記 15 - List傻铣、Set集合及哈希表的原理和存儲

本文主要內(nèi)容
1章贞、List接口
2、Set接口
3非洲、棧鸭限、隊列、數(shù)組怪蔑、列表數(shù)據(jù)的存儲結(jié)構(gòu)
4里覆、哈希表的原理和存儲

01 List接口

A:List接口的特點
a:存取順序一致
b:有索引,通過索引可以精確的操作集合中的元素
c:可存儲重復(fù)元素
d:List接口的常用子類:ArrayList缆瓣、LinkedList

B:List接口特有方法
a:增加元素方法
add(Object e):向集合末尾處喧枷,添加指定的元素
add(int index, Object e) 向集合指定索引處,添加指定的元素弓坞,原有元素依次后移

b:刪除元素刪除
remove(Object e):將指定元素對象隧甚,從集合中刪除,返回值為被刪除的元素
remove(int index):將指定索引處的元素渡冻,從集合中刪除戚扳,返回值為被刪除的元素

c:替換元素方法
E set(int index, Object E):將指定索引處的元素,替換成指定的元素族吻,返回值為替換前的元素

d:查詢元素方法
get(int index):獲取指定索引處的元素帽借,并返回該元素

C:迭代器的并發(fā)修改異常
迭代器的并發(fā)修改異常 java.util.ConcurrentModificationException
即在遍歷的過程中,使用了集合方法修改了集合的長度,致迭代器并不知道集合中的變化超歌,容易引發(fā)數(shù)據(jù)的不確定性砍艾。

D:ArrayList集合
ArrayList集合特點:底層采用的是數(shù)組結(jié)構(gòu)

 ArrayList al=new ArrayList();//創(chuàng)建了一個長度為0的Object類型數(shù)組
 al.add("abc");//底層會創(chuàng)建一個長度為10的Object數(shù)組 Object[] obj=new Object[10]
               //obj[0]="abc"
              //如果添加的元素的超過10個,底層會開辟一個1.5*10的長度的新數(shù)組
              //把原數(shù)組中的元素拷貝到新數(shù)組,再把最后一個元素添加到新數(shù)組中
 原數(shù)組:
 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

E:LinkedList集合
a、LinkedList集合特點
底層采用鏈表結(jié)構(gòu),每次查詢都要從鏈頭或鏈尾找起,查詢相對數(shù)組較慢
LinkedList的索引決定是從鏈頭開始找還是從鏈尾開始找巍举。如果該元素小于元素長度一半,從鏈頭開始找起,如果大于元素長度的一半,則從鏈尾找起

b脆荷、LinkedList特有方法
E removeFirst() 移除并返回鏈表的開頭
E removeLast() 移除并返回鏈表的結(jié)尾
E getFirst() 獲取鏈表的開頭
E getLast() 獲取鏈表的結(jié)尾
addFirst(E) 添加到鏈表的開頭
addLast(E) 添加到鏈表的結(jié)尾

F:Vector類的特點
Vector集合數(shù)據(jù)存儲的結(jié)構(gòu)是數(shù)組結(jié)構(gòu),為JDK中最早提供的集合,是線程同步的
Vector中提供了一個獨特的取出方式:枚舉Enumeration,它是早期的迭代器(與 Iterator 接口的功能是類似的)蜓谋。
Vector集合已被ArrayList替代梦皮。枚舉Enumeration已被迭代器Iterator替代。

02 Set接口

A:Set接口的特點
a:不包含重復(fù)元素,無索引
b:Set集合取出元素的方式可以采用:迭代器桃焕、增強for剑肯。
c:Set集合有多個子類,常用的有HashSet覆旭、LinkedHashSet退子。
d:Set接口的實現(xiàn)類,HashSet (哈希表):無序集合,存儲和取出的順序不同,沒有索引,不存儲重復(fù)元素

B:LinkedHashSet集合特點
inkedHashSet 基于鏈表的哈希表實現(xiàn),繼承自HashSet
LinkedHashSet 自身特性,具有順序,存儲和取出的順序相同的
線程不安全的集合,運行速度塊

C:ArrayList,HashSet判斷對象是否重復(fù)的原因

a:ArrayList的contains方法原理:底層依賴于equals方法
ArrayList的contains方法會使用調(diào)用方法時型将,
傳入的元素的equals方法依次與集合中的舊元素所比較,
從而根據(jù)返回的布爾值判斷是否有重復(fù)元素荐虐。
此時七兜,當(dāng)ArrayList存放自定義類型時,由于自定義類型在未重寫equals方法前福扬,
判斷是否重復(fù)的依據(jù)是地址值腕铸,所以如果想根據(jù)內(nèi)容判斷是否為重復(fù)元素,需要重寫元素的equals方法铛碑。

b:HashSet的add()方法和contains方法()底層都依賴 hashCode()方法與equals方法()
Set集合不能存放重復(fù)元素狠裹,其添加方法在添加時會判斷是否有重復(fù)元素,有重復(fù)不添加汽烦,沒重復(fù)則添加涛菠。
HashSet集合由于是無序的,其判斷唯一的依據(jù)是元素類型的hashCode與equals方法的返回結(jié)果撇吞。規(guī)則如下:
先判斷新元素與集合內(nèi)已經(jīng)有的舊元素的HashCode值
如果不同俗冻,說明是不同元素,添加到集合牍颈。
如果相同迄薄,再判斷equals比較結(jié)果。返回true則相同元素煮岁;返回false則不同元素讥蔽,添加到集合。

所以画机,使用HashSet存儲自定義類型冶伞,如果沒有重寫該類的hashCode與equals方法,則判斷重復(fù)時色罚,使用的是地址值碰缔,如果想通過內(nèi)容比較元素是否相同,需要重寫該元素類的hashcode與equals方法戳护。

03棧金抡、隊列瀑焦、數(shù)組、列表數(shù)據(jù)的存儲結(jié)構(gòu)

a:棧結(jié)構(gòu):后進先出/先進后出(手槍彈夾)
b:隊列結(jié)構(gòu):先進先出/后進后出(銀行排隊)
c:數(shù)組結(jié)構(gòu):
查詢快:通過索引快速找到元素
增刪慢:每次增刪都需要開辟新的數(shù)組,將老數(shù)組中的元素拷貝到新數(shù)組中
開辟新數(shù)組耗費資源
d:鏈表結(jié)構(gòu)
查詢慢:每次都需要從鏈頭或者鏈尾找起
增刪快:只需要修改元素記錄的下個元素的地址值即可不需要移動大量元素

04 哈希表的存儲

A:哈希表的數(shù)據(jù)結(jié)構(gòu)
加載因子:表中填入的記錄數(shù)/哈希表的長度
例如:
加載因子是0.75 代表:
數(shù)組中的16個位置,其中存入160.75=12個元素
如果在存入第十三個(>12)元素,導(dǎo)致存儲鏈子過長,會降低哈希表的性能,那么此時會擴充哈希表(在哈希),底層會開辟一個長度為原長度2倍的數(shù)組,把老元素拷貝到新數(shù)組中,再把新元素添加數(shù)組中
當(dāng)存入元素數(shù)量>哈希表長度
加載因子,就要擴容,因此加載因子決定擴容時機

B:字符串對象重寫重寫hashCode()方法
字符串對象的哈希值為普通的十進制整數(shù)
重寫父類Object的方法:public int hashCode()

  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數(shù)組中{'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;
      }

C:哈希表的存儲過程
1.首先調(diào)用本類的hashCode()方法算出哈希值
2.在容器中找是否與新元素哈希值相同的老元素,
如果沒有直接存入
如果有轉(zhuǎn)到第三步
3.新元素會與該索引位置下的老元素利用equals方法一一對比
一旦新元素.equals(老元素)返回true,停止對比,說明重復(fù),不再存入
如果與該索引位置下的老元素都通過equals方法對比返回false,說明沒有重復(fù),存入

D:哈希表的存儲自定義對象
HashSet集合的自身特點:
底層數(shù)據(jù)結(jié)構(gòu),哈希表
存儲,取出都比較快
線程不安全,運行速度快

E:自定義對象重寫hashCode和equals

     public class HashSetDemo1 {
      public static void main(String[] args) {
        
        //將Person對象中的姓名,年齡,相同數(shù)據(jù),看作同一個對象
        //判斷對象是否重復(fù),依賴對象自己的方法 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;

      /*
       *  沒有做重寫父類,每次運行結(jié)果都是不同整數(shù)
       *  如果子類重寫父類的方法,哈希值,自定義的
       *  存儲到HashSet集合的依據(jù)
       *   
       *  盡可能讓不同的屬性值產(chǎn)生不同的哈希值,這樣就不用再調(diào)用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;
      }
     }

F:hashCode和equals方法的面試題
兩個對象 Person p1 p2

問題: 如果兩個對象的哈希值相同 p1.hashCode()==p2.hashCode()梗肝,兩個對象的equals一定返回true嗎 p1.equals(p2) 一定是true嗎
正確答案:不一定

如果兩個對象的equals方法返回true,p1.equals(p2)==true榛瓮,兩個對象的哈希值一定相同嗎
正確答案: 一定

在 Java 應(yīng)用程序執(zhí)行期間
1.如果根據(jù) equals(Object) 方法,兩個對象是相等的巫击,那么對這兩個對象中的每個對象調(diào)用 hashCode 方法都必須生成相同的整數(shù)結(jié)果禀晓。
2.如果根據(jù) equals(java.lang.Object) 方法,兩個對象不相等坝锰,那么對這兩個對象中的任一對象上調(diào)用 hashCode 方法不 要求一定生成不同的整數(shù)結(jié)果粹懒。
兩個對象不同(對象屬性值不同) equals返回false=====>兩個對象調(diào)用hashCode()方法哈希值相同
兩個對象調(diào)用hashCode()方法哈希值不同=====>equals返回true
兩個對象不同(對象屬性值不同) equals返回false=====>兩個對象調(diào)用hashCode()方法哈希值不同
兩個對象調(diào)用hashCode()方法哈希值相同=====>equals返回true
所以說兩個對象哈希值無論相同還是不同,equals都可能返回true

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市顷级,隨后出現(xiàn)的幾起案子凫乖,更是在濱河造成了極大的恐慌,老刑警劉巖弓颈,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帽芽,死亡現(xiàn)場離奇詭異,居然都是意外死亡翔冀,警方通過查閱死者的電腦和手機导街,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纤子,“玉大人搬瑰,你說我怎么就攤上這事〖聘#” “怎么了跌捆?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長象颖。 經(jīng)常有香客問我佩厚,道長,這世上最難降的妖魔是什么说订? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任抄瓦,我火速辦了婚禮,結(jié)果婚禮上陶冷,老公的妹妹穿的比我還像新娘钙姊。我一直安慰自己,他們只是感情好埂伦,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布煞额。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膊毁。 梳的紋絲不亂的頭發(fā)上胀莹,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音婚温,去河邊找鬼描焰。 笑死,一個胖子當(dāng)著我的面吹牛栅螟,可吹牛的內(nèi)容都是我干的荆秦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼力图,長吁一口氣:“原來是場噩夢啊……” “哼步绸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吃媒,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤靡努,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晓折,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡兽泄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年漓概,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片病梢。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胃珍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜓陌,到底是詐尸還是另有隱情觅彰,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布钮热,位于F島的核電站填抬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏隧期。R本人自食惡果不足惜飒责,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仆潮。 院中可真熱鬧宏蛉,春花似錦、人聲如沸性置。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗅义,卻和暖如春屏歹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芥喇。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工西采, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人继控。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓械馆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親武通。 傳聞我的和親對象是個殘疾皇子霹崎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容