1. 程式人生 > >Java HashSet特點:不重複(物件的雜湊程式碼一樣)、無序

Java HashSet特點:不重複(物件的雜湊程式碼一樣)、無序

HashSet 簡介

HashSet 是一個沒有重複元素的集合。 它是由HashMap實現的(HashSet中大量呼叫了HashMap的方法,其內部封裝了一個HashMap ),不保證元素的順序,而且HashSet允許使用 null 元素。

HashSet是非同步的。如果多個執行緒同時訪問一個雜湊 set,而其中至少一個執行緒修改了該 set,那麼它必須 保持外部同步。這通常是通過對自然封裝該 set 的物件執行同步操作來完成的。如果不存在這樣的物件,則應該使用 Collections.synchronizedSet 方法來“包裝” set。最好在建立時完成這一操作,以防止對該 set 進行意外的不同步訪問:
Set s = Collections.synchronizedSet(new HashSet(…));

HashSet通過iterator()返回的迭代器是fail-fast的。

說說Set:

Set:元素是無序(存入和取出的順序不一定一致),元素不可以重複,因為該集合體系沒有索引。Set集合的功能Collection是一致的,取出只有一種方式 就是迭代器

  • HashSet:底層資料結構是雜湊表,執行緒是非同步的(有個子類可以實現有序,LinkedHashSet(連結串列結構和has結構相結合))
  • TreeSet:可以對Set集合中的元素進行排序(自然排序,由小到大) 底層的資料結構是二叉樹,執行緒不同步

HashSet遍歷方式

  1. 通過Iterator遍歷HashSet
    第一步:根據iterator()獲取HashSet的迭代器。
    第二步:遍歷迭代器獲取各個元素。

  2. 通過for-each遍歷HashSet
    第一步:根據toArray()獲取HashSet的元素集合對應的陣列。
    第二步:遍歷陣列,獲取各個元素。

HashSet的遍歷測試程式如下:

import java.util.Random;
import java.util.Iterator;
import java.util.HashSet;

/*
 * @desc 介紹HashSet遍歷方法
 *
 */
public class HashSetIteratorTest {

    public static void main(String[] args) {
        // 新建HashSet
HashSet set = new HashSet(); // 新增元素 到HashSet中 for (int i=0; i<5; i++) set.add(""+i); // 通過Iterator遍歷HashSet iteratorHashSet(set) ; // 通過for-each遍歷HashSet foreachHashSet(set); } /* * 通過Iterator遍歷HashSet。推薦方式 */ private static void iteratorHashSet(HashSet set) { for(Iterator iterator = set.iterator(); iterator.hasNext(); ) { System.out.printf("iterator : %s\n", iterator.next()); } } /* * 通過for-each遍歷HashSet。不推薦!此方法需要先將Set轉換為陣列 */ private static void foreachHashSet(HashSet set) { String[] arr = (String[])set.toArray(new String[0]); for (String str:arr) System.out.printf("for each : %s\n", str); } }

HashSet示例

下面我們通過例項學習如何使用HashSet

package com.qq.main;

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

public class HashSetTest {

    public static void main(String[] args) {
        testHashSetAPIs() ;
    }

    /*
     * HashSet除了iterator()和add()之外的其它常用API
     */
    private static void testHashSetAPIs() {
        // 新建HashSet
        HashSet set = new HashSet();

        // 將元素新增到Setset.add("a");
        set.add("b");
        set.add("c");
        set.add("d");
        set.add("e");

        // 列印HashSet的實際大小
        System.out.printf("size : %d\n", set.size());

        // 判斷HashSet是否包含某個值
        System.out.printf("HashSet contains a :%s\n", set.contains("a"));
        System.out.printf("HashSet contains g :%s\n", set.contains("g"));

        // 刪除HashSet中的“e”
        set.remove("e");

        // 將Set轉換為陣列
        String[] arr = (String[])set.toArray(new String[0]);
        for (String str:arr)
            System.out.printf("for each : %s\n", str);

        // 新建一個包含b、c、f的HashSet
        HashSet otherset = new HashSet();
        otherset.add("b");
        otherset.add("c");
        otherset.add("f");

        // 克隆一個removeset,內容和set一模一樣
        HashSet removeset = (HashSet)set.clone();
        // 刪除“removeset中,屬於otherSet的元素”
        removeset.removeAll(otherset);
        // 列印removeset
        System.out.printf("removeset : %s\n", removeset);

        // 克隆一個retainset,內容和set一模一樣
        HashSet retainset = (HashSet)set.clone();
        // 保留“retainset中,屬於otherSet的元素”
        retainset.retainAll(otherset);
        // 列印retainset
        System.out.printf("retainset : %s\n", retainset);


        // 遍歷HashSet
        for(Iterator iterator = set.iterator();
               iterator.hasNext(); ) 
            System.out.printf("iterator : %s\n", iterator.next());

        // 清空HashSet
        set.clear();

        // 輸出HashSet是否為空
        System.out.printf("%s\n", set.isEmpty()?"set is empty":"set is not empty");
    }

}

執行輸出結果如下:

size : 5
HashSet contains a :true
HashSet contains g :false
for each : a
for each : b
for each : c
for each : d
removeset : [a, d]
retainset : [b, c]
iterator : a
iterator : b
iterator : c
iterator : d
set is empty

技巧

hashcode和equals方法

HashSet是如何保證元素的唯一性的(判斷元素相同的依據): 是通過元素的兩個方法,hashCode和equals來完成

  -如果元素的HashCode值相同,才會判斷equals是否為true
  -如果元素的hashcode值不同,不會呼叫equals

對於判斷元素是否存在,以及刪除等操作,依賴的方法是元素的hashcode和equals方法。

往hashSet集合中存入自定義物件。如果姓名和年齡相同為同一個人,即重複元素。

import java.util.*;
public class HashSetTest{

    public static void main(String[] args) {
        HashSet hs = new HashSet();

        hs.add(new Person("a1",11));
        hs.add(new Person("a2",12));
        hs.add(new Person("a3",13));
        hs.add(new Person("a2",12));
        hs.add(new Person("a4",14));

        Iterator it = hs.iterator();
        while (it.hasNext()){
            Person p = (Person)it.next();
            System.out.println(p.getName()+"::"+p.getAge());
        }
    }
}

//以後開發中描述事物時,都要有複寫hashCode和equals方法,因為可能這個物件會儲存到HashSet集合中
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;
    }

}

