1. 程式人生 > >Java學習筆記31(集合框架五:set接口、哈希表的介紹)

Java學習筆記31(集合框架五:set接口、哈希表的介紹)

ins gpo 自己 static 增強for {} ati 兩個 公式

set接口的特點:

1.不包含重復元素

2.set集合沒有索引,只能用叠代器或增強for循環遍歷

3.set的底層是map集合

方法和Collection的方法基本一樣

set接口的實現類HashSet:

1.無序集合

2.可以存入空(null)

3.不可以存在重復元素

示例:

package demo;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetDemo {
    public static void main(String[] args) {
        Set
<String> set = new HashSet<String>(); set.add("abc1"); set.add("abc1"); set.add("abc2"); set.add("abc3"); set.add("abc4"); Iterator<String> i1 = set.iterator(); while(i1.hasNext()){ System.out.println(i1.next()); } } }
/* 輸出: 註意:這裏的輸出特點是無序的 abc1 abc4 abc2 abc3 */

set底層數據結構是哈希表:

特點:存儲取出都比較快

原理:具體省略,簡單說就是鏈表數組結合體

對象的哈希值:普通的一個整數

可以理解為身份證號,是hashset存儲的依據

package demo;

public class Person {}
package demo;

public class HashDemo {
    public static void main(String[] args) {
        Person p = new Person();
        
int i = p.hashCode(); System.out.println(i); //每次運行都會輸出不同的整數,比如1191201656 String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1.hashCode());//96354 System.out.println(s2.hashCode());//96354 //這裏Stirng重寫hashcode方法,有對應的計算公式 //當字符串的內容相同時候,運算結果就相同,因此s1和s2的哈希值相同 } }

哈希表存儲過程:


1.調用對象的哈希值

2.集合在容器內搜索有沒有重復的哈希值,如果沒有,存入新元素,記錄哈希值

3.再次存儲,重復上邊的過程

4.如果有重復的哈希值,調用後來者的equals方法,參數為前來者,結果得到true,集合判斷為重復元素,不存入

相同的字符串如果存進去,哈希值相同,equals方法為true,不會存入相同的

只要哈希值相同或者equals方法為true都成立才不會存入,只要其中一條不滿足,都會儲存

哈希表存儲自定義對象:

package demo;

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 String toString() {
        return this.name + ":" + this.age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

}

package demo;

import java.util.HashSet;

public class HashDemo {
    public static void main(String[] args) {
        HashSet<Person> setPerson = new HashSet<Person>();
        setPerson.add(new Person("a",17));
        setPerson.add(new Person("b",20));
        setPerson.add(new Person("b",20));
        setPerson.add(new Person("c",18));
        System.out.println(setPerson);
        //[c:18, b:20, a:17, b:20]
        //發現存入了重復的元素
        //所以想辦法使name和age相同的Person對象視為同一個對象
        //所以需要重寫hashcode方法
    }
}

自己重寫:

package demo;

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 String toString() {
        return this.name + ":" + this.age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public int hashCode(){
        return name.hashCode()+age*66;
    }

    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;
    }
}

eclipse可以幫助我們寫:

package demo;

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 String toString() {
        return this.name + ":" + this.age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

LinkedHashSet集合:基於鏈表的哈希表實現,繼承HashSet,它具有順序

示例:

package demo;

import java.util.LinkedHashSet;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        //有序的set
        LinkedHashSet<Integer> link = new LinkedHashSet<Integer>(); 
        link.add(1);
        link.add(2);
        link.add(3);
        link.add(4);
        System.out.println(link);
        //[1, 2, 3, 4]
    }
}

關於hashcode和equals的一些問題,在面試中會問道:

1.兩個對象哈希值相同,那麽equals方法一定返回true嗎?不一定

取決於如何重寫equals,如果重寫固定了它返回false,結果就一定是false

2.equals方法返回true,那麽哈希值一定相同嗎?一定

如果類中定義一個靜態變量(static int a = 1),然後重寫hashcode返回a+1,那麽每一個對象的哈希值都不一樣

不過java中規定:對象相等,必須具有相同的哈希碼值,所以這裏是一定的

Java學習筆記31(集合框架五:set接口、哈希表的介紹)