1. Java のコレクション
Java のコレクション クラスは、Java プログラミングで最も頻繁に使用され便利なクラスです。コンテナ クラスとして、コレクション クラスは任意の型のデータを格納できます。もちろん、ジェネリックと組み合わせて、指定された型を格納することもできます (ただし、ジェネリックはコンパイル時にのみ有効で、実行時に消去されます)。コレクション クラスに格納されるのはオブジェクトへの参照だけであり、オブジェクト自体ではありません。コレクション クラスの容量は実行時に動的に拡張でき、セットの和集合や共通部分の検索など、多くの便利なメソッドも提供します。
2. コレクションのクラス構造
Java のコレクションには、リンクされたリスト、キュー、ハッシュ テーブルなどのさまざまなデータ構造が含まれています。クラス継承構造の観点から見ると、これは 2 つの主要なカテゴリに分類できます。1 つは Collection インターフェイスから継承されるコレクションで、List、Set、Queue などのコレクション クラスが含まれます。もう 1 つのタイプは Map インターフェイスから継承され、主にハッシュ テーブルに関連するコレクション クラスが含まれます。これら 2 つのカテゴリの継承構造図を見てみましょう:
1、List、Set、Queue
図中の緑の点線は実装を表し、緑の実線はインターフェイス間の継承、青い実線はクラス間の継承を表します。
(1) List: ArrayList や LinkedList など、より多くの List を使用します。この 2 つの違いは、名前からも明らかです。 ArrayList の最下層は配列を通じて実装されるため、ランダム アクセス速度は比較的高速ですが、頻繁に追加や削除が必要な状況では効率が比較的低くなります。 LinkedList の場合、最下層はリンク リストを通じて実装されるため、追加と削除の操作は簡単に完了できますが、ランダム アクセスの効率は比較的低くなります。
まず 2 つの挿入効率を見てみましょう:
package com.paddx.test.collection; import java.util.ArrayList; import java.util.LinkedList; public class ListTest { public static void main(String[] args) { for(int i=;i<;i++){ } long start = System.currentTimeMillis(); LinkedList<Integer> linkedList = new LinkedList<Integer>(); for(int i=;i<;i++){ linkedList.add(,i); } long end = System.currentTimeMillis(); System.out.println(end - start); ArrayList<Integer> arrayList = new ArrayList<Integer>(); for(int i=;i<;i++){ arrayList.add(,i); } System.out.println(System.currentTimeMillis() - end); } }
以下はローカル実行の結果です:
23
1227
この場合、挿入効率がLinkedList の値は ArrayList よりもはるかに高くなりますが、これはさらに極端な状況です。 2 つのランダム アクセスの効率を比較してみましょう:
package com.paddx.test.collection; import java.util.ArrayList; import java.util.LinkedList; import java.util.Random; public class ListTest { public static void main(String[] args) { Random random = new Random(); for(int i=;i<;i++){ } LinkedList<Integer> linkedList = new LinkedList<Integer>(); for(int i=;i<;i++){ linkedList.add(i); } ArrayList<Integer> arrayList = new ArrayList<Integer>(); for(int i=;i<;i++){ arrayList.add(i); } long start = System.currentTimeMillis(); for(int i=;i<;i++){ int j = random.nextInt(i+); int k = linkedList.get(j); } long end = System.currentTimeMillis(); System.out.println(end - start); for(int i=;i<;i++){ int j = random.nextInt(i+); int k = arrayList.get(j); } System.out.println(System.currentTimeMillis() - end); } }
以下はローカルで実行した結果です:
5277
6
ArrayList のランダム アクセス効率がより高いことは明らかです。 LinkedList のそれは数桁違います。これら 2 つのコードを通じて、LinkedList と ArrayList の違いと適用可能なシナリオを明確に理解できるはずです。 Vector は ArrayList のスレッドセーフ バージョンであり、Stack はスタック データ構造に対応します。これら 2 つはほとんど使用されないため、ここでは例を示しません。
(2) Queue: 通常、LinkedList を使用して直接完了できます。上記のクラス図からわかるように、LinkedList は Deque を継承しているため、LinkedList は両端キューの機能を持ちます。 PriorityQueue の特徴は、要素ごとに優先度を設けており、優先度の高い要素から順にデキューされます。
(3)Set: Set と List の主な違いは、Set では要素の繰り返しが許可されないのに対し、List では要素の繰り返しが許可されることです。要素の重複の判定は、オブジェクトのhashメソッドとequalsメソッドに基づいて判断する必要があります。これが、通常、コレクション内の要素クラスの hashCode メソッドとquals メソッドをオーバーライドする理由です。 SetとListの違い、hashcodeメソッドとequalsメソッドの機能を例として見てみましょう:
package com.paddx.test.collection; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; public class SetTest { public static void main(String[] args) { Person p1 = new Person("lxp",10); Person p2 = new Person("lxp",10); Person p3 = new Person("lxp",20); ArrayList<Person> list = new ArrayList<Person>(); list.add(p1); System.out.println("---------"); list.add(p2); System.out.println("---------"); list.add(p3); System.out.println("List size=" + list.size()); System.out.println("----分割线-----"); Set<Person> set = new HashSet<Person>(); set.add(p1); System.out.println("---------"); set.add(p2); System.out.println("---------"); set.add(p3); System.out.println("Set size="+set.size()); } static class Person{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { System.out.println("Call equals();name="+name); if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return name.equals(person.name); } @Override public int hashCode() { System.out.println("Call hashCode(),age="+age); return age; } } }
上記コードの実行結果は以下の通りです:
--------- --------- List size=3 ----分割线----- Call hashCode(),age=10 --------- Call hashCode(),age=10 Call equals();name=lxp --------- Call hashCode(),age=20 Set size=2
結果から、要素がリストに追加されると、追加の操作は実行されず、繰り返すことができることがわかります。 Set を追加する前に、まず hashCode メソッドを実行する必要があります。戻り値がすでにセットに存在する場合は、equals メソッドによって返された結果も true である場合、その要素が証明されます。すでに存在しており、返された hashCode 値が異なる場合、古い要素はコレクションに直接追加されます。ここで、コレクション内の要素について、異なる hashCode 値を持つ要素は等しくなくてはなりませんが、等しくない要素は同じ hashCode 値を持つ可能性があることに注意してください。
HashSetとLinkedHashSetの違いは、後者はセットに挿入される要素の順序が出力の順序と一致していることを保証できることです。 TresSet との違いは、Comparator に従ってソートされることです。デフォルトでは、文字の自然な順序に従って昇順に配置されます。
(4)Iterable: この図から、Collection クラスが Iterable を継承していることがわかります。このインターフェイスの機能は、すべてのコレクション クラス (Map 関連のクラスを除く) が要素トラバーサルの機能を提供することです。要素トラバーサル機能を提供します。 Iterable には Iterator のイテレータが含まれています。そのソース コードは次のとおりです。イテレータ パターンに慣れている場合は、簡単に理解できるはずです。
りー2. 地図:
Map类型的集合最大的优点在于其查找效率比较高,理想情况下可以实现O(1)的时间复杂度。Map中最常用的是HashMap,LinkedHashMap与HashMap的区别在于前者能够保证插入集合的元素顺序与输出顺序一致。这两者与TreeMap的区别在于TreeMap是根据键值进行排序的,当然其底层的实现也有本质的区别,如HashMap底层是一个哈希表,而TreeMap的底层数据结构是一棵树。我们现在看下TreeMap与LinkedHashMap的区别:
package com.paddx.test.collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeMap; public class MapTest { public static void main(String[] args) { Map<String,String> treeMap = new TreeMap<String,String>(); Map<String,String> linkedMap = new LinkedHashMap<String, String>(); treeMap.put("b",null); treeMap.put("c",null); treeMap.put("a",null); for (Iterator<String> iter = treeMap.keySet().iterator();iter.hasNext();){ System.out.println("TreeMap="+iter.next()); } System.out.println("----------分割线---------"); linkedMap.put("b",null); linkedMap.put("c",null); linkedMap.put("a",null); for (Iterator<String> iter = linkedMap.keySet().iterator();iter.hasNext();){ System.out.println("LinkedHashMap="+iter.next()); } } }
运行上述代码,执行结果如下:
TreeMap=a TreeMap=b TreeMap=c ----------分割线--------- LinkedHashMap=b LinkedHashMap=c LinkedHashMap=a
从运行结果可以很明显的看出这TreeMap和LinkedHashMap的区别,前者是按字符串排序进行输出的,而后者是根据插入顺序进行输出的。细心的读者可以发现,HashMap与TreeMap的区别,与之前提到的HashSet与TreeSet的区别是一致的,在后续进行源码分析的时候,我们可以看到HashSet和TreeSet本质上分别是通过HashMap和TreeMap来实现的,所以它们的区别自然也是相同的。HashTable现在已经很少使用了,与HashMap的主要区别是HashTable是线程安全的,不过由于其效率比较低,所以通常使用HashMap,在多线程环境下,通常用CurrentHashMap来代替。
三、总结
本文只是从整体上介绍了Java集合框架及其继承关系。除了上述类,集合还提供Collections和Arrays两个工具类,此外,集合中排序跟Comparable和Comparator紧密相关。
以上がJavaのコレクションクラスとは何ですか?コレクション クラス構造の図例付きの説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。