セット・インタフェース
java.util.setインタフェースは、Collectionインタフェースのメソッドと一致するコレクションインターフェース、から継承された
機能を拡張するために、ノーインタフェースコレクションが、収集インターフェースよりも厳しいです。
セットインターフェース要素が乱れており、要素の非重複を確実にするために特定のルールに入金されます。
それは簡単なことを特徴としています。
- ストレージは、要素を繰り返しません
- いいえ、インデックス、何のインデックス付きの方法は通常のループ反復するために使用することはできません
設定インターフェイスは、複数のクラス、サブクラスはjava.util.HashSetその通常で実装しました
ここではいくつかの実装クラスHashSetのセットインタフェースです
HashSetのコレクションが導入します
-
java.util.HashSetセットはインターフェースクラスの実装で、その格納された要素が繰り返し可能ではなく、(すなわち、一貫性のないアクセスシーケンス)要素が乱れています。
-
根本的な事実はjava.util.HashMapをによってサポートされている達成はjava.util.HashSet
-
HashSetの要素のセットにおけるオブジェクト格納場所のハッシュ値に基づいて決定され、従って良好なアクセスと検索性能を有しています。
-
要素を確保するための唯一の方法は、によって異なりますのhashCodeとequalsメソッドを。
コードを理解するのは簡単です
輸入はjava.util.HashSet。 インポートするjava.util.Iterator; パブリック クラスDemoHashSet { 公共 静的 ボイドメイン(文字列[]引数){ // 创建セット集合(HashSetの) HashSetの<文字列> HashSetの= 新しい HashSetの<> (); // 使用追加方法想HashSetの集合中添加元素 hashSet.add( "A" ); hashSet.add( "B" )。 hashSet.add( "C" )。 hashSet.add( "D" )。 hashSet.add( "A" )。 System.out.printlnは( "HashSetの); System.out.printlnは( "==============================" ); // 使用すると、一連の上で反復し 反復子の<string> = ITE hashSet.iterator(); 一方(ite.hasNext()){ System.out.printlnは(ite.next()); } のSystem.out.println(「======== ====================== " ); // 使用することは、コレクションを拡張forループ(循環、HashSetのコレクショントラバーサルのために使用することはできません) のために(文字列S:HashSetの){ System.out.printlnは(S); } } }
出力結果: 要素のセット:[A、B、C、D] ============================== A B C D ============================== A B C D
注:ループのための共通のHashSetの収集、格納順序要素のHashSetの矛盾セットが繰り返されていない、要素を反復処理することができます
データを格納するための構造のHashSetのセット(ハッシュ・テーブル)
ハッシュテーブルは何ですか
ハッシュ・テーブルおよびデータ構造への直接アクセス-キー値(キー値)に基づいている(また、ハッシュとして知られています)。
換言すれば、ハッシュ・テーブルは、検索を高速化するために、位置レコード(値)のテーブルにマッピングされたキー値(キー)を介してアクセスされます。このマッピング関数が呼び出されたハッシュ関数(ハッシュ関数)、レコードストレージアレイは、ハッシュテーブルと呼ばれます。
/ ** *前JDK1.8、リンクされたリストの実装+を使用して、基礎となるハッシュテーブルアレイ、すなわち競合リンクリスト、同じリストのハッシュ値は、リンクされたリストに格納されています。 *しかし、バケツでより多くの要素は、キー値を見つけるための要素、低効率のハッシュ値により等しくなるとき。 *そしてJDK1.8、メモリ使用してハッシュテーブルの配列 + チェーン +又はアレイ + 赤黒木に、鎖長が閾値(8)を超えると、達成するために、リストを大幅に検索時間を短縮赤黒木、に変換されます。 * /
リンクリストとは何ですか
リスト記憶部は、物理的に非連続、非連続の記憶構造、リンクされたリストの順にリンクポインタによって達成されるデータ要素の論理的な順序です。ノードは、実行時に動的に生成することが可能と一連のノードによってチェーンは、(各ノード要素は、リンクされたリストと呼ばれます)。各ノードは2つの部分から構成さ:データフィールドはデータ要素を格納し、他のノード・アドレス・ポインタ・フィールドの下に格納されます。
赤黒木は何ですか
赤黒木(また公知の対称バイナリBツリー)、自動平衡二分探索木は、コンピュータサイエンスで使用されるデータ構造であり、典型的な使用は、連想配列を実現します。
連想配列とは何ですか
配列のインデックスは、特別な方法です。それは唯一の整数によって索引付けすることができ、また、文字列、または値の他の種類のインデックスを使用する(NULLを除く)してもよいです。
ハッシュ値
理解どのようなハッシュテーブル、ハッシュ値が何であるかを簡単に理解
どのようなハッシュ値
いくつかのハッシュアルゴリズムを介して、データを小さな短いバイナリデータの長い期間にマッピングされ、このデータは、ビッグデータの小さなハッシュ値です。
機能
彼はビッグデータが変更された後にのみ、それはマイナーな変更がある場合でも、彼はハッシュ値を変更しますです。
効果
主な目的は、ファイルのチェックサムまたは署名のためです。
Javaプログラムのハッシュ値
/ ** * Javaでハッシュ値が10進整数、変換後のシステムによって与えられるランダムバイナリ数である
*事実は、それがアドレス値のオブジェクトが、ある論理アドレス、シミュレートされたアドレスであり、そして実際の物理アドレスは、データに保存されていない
* *オブジェクトクラスがメソッドを有し、オブジェクトのハッシュ値を取得することができる: *(ハッシュコードをINT)ハッシュコード値を返す
:ハッシュコード()メソッドソース*
*ネイティブ公共INTのhashCode() ;
*ネイティブ:この方法は、オペレーティングシステム方法のローカル担当者に連絡することです * /
// 随便创建一个类 パブリック クラスの人は、拡張オブジェクト{ プライベート文字列名を、 プライベート int型の年齢; パブリック人(){ } 公共人(文字列名、int型の年齢){ この .nameの= 名前。 この .age = 年齢; } パブリック文字列のgetName(){ 戻り名。 } 公共 ボイドのsetName(文字列名){ この .nameの= 名前。 } 公共 のintgetAge(){ 戻り年齢; } 公共 ボイド setAge(int型の年齢){ この .age = 年齢。 } }
// 参照し、このクラスを使用して、オブジェクトのハッシュ値オブジェクトを作成する パブリック クラスDemoHashCode { 公共 静的 ボイドメイン(文字列[]引数){ // 、P1のオブジェクトを作成し、そのハッシュ値を参照 人物P1を= 新しい新規人物(「LeeHua」を、21 ); // ハッシュ値を取得するために、オブジェクトのハッシュコードメソッドを呼び出し、ハッシュ値P1が一定である INT H1 = p1.hashCode(); のSystem.out.println(H1); // P2オブジェクトを作成しますそのハッシュ値を参照する 人物P2 = 新しい新しい人(「WanTao」、20 ); //は、ハッシュ値を取得するには、オブジェクトのhashCodeメソッドを呼び出して、P2のハッシュ値が一定である int型 H2 = p2.hashCode(); System.out.println(H2); // 参照P1、P2アドレス値 のSystem.out.println(P1) のSystem.out.println(P2); } }
出力: 1639705018 1627674070 view.study.demo18.Person@61bbe9ba view.study.demo18.Person@610455d6
上書きされたhashCodeメソッド場合、作成されたオブジェクトのハッシュ値が影響を受けることになります
以下のような:
パブリック クラス PERSON1の延びオブジェクト{ / ** *オーバーライドhashCodeメソッド * @return ハッシュ値 * / @Override 公共 int型のハッシュコード(){ リターン 666 ; } }
パブリック クラスDemoHashCode1 { 公共 静的 ボイドメイン(文字列[]引数){ // P1のオブジェクト・ビューを作成し、そのハッシュ値 PERSON1 P1 =の新しい新PERSON1()の; // ハッシュ値を求めるコールオブジェクトhashCodeメソッド、P1ハッシュ値は一定である のint =のH1 p1.hashCode(); System.out.printlnは(のH1); // 参照のP1、P2アドレス値 のSystem.out.println(P1); } }
出力: 666 view.study.demo18.Person1@29a
以下のような:私たちは、Stringクラスを使用し、それはまた、オーバーライドhashCodeメソッドをカバー
パブリック クラスDemoStringHashCode { 公共 静的 ボイドメイン(文字列[]引数){ / * Stringクラスのハッシュ値 (クラス文字列オブジェクトクラスのオーバーライドhashCodeメソッド) * / ストリングS1 = 新しい新しい文字列( "LeeHua" ); 文字列S2 = 新しい新しい文字列( "WanTao" ); のSystem.out.println(s1.hashCode()); のSystem.out.println(s2.hashCode()); } }
出力:
-2022794392
-1711288770
画像の理解
定数値、ハッシュ値の各セクション相当の値に、アレイの各位置を見ることができます。
値の数が8未満である場合、配列リスト+を使用する場合、赤黒木のアレイ+を使用して8未満の値の場合数、
以下のような:
ハッシュ値は、1、2、11であります
ハッシュ値は13、14、15であります
値A、B、C、D、E、F、Gは、ハッシュ値89であります
非繰り返しの原則の記憶素子の集合を設定します
原則
set集合在调用add()方法的时候,add()方法会调用元素的hashCode()方法和 equals()方法判断元素是否重复
代码举例
import java.util.HashSet; public class DemoStringHashCode1 { public static void main(String[] args) { HashSet<String> hashSet = new HashSet<>(); String s1 = new String("abc"); String s2 = new String("abc"); hashSet.add(s1); hashSet.add(s2); hashSet.add("一号"); hashSet.add("二号"); System.out.println("s1的哈希值:" + s1.hashCode()); System.out.println("s2的哈希值:" + s2.hashCode()); System.out.println("一号的哈希值:" + "一号".hashCode()); System.out.println("二号的哈希值:" + "二号".hashCode()); System.out.println("HashSet集合:" + hashSet); } }
输出结果: s1的哈希值:96354 s2的哈希值:96354 一号的哈希值:640503 二号的哈希值:644843 HashSet集合:[二号, abc, 一号]
代码讲解
最初,hashSet集合是空的
hashSet.add(s1)的时候,
第一步:add()方法首先会调用s1的hashCode()方法,计算字符串"abc"的哈希值,其哈希值是96354,
第二步:查找集合中哈希值是96354中的元素,没有发现哈希值是96354的key
第三步:将s1存储到集合hashSet中(于是集合hashSet中存在哈希值96354,且对应这数据s1)
hashSet.add(s2)的时候
第一步:add()方法首先会调用s2的hashCode()方法,计算字符串"abc"的哈希值,其哈希值是96354,
第二步:查找集合hashSet中是否存在哈希值是96354,即哈希值96354冲突,
第三步:s2调用equals()方法,和集合中哈希值是96354对应的元素进行比较
第四步:s2.equals(s1)返回true,即哈希值是96354对应的元素已经存在,所以就不添加s2进集合了(其中:s1 = "abc",s2 = "abc")
hashSet.add("一号")的时候
第一步:调用 "一号" 的hashCode()方法,计算字符串 "一号" 的哈希值,其哈希值是640503,
第二步:查找集合中哈希值是640503中的元素,没有发现哈希值是640503的key,
第三步:将 "一号" 存储到集合hashSet中(于是集合hashSet中存在哈希值640503,且对应这数据 "一号")
hashSet.add("二号")的时候
第一步:调用 "二号" 的hashCode()方法,计算字符串 "二号" 的哈希值,其哈希值是644843,
第二步:查找集合中哈希值是644843中的元素,没有发现哈希值是644843的key,
第三步:将 "二号" 存储到集合hashSet中(于是集合hashSet中存在哈希值644843,且对应这数据 "二号")
添加完成,集合hashSet = [abc, 一号, 二号]
HashSet存储自定义类型元素
hashSet存储自定义类型元素,那么自定义的类必须重写hashCode()方法和equals()方法,否则添加的元素可以出现重复,我们平时使用的类型,它们都重写类hashCode()方法和equals()方法。
假如不重写hashCode()方法和equals()方法
例子:
// 随便创建一个类,作为HashSet存入数据的类型 public class Person{ private String name; private int age; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + 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; } }
阿里巴巴Java Code规范会抛出警告
测试一下会出现什么情况
import java.util.HashSet; public class Demo01PersonHashSet { public static void main(String[] args) { HashSet<Person> hashSet = new HashSet<>(); Person p1 = new Person("小明", 20); Person p2 = new Person("小明", 20); Person p3 = new Person("小红", 20); hashSet.add(p1); hashSet.add(p2); hashSet.add(p3); System.out.println(hashSet); } }
输出结果:
[Person{name='小明', age=20}, Person{name='小明', age=20}, Person{name='小红', age=20}]
可以看到,hashSet集合里面可以存在重复的元素
重写hashCode()方法和equals()方法
还是上面这个例子:
在Person类里面添加要重写hashCode()、equals()方法的代码即可,要添加的代码如下
public class Person{ @Override public boolean equals(Object o) { // 参数 == 对象 if (this == o) { return true; } // 传入参数为空,或者对象与参数的hashCode不相等 if (o == null || getClass() != o.getClass()) { return false; } // 向下转型,把Object类型转型为Person类型 Person person = (Person) o; // 返回 age,name return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
再次用上面的代码测试一下Person类型的数据添加是否会出现重复
输出结果:
[Person{name='小明', age=20}, Person{name='小红', age=20}]
可以看到,输出结果中,hashSet集合的元素并没有重复,因此,如果我们想要用HashSet集合存储自定义类型的数据,一定要记得覆盖重写hashCode()方法和equals()方法