程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java編程手冊-Collection框架(下)

Java編程手冊-Collection框架(下)

編輯:JAVA綜合教程

Java編程手冊-Collection框架(下)


5. Set接口與實現

Set接口表示一個數學的集合,它不允許元素的重復,只能包含一個null元素。

\

 

Set接口聲明了下面抽象方法。

 

boolean add(E o)           // add the specified element if it is not already present
boolean remove(Object o)   // remove the specified element if it is present
boolean contains(Object o) // return true if it contains o
 
// Set operations
boolean addAll(Collection c) // Set union
boolean retainAll(Collection c)        // Set intersection

Set接口的實現類包括:

 

HashSet:在一個哈希表中存儲元素(哈希值通過hashcode()產生),HashSet是Set的全面實現。LinkedHashSet:存儲元素在一個哈希鏈表中,因此它有更高的插入刪除效率。TreeSet: 它也實現了子接口NavigableSet 和 SortedSet,存儲元素在一個紅黑樹的數據結構中,它的搜索、添加、刪除效率很高,時間復雜度為O(log(n) 5.1 HashSet的例子 下面寫了一個Book類並且寫了一個Book的集合。
public class Book {
   private int id;
   private String title;
 
   // Constructor
   public Book(int id, String title) {
      this.id = id;
      this.title = title;
   }
 
   @Override
   public String toString() {
      return id + ": " + title;
   }
 
   // Two book are equal if they have the same id
   @Override
   public boolean equals(Object o) {
      if (!(o instanceof Book)) {
         return false;
      }
      return this.id == ((Book)o).id;
   }
 
   // Consistent with equals(). Two objects which are equal have the same hash code.
   @Override
   public int hashCode() {
      return id;
   }
}

我們需要提供equals()方法,這樣實現Set的集合可以驗證元素的相等性和重復性,例如,我們選用id來區分不同的對象元素,這樣我們實現的equals()方法就是如果兩個對象的id相同,那麼就返回true。另外,我們也需要重新hashCode()方法來保持它也equals()的一致性。關於equals()和hashCode()的關聯可以參考文章:Effective Java——對所有對象通用的方法
import java.util.HashSet;
import java.util.Set;
public class TestHashSet {
   public static void main(String[] args) {
      Book book1 = new Book(1, "Java for Dummies");
      Book book1Dup = new Book(1, "Java for the Dummies"); // same id as above
      Book book2 = new Book(2, "Java for more Dummies");
      Book book3 = new Book(3, "more Java for more Dummies");
 
      Set set1 = new HashSet();
      set1.add(book1);
      set1.add(book1Dup); // duplicate id, not added
      set1.add(book1);    // added twice, not added
      set1.add(book3);
      set1.add(null);     // Set can contain a null
      set1.add(null);     // but no duplicate
      set1.add(book2);
      System.out.println(set1); // [null, 1: Java for Dummies,
                                //  2: Java for more Dummies, 3: more Java for more Dummies]
 
      set1.remove(book1);
      set1.remove(book3);
      System.out.println(set1); // [null, 2: Java for more Dummies]
 
      Set set2 = new HashSet();
      set2.add(book3);
      System.out.println(set2); // [3: more Java for more Dummies]
      set2.addAll(set1);        // "union" with set1
      System.out.println(set2); // [null, 2: Java for more Dummies, 3: more Java for more Dummies]
 
      set2.remove(null);
      System.out.println(set2); // [2: Java for more Dummies, 3: more Java for more Dummies]
      set2.retainAll(set1);     // "intersection" with set1
      System.out.println(set2); // [2: Java for more Dummies]
   }
}
一個Set不能存放重復的元素,檢查元素的重復性就是通過重寫的equal()方法來檢查的。另外一個Set中只能存放一個null元素。addAll()是否是將兩個Set聯合,retainAll()是取兩個Set的交集。   需要注意的是Set中元素的排序是任意的,並不是插入的順序。   5.2 LinkedHashSet的例子 不像HashSet,LinkedHashSet構建的是一個基於哈希表的鏈表,主要是為了更好的插入和刪除效率,另外,它裡面元素的順序維持的就是插入的順序(例如:add()方法)。
import java.util.LinkedHashSet;
import java.util.Set;
public class TestLinkedHashSet {
   public static void main(String[] args) {
      Book book1 = new Book(1, "Java for Dummies");
      Book book1Dup = new Book(1, "Java for the Dummies"); // same id as above
      Book book2 = new Book(2, "Java for more Dummies");
      Book book3 = new Book(3, "more Java for more Dummies");
 
      Set set = new LinkedHashSet();
      set.add(book1);
      set.add(book1Dup); // duplicate id, not added
      set.add(book1); // added twice, not added
      set.add(book3);
      set.add(null);  // Set can contain a null
      set.add(null);  // but no duplicate
      set.add(book2);
      System.out.println(set);  // [1: Java for Dummies, 3: more Java for more Dummies,
                                //  null, 2: Java for more Dummies]
   }
}

可以看到,Set的輸出的順序跟add()添加的順序是一致的。   5.3 NavigableSet & SortedSet接口 SortedSet在元素add()的過程中會進行排序,排序策略使用的是Comparable的實現或者提供的Comparator對象。 NavigableSet是Set的子接口,它提供了一些額外的方法。
Iterator descendingIterator()  // Returns an iterator over the elements in this set,
                                  // in descending order.
Iterator iterator()   // Returns an iterator over the elements in this set, in ascending order.
 
// Per-element operation
E floor(E e)    // Returns the greatest element in this set less than or equal to the given element, 
                // or null if there is no such element.
E ceiling(E e)  // Returns the least element in this set greater than or equal to the given element, 
                // or null if there is no such element.
E lower(E e)    // Returns the greatest element in this set strictly less than the given element, 
                // or null if there is no such element.
E higher(E e)   // Returns the least element in this set strictly greater than the given element, 
                // or null if there is no such element.
 
// Subset operation
SortedSet headSet(E toElement) // Returns a view of the portion of this set 
                                  // whose elements are strictly less than toElement.
SortedSet tailSet(E fromElement) // Returns a view of the portion of this set
                                    // whose elements are greater than or equal to fromElement.
SortedSet subSet(E fromElement, E toElement)  
                      // Returns a view of the portion of this set 
                      // whose elements range from fromElement, inclusive, to toElement, exclusive.
5.4 TreeSet例子 TreeSet是NavigableSetSortedSet的實現. 例子——實現Comparable的TreeSet
public class AddressBookEntry implements Comparable {
   private String name, address, phone;
 
   public AddressBookEntry(String name) {
      this.name = name;
   }
 
   @Override
   public String toString() {
      return name;
   }
 
   @Override
   public int compareTo(AddressBookEntry another) {
      return this.name.compareToIgnoreCase(another.name);
   }
 
   @Override
   public boolean equals(Object o) {
      if (!(o instanceof AddressBookEntry)) {
         return false;
      }
      return this.name.equalsIgnoreCase(((AddressBookEntry)o).name);
   }
 
   @Override
   public int hashCode() {
      return name.length();
   }
}
AddressBookEntry實現了Comparable接口,為了在TreeSet中進行使用,它重寫了compareTo()方法去比較name,它同時也重新了equals()和hashCode()方法,主要為了保持跟compareTo()的一致性。
import java.util.TreeSet;
 
public class TestTreeSetComparable {
   public static void main(String[] args) {
      AddressBookEntry addr1 = new AddressBookEntry("peter");
      AddressBookEntry addr2 = new AddressBookEntry("PAUL");
      AddressBookEntry addr3 = new AddressBookEntry("Patrick");
 
      TreeSet set = new TreeSet();
      set.add(addr1);
      set.add(addr2);
      set.add(addr3);
      System.out.println(set); // [Patrick, PAUL, peter]
 
      System.out.println(set.floor(addr2));   // PAUL
      System.out.println(set.lower(addr2));   // Patrick
      System.out.println(set.headSet(addr2)); // [Patrick]
      System.out.println(set.tailSet(addr2)); // [PAUL, peter]
   }
}
可以看到AddressBookEntry對象在add()操作過程中進行了排序,使用的就是Comparable實現的方法。   例子——實現Comparator的TreeSet
下面我們來重新上面的例子,這次使用的是Comparator對象來實現對象的比較。
public class PhoneBookEntry {
   public String name, address, phone;
 
   public PhoneBookEntry(String name) {
      this.name = name;
   }
 
   @Override
   public String toString() {
      return name;
   }
}

上面的PhoneBookEntry並沒有實現Comparator,我們這裡是單獨定義一個Comparator實例,使用這個實例來創建TreeSet。
import java.util.Set;
import java.util.TreeSet;
import java.util.Comparator;
 
public class TestTreeSetComparator {
   public static class PhoneBookComparator implements Comparator {
      @Override
      public int compare(PhoneBookEntry p1, PhoneBookEntry p2) {
         return p2.name.compareToIgnoreCase(p1.name);  // descending name
      }
   }
 
   public static void main(String[] args) {
      PhoneBookEntry addr1 = new PhoneBookEntry("peter");
      PhoneBookEntry addr2 = new PhoneBookEntry("PAUL");
      PhoneBookEntry addr3 = new PhoneBookEntry("Patrick");
 
      Comparator comp = new PhoneBookComparator();
      TreeSet set = new TreeSet(comp);
      set.add(addr1);
      set.add(addr2);
      set.add(addr3);
      System.out.println(set);    // [peter, PAUL, Patrick]
 
      Set newSet = set.descendingSet();  // Reverse the order
      System.out.println(newSet); // [Patrick, PAUL, peter]
   }
}
上面我們創建了一個帶有BookComparator實例的TreeSet,這樣上面Set中對象的比較使用的就是BookComparator的compare方法,在上面例子中,調用TreeSet的descendingSet()方法來是集合倒序。   6. Queue接口與實現 Queue中的元素是以一種特定的順序進行添加和刪除,例如典型的先入先出。deque是一個雙向隊列,它的元素的添加和刪除可以在兩端進行。 \ 在Collection操作之外,Queue也額外添加了插入、獲取、查看的操作方法,每個方法都提供了兩種形式:一個是如果操作失敗會拋出異常,另外一個如果操作是否會返回一個值(false或者null,據具體操作而定)。
// Insertion at the end of the queue
boolean add(E e)   // throws IllegalStateException if no space is currently available
boolean offer(E e) // returns true if the element was added to this queue, else false
 
// Extract element at the head of the queue
E remove()         // throws NoSuchElementException if this queue is empty
E poll()           // returns the head of this queue, or null if this queue is empty
 
// Inspection (retrieve the element at the head, but does not remove)
E element()        // throws NoSuchElementException if this queue is empty
E peek()           // returns the head of this queue, or null if this queue is empty

Deque也提供了額外的方法來操作隊列的兩端
// Insertion
void addFirst(E e)
void addLast(E e)
boolean offerFirst(E e)
boolean offerLast(E e)
 
// Retrieve and Remove
E removeFirst()
E removeLast()
E pollFirst()
E pollLast()
 
// Retrieve but does not remove
E getFirst()
E getLast()
E peekFirst()
E peekLast()
一個Deque可以看做是一個FIFO對象(通過add(e),remove(),element(),offer(e),poll(),peek()方法),也可以看做是一個LIFO隊列(通過push(e),pop(),peek()方法)。 QueueDeque的實現類如下: PriorityQueue: 這個隊列可以使用一個指定的順序去進行排序,而不是FIFO的順序。
ArrayDeque: 使用queue或者deque來實現的動態數組,類似於ArrayList
LinkedList: 它在實現List接口的基礎上,也實現了QueueDeque接口,它是雙向鏈表結構。
  7. Map接口與實現 Map集合對應的是一個鍵值對,每個key對應一個value,鍵值不允許重復,value是允許重復的,它跟線性數組有些相同,不同的是它使用key來進行索引訪問對應的value,所以map使用使用任意的key。 \ Map接口聲明了下面抽象方法。
V get(Object key)      // Returns the value of the specified key
V put(K key, V value)  // Associate the specified value with the specified key
boolean containsKey(Object key)  // Is this map has specified key?
boolean containsValue(Object value)

// Views
Set keySet()         // Returns a set view of the keys
Collection values()  // Returns a collection view of the values
Set entrySet()          // Returns a set view of the key-value
Map接口的實現類包括: HashMap:HashMap實現了Map,並且是Map全面的實現,但是HashMap的方法不是同步的,也就是線程不安全。
TreeMap:實現了SortedMap接口的紅黑樹。
LinkedHashMap:帶有鏈表的哈希表,方便插入和刪除
Hashtable:它是對Map方法的同步實現,也就是它是線程安全的,另外它不允許key和value為null。
例子:
HashMap aMap = new HashMap();
aMap.put("1", "Monday");
aMap.put("2", "Tuesday");
aMap.put("3", "Wednesday");

String str1 = aMap.get("1");  // No need downcast
System.out.println(str1);
String str2 = aMap.get("2");
System.out.println(str2);
String str3 = aMap.get("3");
System.out.println(str3);

Set keys = aMap.keySet();
for (String str : keys) {
   System.out.print(str);
   System.out.print(":");
   System.out.println(aMap.get(str));
}
  例子——HashMap
// Counts the frequency of each of the words in a file given in the command-line,
// and saves in a map of {word, freq}.
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;
import java.io.File;
 
public class WordCount {
   public static void main(String[] args) throws Exception {
      Scanner in = new Scanner(new File(args[0]));
 
      Map map = new HashMap();
      while (in.hasNext()) {
         String word = in.next();
         int freq = (map.get(word) == null) ? 1 : map.get(word) + 1;   // type-safe
         map.put(word, freq);      // autobox int to Integer and upcast, type-check
      }
      System.out.println(map);
   }
}

8. 算法 Collection框架提供了兩個工具類:java.util.Arraysjava.util.Collections,它們提供了一些基本的算法,例如插入和查找等等。 另外需要注意的是Collections是工具類,Collection是集合框架的接口。   8.1 java.util.Arrays工具類 java.util.Arrays包含了很多的靜態方法來對數組進行排序或者查找等等操作。 Array是Java中的引用類型,它可以包含基本數據類型,也可以包含對象數據類型,Java中的數組可以包含9種數據類型,byte,short,int,long,float,double,char,boolean和對象類型。     Sorting - Arrays.sort()
對除boolean類型之外的基本數據類型以及對象類型的數據進行排序,例如int[]數組:
// Sort the given array into ascending order
public static void sort(int[] a)
// Sort between fromIndex (inclusive) and toTodex (exclusive)
public static void sort(int[] a, int fromIndex, int toIndex)
同理,sort()可用於byte[],short[],long[],float[],double[],char[](除boolean[]外) andObject[]中。對應Object[],對象必須實現Comparable接口的compareTo()方法。
public static void sort(Object[] a)
public static void sort(Object[] a, int fromIndex, int toIndex)
對於泛型對象的排序,通過提供Comparator對象來實現排序。
public static  void sort(T[] a, Comparator c)
public static  void sort(T[] a, int fromIndex, int toIndex, Comparator c)
假設你想對一個Integer數組進行排序,也就是T為Integer,你可以實現一個Comparator或者Comparator或者Comparator Searching - Arrays.binarySearch() 同理,也有對於所有基本數據類型或者對象類型查找的方法,在執行binarySearch()執行對數組需要進行排序。
public static int binarySearch(int[] a, int key)
public static int binarySearch(int[] a, int fromIndex, int toIndex, int key)
// Similar methods for byte[], short[], long[], float[], double[] and char[]
 
// Searching objects, which implements Comparable
public static int binarySearch(Object[] a, Object key)
public static int binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
// Searching generic objects, based on the given Comparator
public static  int binarySearch(T[] a, T key, Comparator c)
public static  int binarySearch(T[] a, T key, int fromIndex, int toIndex, Comparator c)

Equality Comparison - Arrays.equals()
public static boolean equals(int[] a1, int[] a2)
// Similar methods for byte[], short[], long[], float[], double[], char[], boolean[] and Object[]

Copying - Arrays.copyOf() 和 Arrays.copyOfRange()
public static int[] copyOf(int[] original, int newLength)
  // Copies the given array, truncating or padding with zeros (if necessary) so the copy has the specified length
public static int[] copyOfRange(int[] original, int from, int to)
  // padded with 0 if to is beyond the length
 
// Similar methods for byte[], short[], long[], float[], double[], char[] and boolean[]

public static  T[] copyOf(T[] original, int newLength)
public static  T[] copyOfRange(T[] original, int from, int to)
public static  T[] copyOf(U[] original, int newLength, Class newType)
public static  T[] copyOfRange(U[] original, int from, int to, Class newType)
Filling - Arrays.fill()
public static void fill(int[] a, int value)
public static void fill(int[] a, int fromIndex, int toIndex, int value)
// Similar methods for byte[], short[], long[], float[], double[], char[] and boolean[] and Object[]
Description - Arrays.toString()
// Returns a string representation of the contents of the specified array.
public static String toString(int[] a)
// Similar methods for byte[], short[], long[], float[], double[], char[] and boolean[] and Object[]

轉換為List - Arrays.asList()
// Returns a fixed-size list backed by the specified array.
// Change to the list write-thru to the array.
public static  List asList(T[] a)
  8.2 java.util.Collections工具類 跟java.util.Arrays一樣,java.util.Collections也提供了靜態的方法來對集合進行操作。、   Sorting - Collections.sort()
// Sorts the specified list into ascending order. The objects shall implement Comparable. 
public static > void sort(List list)
// Sorts the specified list according to the order induced by the specified comparator.
public static  void sort(List list, Comparator c)
需要注意的是Collections.sort()只能用在List上面,不能使用在Set,QueueMap上,SortedSet(TreeSet) 和SortedMap(TreeMap)可以自動排序。

Searching - Collections.binarySearch() 在使用binarySearch()之前,List必須進行排序。
public static  int binarySearch(List> list, T key)
public static  int binarySearch(List list, T key, Comparator c)

最大和最小 - Collections.max() & Collections.min()
// Returns the maximum/minimum element of the given collection, according to the natural ordering of its elements.
public static > T max(Collection c)
public static > T min(Collection c)
 
// Returns the maximum/minimum element of the given collection, according to the order induced by the specified comparator.
public static  T max(Collection c, Comparator comp)
public static  T min(Collection c, Comparator comp)

Synchronized Collection, List, Set & Map 很多的Collection的實現類都不是同步的,例如ArrayList,HashSetHashMap,也就是它們不是線程安全的,除了VectorHashTable是同步的,如果我們不想使用VectorHashTable,我們可以通過靜態的Collections.synchronizedXxx()創建同步的CollectionListSetSortedSetMapSortedMap。
// Returns a synchronized (thread-safe) collection backed by the specified collection.
public static  Collection synchronizedCollection(Collection c)

// Others
public static  List synchronizedList(List list)
public static  Set synchronizedSet(Set set)
public static  SortedSet synchronizedSortedSet(SortedSet set)
public static  Map synchronizedMap(Map map)
public static  SortedMap synchronizedSortedMap(SortedMap map)
對於上面方法返回的對象,在遍歷的時候,必須包含在synchronize塊中。
List lst = Collections.synchronizedList(new ArrayList());
   ......
synchronized(lst) {  // must be enclosed in a synchronized block
   Iterator iter = lst.iterator(); 
   while (iter.hasNext())
     iter.next();
     ......
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved