- 浏览: 3623 次
- 性别:
- 来自: 苏州
最新评论
JAVA基础_物件容器(Container)
转自:良葛格学习笔记(http://caterpillar.onlyfun.net/Gossip/)
物件容器(Container)
物件容器可以幫您持有對象,在Java中分作兩大類:Collection 與 Map。前者可持有各自獨立的物件,後者持有成對的key-value物件。
* Collection 類
Collection 類包括了 List 類與 Set 類,List 以放置物件至容器中的順序來排列物件,Set 類不接受重覆的物件,並有自己的一套排序規則。
o ArrayList
o LinkedList
o HashSet
o TreeSet
o EnumSet
* Map 類
在將物件存入 Map類時,需要配合一把key,您要取回物件時就是根據這把key,Map中的key是唯一的,Map擁有自己的排序機制。
o HashMap
o TreeMap
o EnumMap
ArrayList
ArrayList類別實作了List介面,List介面是Collection介面的子介面,主要增加了根據索引取得物件的方法。
ArrayList使用陣列實作List介面,所以對於快速的隨機取得物件來說,使用ArrayList可以得到較好的效能,不過在移除物件或插入物件時,ArrayList就比較慢(使用 LinkedList 在這方面就好的多)。
來看看一個ArrayList的範例:
* ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String> list = new ArrayList<String>();
System.out.println("輸入名稱(quit結束)");
while(true) {
System.out.print("# ");
String input = scanner.next();
if(input.equals("quit"))
break;
list.add(input);
}
System.out.print("顯示輸入: ");
for(int i = 0; i < list.size(); i++)
System.out.print(list.get(i) + " ");
System.out.println();
}
}
在 J2SE 5.0 之後新增了泛型(Generic)的功能,使用物件容器時建議容器中將儲存的物件型態,如此您的物件在存入容器會被限定為您所宣告的型態,而取出時,也不至於失去原來的型態資訊,可以避免型態轉換時的問題。
使用add()方法可以將一個物件加入ArrayList中,使用size()方法可以傳回目前的ArrayList的長度,使用get()可以傳回指定索引處的物件,使用toArray()可以將ArrayList中的物件轉換為物件陣列。
以下是執行結果:
輸入名稱(quit結束)
# Justin
# caterpillar
# momor
# quit
顯示輸入: Justin caterpillar momor
您可以使用get()方法指定索引值取出物件,然而如果您的目的是要循序取出容器中所有的物件,則您可以使用Iterator類,Iterator類實作 Iterator 模式,實際來看個例子:
* ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String> list = new ArrayList<String>();
System.out.println("輸入名稱(quit結束)");
while(true) {
System.out.print("# ");
String input = scanner.next();
if(input.equals("quit"))
break;
list.add(input);
}
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
iterator()方法會傳回一個Iterator物件,這個物件提供的遍訪的方法,hasNext()方法測試Iterator中是否還有物件,如果有的話,可以使用next()取出。
事實上,在J2SE 5.0您也不必須使用iterator()了,使用增強的for迴圈可以直接遍訪List的所有元素,例如:
* ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String> list = new ArrayList<String>();
System.out.println("輸入名稱(quit結束)");
while(true) {
System.out.print("# ");
String input = scanner.next();
if(input.equals("quit"))
break;
list.add(input);
}
for(String s : list) {
System.out.print(s + " ");
}
System.out.println();
}
}
LinkedList
List類是以物件加入(add)容器的順序來排列它們,如果您的物件加入之後大都是為了取出,而不會常作移除或插入(Insert)的動作,則使用ArrayList,如果您會經常從容器中作移除或插入物件的動作,則使用LinkedList會獲得較好的效能。
LinkedList實作了List介面,並增加了一些移除與插入物件的特定方法,像是addFirst()、addLast()、 getFirst()、getLast()、removeFirst( )、removeLast()等等,由於在插入與移除時有較好的效能,適合拿來實作堆疊(Stack)與佇列(Queue)。
以下實作一個簡單的FILO(First-In, Last-Out)堆疊,可以存入字串:
* StringStack.java
package onlyfun.caterpillar;
import java.util.*;
public class StringStack {
private LinkedList<String> linkedList;
public StringStack() {
linkedList = new LinkedList<String>();
}
public void push(String name) {
linkedList.addFirst(name);
}
public String top() {
return linkedList.getFirst();
}
public String pop() {
return linkedList.removeFirst();
}
public boolean isEmpty() {
return linkedList.isEmpty();
}
}
而對於FIFO(First-In, First-Out)的佇列,我們也可以使用LinkedList來實作:
* StringQueue.java
package onlyfun.caterpillar;
import java.util.*;
public class StringQueue {
private LinkedList<String> linkedList;
public StringQueue() {
linkedList = new LinkedList<String>();
}
public void put(String name) {
linkedList.addFirst(name);
}
public String get() {
return linkedList.removeLast();
}
public boolean isEmpty() {
return linkedList.isEmpty();
}
}
事實上,如果您要使用佇列的功能,您也不用親自實作,在J2SE 5.0中,LinkedList也實作了新加入的java.util.Queue介面,這個介面有五個必須實作的方法:
element() 取得但不移除佇列第一個元件,佇列為空時會丟出例外
offer() 加入一個元素至佇列中
peek() 取得但不移除佇列第一個元件
poll() 取得並移去佇列第一個元件,佇列為空時傳回null
remove() 取得並移除佇列第一個元件
要使用佇列的功能,您只要類似這樣的宣告:
Queue<String> queue = new LinkedList<String>();
HashSet
HashSet實作Set介面,Set介面繼承Collection介面,Set容器中的物件都是唯一的,加入 Set容器中的物件都必須重新定義equals()方法,作為唯一性的識別,Set容器有自己的一套排序規則。
HashSet的排序規則是利用Hash Table,所以加入HashSet容器的物件還必須重新定義hashCode()方法,利用Hash的方式,可以讓您快速的找到容器中的物件,在比較兩個加入Set容器中的物件是否相同時,會先比較hashCode()方法傳回的值是否相同,如果相同,則再使用equals()方法比較,如果兩者都相同,則視為相同的物件。
事實上,在撰寫新的類別時,最好總是重新定義equals()與hashCode()方法,以符合Java的設計規範,您可以參考 Object 類別 中的介紹瞭解如何重新定義equals()與hashCode()。
來看一個例子:
* HashSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("caterpillar");
set.add("justin");
set.add("momor");
set.add("justin");
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
執行結果:
momor justin caterpillar
如上所示的,即使重覆加入了"justin"字串,HashSet中仍只有一個"justin"字串物件,另一個要注意的是,选代所有的值時,其順序與您加入的順序是不一樣的,选代所有值時的順序是HashSet排序過後的順序。
LinkedHashSet是HashSet的子類,它在內部實作使用Hash Code進行排序,然而允許您在列舉時行為像是LinkedList,簡單的改寫上面的程式即可瞭解:
* LinkedHashSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<String>();
set.add("caterpillar");
set.add("justin");
set.add("momor");
set.add("justin");
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
執行結果:
caterpillar justin momor
可以在執行結果中看到的,选代時的順序正是您加入值的順序。
TreeSet
TreeSet實作Set介面與SortedSet介面,提供相關的方法讓您有序的取出對應位置的物件,像是 first()、last()等方法,TreeSet是J2SE中唯一實作SortedSet介面的類別,它使用紅黑樹結構來對加入的物件進行排序。
看個簡單的例子:
* TreeSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
Set<String> set = new TreeSet<String>();
set.add("justin");
set.add("caterpillar");
set.add("momor");
set.add("justin");
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
由於加入的是String物件,執行結果會自動依字典順序進行排序的動作:
caterpillar justin momor
依字典順序排序String物件是TreeSet預設的,如果您對物件有自己的一套排序順序,您要實作一個 Comparator 物件,您要實作compare()方法,它必須傳回整數值,如果物件順序相同則傳回0,傳回正整數表示compare()方法的第一個物件大於第二個物件,反之則傳回負整數。
舉個實際的例子,假設您想要改變TreeSet依字典順序排列加入的物件為相反的順序:
* CustomComparator.java
package onlyfun.caterpillar;
import java.util.Comparator;
public class CustomComparator<T> implements Comparator<T> {
public int compare(T o1, T o2) {
if (((T) o1).equals(o2))
return 0;
return ((Comparable<T>) o1).compareTo((T) o2) * -1;
}
}
在自訂的Comparator中,如果兩個物件的順序相同會傳回0,這在TreeSet中表示兩個物件是同一個物件,TreeSet要求傳入的物件必須實作java.lang.Comparable介面,範例中只是簡單的將原來compareTo()傳回的值乘以負一,如此在TreeSet中就可以簡單的讓排列順序相反。
在建構TreeSet實例時一併指定自訂的Comparator,例如:
* TreeSetDemo2.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeSetDemo2 {
public static void main(String[] args) {
// 自訂Comparator
Comparator<String> comparator =
new CustomComparator<String>();
Set<String> set =
new TreeSet<String>(comparator);
set.add("justin");
set.add("caterpillar");
set.add("momor");
// 使用 enhanced for loop 顯示物件
for(String name : set) {
System.out.print(name + " ");
}
System.out.println();
}
}
執行的結果是相反的:
momor justin caterpillar
EnumSet
EnumSet的名稱說明了其作用,它是在J2SE 5.0後加入的新類別,可以協助您建立列舉值的集合,它提供了一系列的靜態方法,可以讓您指定不同的集合建立方式,例如:
* EnumSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum FontConstant { Plain, Bold, Italic }
public class EnumSetDemo {
public static void main(String[] args) {
EnumSet<FontConstant> enumSet =
EnumSet.of(FontConstant.Plain, FontConstant.Bold);
showEnumSet(enumSet);
showEnumSet(EnumSet.complementOf(enumSet));
}
public static void showEnumSet(
EnumSet<FontConstant> enumSet) {
Iterator iterator = enumSet.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
您可以指定列舉值來加入EnumSet中,of()方法會返回一個EnumSet的實例,當中包括您所指定的列舉值,您也可以使complementOf()指定一個EnumSet的互補集,以下是執行的結果:
Plain Bold
Italic
EnumSet實作了Set介面,所以您可以使用Set介面的所有方法來測試它所包括的列舉值,例如測試一個集合中是否包括 FontConstant.Bold:
if(enumSet.contains(FontConstant.Bold)) {
....
}
您也可以建立一個空的EnumSet,然後自己逐個加入列舉值,例如:
* EnumSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum FontConstant { Plain, Bold, Italic }
public class EnumSetDemo {
public static void main(String[] args) {
EnumSet<FontConstant> enumSet =
EnumSet.noneOf(FontConstant.class);
enumSet.add(FontConstant.Bold);
enumSet.add(FontConstant.Italic);
showEnumSet(enumSet);
}
public static void showEnumSet(
EnumSet<FontConstant> enumSet) {
Iterator iterator = enumSet.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
執行結果:
Bold Italic
您也可以由一個容器物件中建立EnumSet:
List<FontConstant> list = new ArrayList<FontConstant>();
list.add(FontConstant.Bold);
list.add(FontConstant.Italic);
showEnumSet(EnumSet.copyOf(list));
HashMap
HashMap實作Map介面,內部實作使用Hash Table,讓您在常數時間內可以尋得key/value對。
所謂的key/value對,簡單的說,您將Map容器物件當作一個有很多間房間的房子,每個房間的門有一把鑰匙,您將物件儲存至房間中時,要順便擁有一把鑰匙,下次要取回物件時,就是根據這把鑰匙取得。
以一個簡單的例子來作說明:
* HashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new HashMap<String, String>();
map.put("caterpillar", "caterpillar's message!!");
map.put("justin", "justin's message!!");
System.out.println(map.get("justin"));
System.out.println(map.get("caterpillar"));
}
}
在宣告Map型態時,您指定了key/value各自的型態,這邊都是宣告為String,也就是以String物件作為key物件的型態,而 value也是以String物件作為其型態。
使用Map的put()方法將物件存入,必須同時指定key/value,而要取回物件時,則指定key,程式的執行結果如下:
justin's message!!
caterpillar's message!!
HashMap是個被經常使用的物件,您可以參考下面幾個例子中HashMap的應用:
* Command 模式
* Thread-Specific Storage 模式
* 控制器(Servlet)
可以使用values()方法返回一個Collection物件,如果您需要一次选代Map中所有的物件,這會很有用,例如:
* HashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new HashMap<String, String>();
map.put("justin", "justin's message!!");
map.put("momor", "momor's message!!");
map.put("caterpillar", "caterpillar's message!!");
Collection collection = map.values();
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
執行結果:
momor's message!!
justin's message!!
caterpillar's message!!
HashMap使用Hash Table,因而它有自己的排序方式,如果您想要在选代所有的物件時,依照插入的順序來排序,則可以使用LinkedHashMap,它是HashMap 的子類,使用values()所返回的Collection物件,其內含物件之順序即為當初您加入物件之順序,例如:
* LinkedHashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class LinkedHashMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new LinkedHashMap<String, String>();
map.put("justin", "justin's message!!");
map.put("momor", "momor's message!!");
map.put("caterpillar", "caterpillar's message!!");
Collection collection = map.values();
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
執行結果:
justin's message!!
momor's message!!
caterpillar's message!!
TreeMap
TreeMap實作Map介面與SortedMap介面,提供相關的方法讓您有序的取出對應位置的物件,像是 firstKey()、lastKey()等方法,TreeMap是J2SE中唯一實作SortedMap介面的類別,它使用紅黑樹結構來對加入的物件進行排序。
看個簡單的例子:
* TreeMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new TreeMap<String, String>();
map.put("justin", "justin's message!!");
map.put("momor", "momor's message!!");
map.put("caterpillar", "caterpillar's message!!");
Collection collection = map.values();
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
由於您加入的是String物件,執行結果會自動依key的字典順序進行排序的動作:
caterpillar's message!!
justin's message!!
momor's message!!
依字典順序排序String物件是TreeMap預設的,如果您對物件有自己的一套排序順序,您要實作一個 Comparator 物件,它有兩個必須實作的方法,compare()與equals(),前者必須傳回整數值,如果物件順序相同則傳回0,傳回正整數表示compare ()方法的第一個物件大於第二個物件,反之則傳回負整數,後者則是定義兩個物件是否相等。
EnumMap
EnumMap是個專為列舉型別設計的類別,方便您使用列舉型別及Map物件,直接來舉個實例:
* EnumMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum Action {TURN_LEFT, TURN_RIGHT, SHOOT}
public class EnumMapDemo {
public static void main(String[] args) {
Map<Action, String> map =
new EnumMap<Action, String>(Action.class);
map.put(Action.TURN_LEFT, "向左轉");
map.put(Action.TURN_RIGHT, "向右轉");
map.put(Action.SHOOT, "射擊");
for(Action action : Action.values( ) ) {
System.out.println(map.get(action));
}
}
}
執行結果:
向左轉
向右轉
射擊
與單純的使用HashMap比較起來的差別是,在上面的程式中,EnumMap將根據列舉的順序來維護物件的排列順序,從下面這個程式可以看個大概:
* EnumMapDemo2.java
package onlyfun.caterpillar;
import java.util.*;
enum Action {TURN_LEFT, TURN_RIGHT, SHOOT}
public class EnumMapDemo2 {
public static void main(String[] args) {
Map<Action, String> map =
new EnumMap<Action, String>(Action.class);
map.put(Action.SHOOT, "射擊");
map.put(Action.TURN_RIGHT, "向右轉");
map.put(Action.TURN_LEFT, "向左轉");
for(String value : map.values( )) {
System.out.println(value);
}
}
}
執行結果:
向左轉
向右轉
射擊
從遍訪的結果可以看出,物件的順序是根據列舉順序來排列的。
物件容器(Container)
物件容器可以幫您持有對象,在Java中分作兩大類:Collection 與 Map。前者可持有各自獨立的物件,後者持有成對的key-value物件。
* Collection 類
Collection 類包括了 List 類與 Set 類,List 以放置物件至容器中的順序來排列物件,Set 類不接受重覆的物件,並有自己的一套排序規則。
o ArrayList
o LinkedList
o HashSet
o TreeSet
o EnumSet
* Map 類
在將物件存入 Map類時,需要配合一把key,您要取回物件時就是根據這把key,Map中的key是唯一的,Map擁有自己的排序機制。
o HashMap
o TreeMap
o EnumMap
ArrayList
ArrayList類別實作了List介面,List介面是Collection介面的子介面,主要增加了根據索引取得物件的方法。
ArrayList使用陣列實作List介面,所以對於快速的隨機取得物件來說,使用ArrayList可以得到較好的效能,不過在移除物件或插入物件時,ArrayList就比較慢(使用 LinkedList 在這方面就好的多)。
來看看一個ArrayList的範例:
* ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String> list = new ArrayList<String>();
System.out.println("輸入名稱(quit結束)");
while(true) {
System.out.print("# ");
String input = scanner.next();
if(input.equals("quit"))
break;
list.add(input);
}
System.out.print("顯示輸入: ");
for(int i = 0; i < list.size(); i++)
System.out.print(list.get(i) + " ");
System.out.println();
}
}
在 J2SE 5.0 之後新增了泛型(Generic)的功能,使用物件容器時建議容器中將儲存的物件型態,如此您的物件在存入容器會被限定為您所宣告的型態,而取出時,也不至於失去原來的型態資訊,可以避免型態轉換時的問題。
使用add()方法可以將一個物件加入ArrayList中,使用size()方法可以傳回目前的ArrayList的長度,使用get()可以傳回指定索引處的物件,使用toArray()可以將ArrayList中的物件轉換為物件陣列。
以下是執行結果:
輸入名稱(quit結束)
# Justin
# caterpillar
# momor
# quit
顯示輸入: Justin caterpillar momor
您可以使用get()方法指定索引值取出物件,然而如果您的目的是要循序取出容器中所有的物件,則您可以使用Iterator類,Iterator類實作 Iterator 模式,實際來看個例子:
* ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String> list = new ArrayList<String>();
System.out.println("輸入名稱(quit結束)");
while(true) {
System.out.print("# ");
String input = scanner.next();
if(input.equals("quit"))
break;
list.add(input);
}
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
iterator()方法會傳回一個Iterator物件,這個物件提供的遍訪的方法,hasNext()方法測試Iterator中是否還有物件,如果有的話,可以使用next()取出。
事實上,在J2SE 5.0您也不必須使用iterator()了,使用增強的for迴圈可以直接遍訪List的所有元素,例如:
* ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String> list = new ArrayList<String>();
System.out.println("輸入名稱(quit結束)");
while(true) {
System.out.print("# ");
String input = scanner.next();
if(input.equals("quit"))
break;
list.add(input);
}
for(String s : list) {
System.out.print(s + " ");
}
System.out.println();
}
}
LinkedList
List類是以物件加入(add)容器的順序來排列它們,如果您的物件加入之後大都是為了取出,而不會常作移除或插入(Insert)的動作,則使用ArrayList,如果您會經常從容器中作移除或插入物件的動作,則使用LinkedList會獲得較好的效能。
LinkedList實作了List介面,並增加了一些移除與插入物件的特定方法,像是addFirst()、addLast()、 getFirst()、getLast()、removeFirst( )、removeLast()等等,由於在插入與移除時有較好的效能,適合拿來實作堆疊(Stack)與佇列(Queue)。
以下實作一個簡單的FILO(First-In, Last-Out)堆疊,可以存入字串:
* StringStack.java
package onlyfun.caterpillar;
import java.util.*;
public class StringStack {
private LinkedList<String> linkedList;
public StringStack() {
linkedList = new LinkedList<String>();
}
public void push(String name) {
linkedList.addFirst(name);
}
public String top() {
return linkedList.getFirst();
}
public String pop() {
return linkedList.removeFirst();
}
public boolean isEmpty() {
return linkedList.isEmpty();
}
}
而對於FIFO(First-In, First-Out)的佇列,我們也可以使用LinkedList來實作:
* StringQueue.java
package onlyfun.caterpillar;
import java.util.*;
public class StringQueue {
private LinkedList<String> linkedList;
public StringQueue() {
linkedList = new LinkedList<String>();
}
public void put(String name) {
linkedList.addFirst(name);
}
public String get() {
return linkedList.removeLast();
}
public boolean isEmpty() {
return linkedList.isEmpty();
}
}
事實上,如果您要使用佇列的功能,您也不用親自實作,在J2SE 5.0中,LinkedList也實作了新加入的java.util.Queue介面,這個介面有五個必須實作的方法:
element() 取得但不移除佇列第一個元件,佇列為空時會丟出例外
offer() 加入一個元素至佇列中
peek() 取得但不移除佇列第一個元件
poll() 取得並移去佇列第一個元件,佇列為空時傳回null
remove() 取得並移除佇列第一個元件
要使用佇列的功能,您只要類似這樣的宣告:
Queue<String> queue = new LinkedList<String>();
HashSet
HashSet實作Set介面,Set介面繼承Collection介面,Set容器中的物件都是唯一的,加入 Set容器中的物件都必須重新定義equals()方法,作為唯一性的識別,Set容器有自己的一套排序規則。
HashSet的排序規則是利用Hash Table,所以加入HashSet容器的物件還必須重新定義hashCode()方法,利用Hash的方式,可以讓您快速的找到容器中的物件,在比較兩個加入Set容器中的物件是否相同時,會先比較hashCode()方法傳回的值是否相同,如果相同,則再使用equals()方法比較,如果兩者都相同,則視為相同的物件。
事實上,在撰寫新的類別時,最好總是重新定義equals()與hashCode()方法,以符合Java的設計規範,您可以參考 Object 類別 中的介紹瞭解如何重新定義equals()與hashCode()。
來看一個例子:
* HashSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("caterpillar");
set.add("justin");
set.add("momor");
set.add("justin");
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
執行結果:
momor justin caterpillar
如上所示的,即使重覆加入了"justin"字串,HashSet中仍只有一個"justin"字串物件,另一個要注意的是,选代所有的值時,其順序與您加入的順序是不一樣的,选代所有值時的順序是HashSet排序過後的順序。
LinkedHashSet是HashSet的子類,它在內部實作使用Hash Code進行排序,然而允許您在列舉時行為像是LinkedList,簡單的改寫上面的程式即可瞭解:
* LinkedHashSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<String>();
set.add("caterpillar");
set.add("justin");
set.add("momor");
set.add("justin");
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
執行結果:
caterpillar justin momor
可以在執行結果中看到的,选代時的順序正是您加入值的順序。
TreeSet
TreeSet實作Set介面與SortedSet介面,提供相關的方法讓您有序的取出對應位置的物件,像是 first()、last()等方法,TreeSet是J2SE中唯一實作SortedSet介面的類別,它使用紅黑樹結構來對加入的物件進行排序。
看個簡單的例子:
* TreeSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
Set<String> set = new TreeSet<String>();
set.add("justin");
set.add("caterpillar");
set.add("momor");
set.add("justin");
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
由於加入的是String物件,執行結果會自動依字典順序進行排序的動作:
caterpillar justin momor
依字典順序排序String物件是TreeSet預設的,如果您對物件有自己的一套排序順序,您要實作一個 Comparator 物件,您要實作compare()方法,它必須傳回整數值,如果物件順序相同則傳回0,傳回正整數表示compare()方法的第一個物件大於第二個物件,反之則傳回負整數。
舉個實際的例子,假設您想要改變TreeSet依字典順序排列加入的物件為相反的順序:
* CustomComparator.java
package onlyfun.caterpillar;
import java.util.Comparator;
public class CustomComparator<T> implements Comparator<T> {
public int compare(T o1, T o2) {
if (((T) o1).equals(o2))
return 0;
return ((Comparable<T>) o1).compareTo((T) o2) * -1;
}
}
在自訂的Comparator中,如果兩個物件的順序相同會傳回0,這在TreeSet中表示兩個物件是同一個物件,TreeSet要求傳入的物件必須實作java.lang.Comparable介面,範例中只是簡單的將原來compareTo()傳回的值乘以負一,如此在TreeSet中就可以簡單的讓排列順序相反。
在建構TreeSet實例時一併指定自訂的Comparator,例如:
* TreeSetDemo2.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeSetDemo2 {
public static void main(String[] args) {
// 自訂Comparator
Comparator<String> comparator =
new CustomComparator<String>();
Set<String> set =
new TreeSet<String>(comparator);
set.add("justin");
set.add("caterpillar");
set.add("momor");
// 使用 enhanced for loop 顯示物件
for(String name : set) {
System.out.print(name + " ");
}
System.out.println();
}
}
執行的結果是相反的:
momor justin caterpillar
EnumSet
EnumSet的名稱說明了其作用,它是在J2SE 5.0後加入的新類別,可以協助您建立列舉值的集合,它提供了一系列的靜態方法,可以讓您指定不同的集合建立方式,例如:
* EnumSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum FontConstant { Plain, Bold, Italic }
public class EnumSetDemo {
public static void main(String[] args) {
EnumSet<FontConstant> enumSet =
EnumSet.of(FontConstant.Plain, FontConstant.Bold);
showEnumSet(enumSet);
showEnumSet(EnumSet.complementOf(enumSet));
}
public static void showEnumSet(
EnumSet<FontConstant> enumSet) {
Iterator iterator = enumSet.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
您可以指定列舉值來加入EnumSet中,of()方法會返回一個EnumSet的實例,當中包括您所指定的列舉值,您也可以使complementOf()指定一個EnumSet的互補集,以下是執行的結果:
Plain Bold
Italic
EnumSet實作了Set介面,所以您可以使用Set介面的所有方法來測試它所包括的列舉值,例如測試一個集合中是否包括 FontConstant.Bold:
if(enumSet.contains(FontConstant.Bold)) {
....
}
您也可以建立一個空的EnumSet,然後自己逐個加入列舉值,例如:
* EnumSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum FontConstant { Plain, Bold, Italic }
public class EnumSetDemo {
public static void main(String[] args) {
EnumSet<FontConstant> enumSet =
EnumSet.noneOf(FontConstant.class);
enumSet.add(FontConstant.Bold);
enumSet.add(FontConstant.Italic);
showEnumSet(enumSet);
}
public static void showEnumSet(
EnumSet<FontConstant> enumSet) {
Iterator iterator = enumSet.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
執行結果:
Bold Italic
您也可以由一個容器物件中建立EnumSet:
List<FontConstant> list = new ArrayList<FontConstant>();
list.add(FontConstant.Bold);
list.add(FontConstant.Italic);
showEnumSet(EnumSet.copyOf(list));
HashMap
HashMap實作Map介面,內部實作使用Hash Table,讓您在常數時間內可以尋得key/value對。
所謂的key/value對,簡單的說,您將Map容器物件當作一個有很多間房間的房子,每個房間的門有一把鑰匙,您將物件儲存至房間中時,要順便擁有一把鑰匙,下次要取回物件時,就是根據這把鑰匙取得。
以一個簡單的例子來作說明:
* HashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new HashMap<String, String>();
map.put("caterpillar", "caterpillar's message!!");
map.put("justin", "justin's message!!");
System.out.println(map.get("justin"));
System.out.println(map.get("caterpillar"));
}
}
在宣告Map型態時,您指定了key/value各自的型態,這邊都是宣告為String,也就是以String物件作為key物件的型態,而 value也是以String物件作為其型態。
使用Map的put()方法將物件存入,必須同時指定key/value,而要取回物件時,則指定key,程式的執行結果如下:
justin's message!!
caterpillar's message!!
HashMap是個被經常使用的物件,您可以參考下面幾個例子中HashMap的應用:
* Command 模式
* Thread-Specific Storage 模式
* 控制器(Servlet)
可以使用values()方法返回一個Collection物件,如果您需要一次选代Map中所有的物件,這會很有用,例如:
* HashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new HashMap<String, String>();
map.put("justin", "justin's message!!");
map.put("momor", "momor's message!!");
map.put("caterpillar", "caterpillar's message!!");
Collection collection = map.values();
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
執行結果:
momor's message!!
justin's message!!
caterpillar's message!!
HashMap使用Hash Table,因而它有自己的排序方式,如果您想要在选代所有的物件時,依照插入的順序來排序,則可以使用LinkedHashMap,它是HashMap 的子類,使用values()所返回的Collection物件,其內含物件之順序即為當初您加入物件之順序,例如:
* LinkedHashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class LinkedHashMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new LinkedHashMap<String, String>();
map.put("justin", "justin's message!!");
map.put("momor", "momor's message!!");
map.put("caterpillar", "caterpillar's message!!");
Collection collection = map.values();
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
執行結果:
justin's message!!
momor's message!!
caterpillar's message!!
TreeMap
TreeMap實作Map介面與SortedMap介面,提供相關的方法讓您有序的取出對應位置的物件,像是 firstKey()、lastKey()等方法,TreeMap是J2SE中唯一實作SortedMap介面的類別,它使用紅黑樹結構來對加入的物件進行排序。
看個簡單的例子:
* TreeMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeMapDemo {
public static void main(String[] args) {
Map<String, String> map =
new TreeMap<String, String>();
map.put("justin", "justin's message!!");
map.put("momor", "momor's message!!");
map.put("caterpillar", "caterpillar's message!!");
Collection collection = map.values();
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
由於您加入的是String物件,執行結果會自動依key的字典順序進行排序的動作:
caterpillar's message!!
justin's message!!
momor's message!!
依字典順序排序String物件是TreeMap預設的,如果您對物件有自己的一套排序順序,您要實作一個 Comparator 物件,它有兩個必須實作的方法,compare()與equals(),前者必須傳回整數值,如果物件順序相同則傳回0,傳回正整數表示compare ()方法的第一個物件大於第二個物件,反之則傳回負整數,後者則是定義兩個物件是否相等。
EnumMap
EnumMap是個專為列舉型別設計的類別,方便您使用列舉型別及Map物件,直接來舉個實例:
* EnumMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum Action {TURN_LEFT, TURN_RIGHT, SHOOT}
public class EnumMapDemo {
public static void main(String[] args) {
Map<Action, String> map =
new EnumMap<Action, String>(Action.class);
map.put(Action.TURN_LEFT, "向左轉");
map.put(Action.TURN_RIGHT, "向右轉");
map.put(Action.SHOOT, "射擊");
for(Action action : Action.values( ) ) {
System.out.println(map.get(action));
}
}
}
執行結果:
向左轉
向右轉
射擊
與單純的使用HashMap比較起來的差別是,在上面的程式中,EnumMap將根據列舉的順序來維護物件的排列順序,從下面這個程式可以看個大概:
* EnumMapDemo2.java
package onlyfun.caterpillar;
import java.util.*;
enum Action {TURN_LEFT, TURN_RIGHT, SHOOT}
public class EnumMapDemo2 {
public static void main(String[] args) {
Map<Action, String> map =
new EnumMap<Action, String>(Action.class);
map.put(Action.SHOOT, "射擊");
map.put(Action.TURN_RIGHT, "向右轉");
map.put(Action.TURN_LEFT, "向左轉");
for(String value : map.values( )) {
System.out.println(value);
}
}
}
執行結果:
向左轉
向右轉
射擊
從遍訪的結果可以看出,物件的順序是根據列舉順序來排列的。
相关推荐
在IT行业中,物件分类是一种常见的数据管理策略,用于有效地组织和检索信息。在这个名为“wuziguanli.rar”的压缩包文件中,我们看到的是一个专门针对“物件分类”设计的系统,它旨在优化物资的分类记录和整理,从而...
### Java基础教学知识点 #### 一、Java的基本语法规则 **1.1 基本数据类型** Java中提供了多种基本数据类型,包括整数类型(`byte`, `short`, `int`, `long`)、浮点数类型(`float`, `double`)、字符类型(`...
**SURF简介** SURF(Speeded Up Robust Features)是一种高效的计算机视觉算法,用于图像中的特征检测、描述和匹配。SURF是SIFT(Scale-Invariant Feature Transform)的优化版本,它在保持SIFT的强大功能的同时,...
物件计数是红外计数器的主要功能,通常涉及以下几个步骤: 1. **初始化**:系统启动时,计数器通常被设定为零。 2. **检测**:红外传感器持续监测其工作区域,当有物体经过时,检测到的信号变化。 3. **信号处理**...
知识点详述: ...通过上述知识点的梳理,我们不仅了解了Java的基础语法和物件导向的特性,还掌握了如何在Java中进行有效的数据管理和程序控制,为进一步深入学习Java和物件导向程式设计奠定了坚实的基础。
本教程将带你逐步进入OOP的大门,从基础开始,逐步深入。 8-1 物件導向與類別 物件導向设计的核心是类(Class)和对象(Object)。类是描述一类具有相同属性和行为的实体的模板或蓝图,而对象则是类的实例。在OOP中...
本资料集“MP31516_Example_UML物件导向系统分析与设计_”旨在深入探讨UML在对象导向系统分析与设计中的应用。 UML的核心概念是通过图形化的方式表达软件系统的结构和行为。它包括多种图表类型,如用例图、类图、...
UML简介-Java2物件导向.pdf
container是Java中的一种容器,用于存储和管理对象。 iterator(迭代器) iterator是Java中的一种迭代器,用于遍历容器中的元素。 linker(连结器) linker是Java中的一种连结器,用于将多个对象连接起来。 ...
Java JDK(Java Development Kit)是Java编程语言的核心组件,包含Java运行环境、编译器、类库以及各种工具,是开发者进行Java程序开发的基础。Java JDK 6.0是Oracle公司发布的一个重要版本,提供了许多新的特性和...
24. 容器(Container):在 Java 中,容器是一种对象,它可以被用来存储其他对象。容器可以用于实现某些特定的功能。 25. 迭代器(Iterator):在 Java 中,迭代器是一种对象,它可以被用来迭代其他对象。迭代器...
酒店管理会所__前厅部物件类资料电子档汇总.pdf
在Java中,物件容器是存储对象的关键结构,分为两大类:Collection和Map。Collection接口包括了List和Set,List如ArrayList和LinkedList,按照添加顺序维护元素,Set如HashSet和TreeSet,不允许重复元素且有特定的...
以3D视觉为基础的物件回想系统.pdf,这是一份不错的文档
在"小飛機惡戰_移動物件"项目中,我们将学习如何实现图片的动态移动,这对于游戏开发或其他需要图形交互的软件来说是非常基础且重要的。 首先,我们需要了解VB6中的基本控件和事件。在VB6中,PictureBox控件是用于...
Java沒有指標 - 淺談參考(Reference)與物件的複製
物件導向資料結構-使用JAVA語言,用於教學用的教程。 教學內容: 第1章:資料結構導論(Introduction) 第2章:陣列與矩陣(Arrays and Matrices) 第3章:鏈結串列(Linked Lists) 第4章:堆疊(Stacks) 第5章:...
6. 抽象类:Android框架中提供了很多抽象类,如AbstractThreadedSyncAdapter,它为创建异步适配器提供了基础结构。开发者可以根据需求覆盖其抽象方法,实现具体功能。 7. 构造器与初始化:在Android应用中,构造器...
2014 InduSoft_基础课程_画面建立&专案测试zip,2014 InduSoft_基础课程_画面建立&专案测试,如何使用Indusoft圖形庫?建立畫面背景?建立時間與日期?建立離開系統物件?建立水槽物件?建立滑動器物件?動態準位長條圖?製作...