執行輸出結果:

a1::11
a2::12
a4::14
a3::13
a2::12

可以看到輸出了兩次『a2::12』,是由於沒有複寫hashcode和equals方法。

複寫equals方法

package com.qq.main;

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 boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o.getClass() == Person.class) {
            Person p = (Person) o;
            return p.name.equals(name) && p.age == age;
        }
        return false;
    }
}

執行輸出結果:

a1::11
a2::12
a4::14
a3::13
a2::12

至此看樣看到只複寫equals方法是不能去除重複元素的,必須複寫hashCode方法。

在Person類中複寫hashCode方法,程式碼:

@Override
    public int hashCode() {
        //return 60;//很多重複比較,導致雜湊值都相同,要呼叫equals方法比較是不是同一個物件
        return name.hashCode()+age*27;//*27是為了保證雜湊值的唯一性,可以任何值都可以.每個字串都有自己的雜湊值
    }

也可以:

@Override
    public int hashCode() {
        return name.hashCode();
    }

複寫hashCode()的方法沒有特別要求,只要返回值唯一即可。

執行輸出結果:

a1::11
a2::12
a3::13
a4::14

記住:如果元素要儲存到HashSet集合中,必須覆蓋hashCode方法和equals方法。

一般情況下,如果定義的類會產生很多物件,比如人,學生,書,通常都需要覆蓋equals,hashCode方法。建立物件判斷是否相同的依據。

相關推薦

Java HashSet特點重複物件程式碼一樣無序

HashSet 簡介 HashSet 是一個沒有重複元素的集合。 它是由HashMap實現的(HashSet中大量呼叫了HashMap的方法,其內部封裝了一個HashMap ),不保證元素的順序,而且HashSet允許使用 null 元素。 HashSet是

本地Navicat可以連線linux上的mysql8.0.13但Java程式連線連線mysql8.0.13驅動配置

原因:mysql5.6以上版本驅動包和驅動配置變了 mysql5.6以前版本配置: db.properties配置: jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/taota

洛谷4895 獨釣寒江雪 +dp+組合

qwq 首先,如果是沒有要求本質不同的話,那麼還是比較簡單的一個樹形dp 我們令\(dp[i][0/1]\)表示是否\(i\)的子樹,是否選\(i\)這個點的方案數。 一個比較顯然的想法。 \(dp[i][0]=\prod (dp[p][0]+dp[p][1])\) \(dp[i][1]=\prod d

java輸入輸出10IO流IO流概述及其分類

1 概念 1、IO流用來處理裝置之間的資料傳輸。 2、Java對資料的操作時通過流的方式。 3、Java用於操作流的類都在IO包中。 4、流按流向分為兩種:輸入流,輸出流。 5、流按照操作型別分為兩種:(1)位元組流:位元組流可以操作任何資料,因為在計算機中任何資料都是以位元

java程式設計思想讀書筆記二物件的建立

java物件 物件的建立 java的物件是在執行時建立的,建立物件的的觸發條件有以下幾種: 用new語句建立物件,這是最常用的建立物件方法。 運用反射手段,呼叫java.lang.reflect.Constructor類的newInstance()例項方法。

“全棧2019”Java第一章安裝JDK11Mac

安裝 開發環境 ref 進步 技術分享 mac com 第一章 計劃 難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 文章原文鏈接 “全棧2019”Java第一章:安裝JDK11(Mac) 下一章 “全棧2019”Java

“全棧2019”Java第二章安裝JDK11Windows

難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 文章原文連結 “全棧2019”Java第二章:安裝JDK11(Windows) 下一章 “全棧2019”Java第三章:安裝開發工

java隨機100數字重複 ,位置隨機

import java.util.Set; import java.util.TreeSet; public class Print { public static void main(String[] args) { String str = new Strin

java學習筆記--物件程式設計-類與方法

面向過程-程式設計正規化-c-行為 面向物件-能進行現實生活的抽象 面向介面程式設計 面向切面程式設計 函數語言程式設計正規化 -Scala,Koltin //lamdba表示式 ()-> { } 面向物件三大特徵: a.封裝        將客觀事物

java輸入輸出14IO流位元組流讀寫中文

位元組流讀取中文的問題 位元組流在讀中文的時候有可能會讀到半個中文,造成亂碼。 位元組流寫出中文的問題 位元組流直接操作位元組,所以寫出中文必須將字串轉換成位元組陣列。寫出回車換行write("\r\n

java基礎教程集合概述27

今天要講的內容是集合。集合是我們程式設計時非常頻繁的物件,必須花費大量時間學習。 我們還是從是什麼和為什麼兩個角度進行引入。 集合是什麼? 集合是儲存和操作一組物件的物件。類似一個池子,可以儲存操作一組元素。 為什麼要有集合? 從集合是什麼來看,集合和我們之前提到的陣

java生成4位重複字元(包含大寫字母小寫字母數字)

需要生成4位不重複的字元作為唯一引數,要求只能使用大寫字母、小寫字母和數字的組合。大寫字母26個、小寫字母26個、10個數字共62個字元。不重複排列個數:62*62*62*62=14776336個。 /** * * @author wzp * 2016-3-18

3. Longest Substring Without Repeating Characters求最長的重複的連續的子序列。

官網 Given a string, find the length of the longest substring without repeating characters. Examples: Given “abcabcbb”, the answer

JAVA】基礎設計模式單例設計模式,工廠設計模式

設計模式:解決某一類問題最行之有效的方法。 java中有23種設計模式。 建立型模式(5種):工廠方法模式,抽象工廠模式,單例模式,建造者模式,原型模式。 結構型模式(7種):介面卡模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。 行為型模式(11種):策略模式、模板方法

Java併發包阻塞佇列BlockingQueue

BlockingQueue 在java.util.concurrent包中的 BlockingQueue介面類是一種執行緒安全的佇列。這篇文章我們將展示如何使用BlockingQueue。 這篇文章不討論BlockQueue的實現。如果你對此感興趣,有一片理論

java演算法題存在重複

題目: 給定一個整數陣列,判斷是否存在重複元素。 如果任何值在陣列中出現至少兩次,函式返回 true。如果陣列中每個元素都不相同,則返回 false。 示例 1: 輸入: [1,2,3,1] 輸出: true 示例 2: 輸入: [1,2,3,4] 輸出: false

編寫可維護程式碼4輕易修改物件方法

編寫可維護的程式碼規則第4篇。 本篇主要講下物件的屬性與方法的修改問題。由於js中修改物件的屬性和方法簡直容易至極,所以任何人都可以更改js中的具有可訪問可修改許可權的物件。這就帶來極大的風險,容易造成各種奇葩的bug問題且難以排查,更別說如果是多人協同開發的情況下,某個人改動已有方

Java 物件間的型別轉換

和標準型別資料的轉換一樣,類物件之間也可以相互轉換,!!!!前提條件是源和目的類之間必須通過繼承相聯絡。轉換可分為顯示和隱式兩種,顯示轉換格式為: (類名)物件名 它將物件轉換成類名所表示的其他物件

Java JVM 8垃圾回收GC 在什麼時候,對什麼東西,做了什麼事情

在什麼時候 首先需要知道,GC又分為 minor GC 和 Full GC (也稱為 Major GC )。Java 堆記憶體分為新生代和老年代,新生代中又分為1個 Eden 區域 和兩個 Survivor 區域。 那麼對於 Minor GC 的觸發條件:大

java算術運算子取餘取模%

本質:a % b = a - a /b * b;        int num1 = 10 % 3;//10-(10/3)*3==>10-3*3==>1int num2 = -10 % 3;//-10-((-10)/3)*3==>-10-(-3)*3==&g