[TOC]
# éå½:éå主é¢
> æ¬é彿¯ä¸äºæ¯[第åäºç« éå]()ä¸ä»ç»çæ´é«çº§çå
容ã
## ç¤ºä¾æ°æ®
è¿éå建ä¸äºæ ·æ¬æ°æ®ç¨äºéå示ä¾ã 以䏿°æ®å°é¢è²åç§°ä¸HTMLé¢è²çRGBå¼ç¸å
³èã请注æï¼æ¯ä¸ªé®åå¼é½æ¯å¯ä¸çï¼
```java
// onjava/HTMLColors.java
// Sample data for collection examples
package onjava;
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
public class HTMLColors {
public static final Object[][] ARRAY = {
{ 0xF0F8FF, "AliceBlue" },
{ 0xFAEBD7, "AntiqueWhite" },
{ 0x7FFFD4, "Aquamarine" },
{ 0xF0FFFF, "Azure" },
{ 0xF5F5DC, "Beige" },
{ 0xFFE4C4, "Bisque" },
{ 0x000000, "Black" },
{ 0xFFEBCD, "BlanchedAlmond" },
{ 0x0000FF, "Blue" },
{ 0x8A2BE2, "BlueViolet" },
{ 0xA52A2A, "Brown" },
{ 0xDEB887, "BurlyWood" },
{ 0x5F9EA0, "CadetBlue" },
{ 0x7FFF00, "Chartreuse" },
{ 0xD2691E, "Chocolate" },
{ 0xFF7F50, "Coral" },
{ 0x6495ED, "CornflowerBlue" },
{ 0xFFF8DC, "Cornsilk" },
{ 0xDC143C, "Crimson" },
{ 0x00FFFF, "Cyan" },
{ 0x00008B, "DarkBlue" },
{ 0x008B8B, "DarkCyan" },
{ 0xB8860B, "DarkGoldenRod" },
{ 0xA9A9A9, "DarkGray" },
{ 0x006400, "DarkGreen" },
{ 0xBDB76B, "DarkKhaki" },
{ 0x8B008B, "DarkMagenta" },
{ 0x556B2F, "DarkOliveGreen" },
{ 0xFF8C00, "DarkOrange" },
{ 0x9932CC, "DarkOrchid" },
{ 0x8B0000, "DarkRed" },
{ 0xE9967A, "DarkSalmon" },
{ 0x8FBC8F, "DarkSeaGreen" },
{ 0x483D8B, "DarkSlateBlue" },
{ 0x2F4F4F, "DarkSlateGray" },
{ 0x00CED1, "DarkTurquoise" },
{ 0x9400D3, "DarkViolet" },
{ 0xFF1493, "DeepPink" },
{ 0x00BFFF, "DeepSkyBlue" },
{ 0x696969, "DimGray" },
{ 0x1E90FF, "DodgerBlue" },
{ 0xB22222, "FireBrick" },
{ 0xFFFAF0, "FloralWhite" },
{ 0x228B22, "ForestGreen" },
{ 0xDCDCDC, "Gainsboro" },
{ 0xF8F8FF, "GhostWhite" },
{ 0xFFD700, "Gold" },
{ 0xDAA520, "GoldenRod" },
{ 0x808080, "Gray" },
{ 0x008000, "Green" },
{ 0xADFF2F, "GreenYellow" },
{ 0xF0FFF0, "HoneyDew" },
{ 0xFF69B4, "HotPink" },
{ 0xCD5C5C, "IndianRed" },
{ 0x4B0082, "Indigo" },
{ 0xFFFFF0, "Ivory" },
{ 0xF0E68C, "Khaki" },
{ 0xE6E6FA, "Lavender" },
{ 0xFFF0F5, "LavenderBlush" },
{ 0x7CFC00, "LawnGreen" },
{ 0xFFFACD, "LemonChiffon" },
{ 0xADD8E6, "LightBlue" },
{ 0xF08080, "LightCoral" },
{ 0xE0FFFF, "LightCyan" },
{ 0xFAFAD2, "LightGoldenRodYellow" },
{ 0xD3D3D3, "LightGray" },
{ 0x90EE90, "LightGreen" },
{ 0xFFB6C1, "LightPink" },
{ 0xFFA07A, "LightSalmon" },
{ 0x20B2AA, "LightSeaGreen" },
{ 0x87CEFA, "LightSkyBlue" },
{ 0x778899, "LightSlateGray" },
{ 0xB0C4DE, "LightSteelBlue" },
{ 0xFFFFE0, "LightYellow" },
{ 0x00FF00, "Lime" },
{ 0x32CD32, "LimeGreen" },
{ 0xFAF0E6, "Linen" },
{ 0xFF00FF, "Magenta" },
{ 0x800000, "Maroon" },
{ 0x66CDAA, "MediumAquaMarine" },
{ 0x0000CD, "MediumBlue" },
{ 0xBA55D3, "MediumOrchid" },
{ 0x9370DB, "MediumPurple" },
{ 0x3CB371, "MediumSeaGreen" },
{ 0x7B68EE, "MediumSlateBlue" },
{ 0x00FA9A, "MediumSpringGreen" },
{ 0x48D1CC, "MediumTurquoise" },
{ 0xC71585, "MediumVioletRed" },
{ 0x191970, "MidnightBlue" },
{ 0xF5FFFA, "MintCream" },
{ 0xFFE4E1, "MistyRose" },
{ 0xFFE4B5, "Moccasin" },
{ 0xFFDEAD, "NavajoWhite" },
{ 0x000080, "Navy" },
{ 0xFDF5E6, "OldLace" },
{ 0x808000, "Olive" },
{ 0x6B8E23, "OliveDrab" },
{ 0xFFA500, "Orange" },
{ 0xFF4500, "OrangeRed" },
{ 0xDA70D6, "Orchid" },
{ 0xEEE8AA, "PaleGoldenRod" },
{ 0x98FB98, "PaleGreen" },
{ 0xAFEEEE, "PaleTurquoise" },
{ 0xDB7093, "PaleVioletRed" },
{ 0xFFEFD5, "PapayaWhip" },
{ 0xFFDAB9, "PeachPuff" },
{ 0xCD853F, "Peru" },
{ 0xFFC0CB, "Pink" },
{ 0xDDA0DD, "Plum" },
{ 0xB0E0E6, "PowderBlue" },
{ 0x800080, "Purple" },
{ 0xFF0000, "Red" },
{ 0xBC8F8F, "RosyBrown" },
{ 0x4169E1, "RoyalBlue" },
{ 0x8B4513, "SaddleBrown" },
{ 0xFA8072, "Salmon" },
{ 0xF4A460, "SandyBrown" },
{ 0x2E8B57, "SeaGreen" },
{ 0xFFF5EE, "SeaShell" },
{ 0xA0522D, "Sienna" },
{ 0xC0C0C0, "Silver" },
{ 0x87CEEB, "SkyBlue" },
{ 0x6A5ACD, "SlateBlue" },
{ 0x708090, "SlateGray" },
{ 0xFFFAFA, "Snow" },
{ 0x00FF7F, "SpringGreen" },
{ 0x4682B4, "SteelBlue" },
{ 0xD2B48C, "Tan" },
{ 0x008080, "Teal" },
{ 0xD8BFD8, "Thistle" },
{ 0xFF6347, "Tomato" },
{ 0x40E0D0, "Turquoise" },
{ 0xEE82EE, "Violet" },
{ 0xF5DEB3, "Wheat" },
{ 0xFFFFFF, "White" },
{ 0xF5F5F5, "WhiteSmoke" },
{ 0xFFFF00, "Yellow" },
{ 0x9ACD32, "YellowGreen" },
};
public static final Map MAP =
Arrays.stream(ARRAY)
.collect(Collectors.toMap(
element -> (Integer)element[0],
element -> (String)element[1],
(v1, v2) -> { // Merge function
throw new IllegalStateException();
},
LinkedHashMap::new
));
// Inversion only works if values are unique:
public static Map
invert(Map map) {
return map.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getValue,
Map.Entry::getKey,
(v1, v2) -> {
throw new IllegalStateException();
},
LinkedHashMap::new
));
}
public static final Map
INVMAP = invert(MAP);
// Look up RGB value given a name:
public static Integer rgb(String colorName) {
return INVMAP.get(colorName);
}
public static final List LIST =
Arrays.stream(ARRAY)
.map(item -> (String)item[1])
.collect(Collectors.toList());
public static final List RGBLIST =
Arrays.stream(ARRAY)
.map(item -> (Integer)item[0])
.collect(Collectors.toList());
public static
void show(Map.Entry e) {
System.out.format(
"0x%06X: %s%n", e.getKey(), e.getValue());
}
public static void
show(Map m, int count) {
m.entrySet().stream()
.limit(count)
.forEach(e -> show(e));
}
public static void show(Map m) {
show(m, m.size());
}
public static
void show(Collection lst, int count) {
lst.stream()
.limit(count)
.forEach(System.out::println);
}
public static void show(Collection lst) {
show(lst, lst.size());
}
public static
void showrgb(Collection lst, int count) {
lst.stream()
.limit(count)
.forEach(n -> System.out.format("0x%06X%n", n));
}
public static void showrgb(Collection lst) {
showrgb(lst, lst.size());
}
public static
void showInv(Map m, int count) {
m.entrySet().stream()
.limit(count)
.forEach(e ->
System.out.format(
"%-20s 0x%06X%n", e.getKey(), e.getValue()));
}
public static void showInv(Map m) {
showInv(m, m.size());
}
public static void border() {
System.out.println(
"******************************");
}
}
```
**MAP** æ¯ä½¿ç¨Streamsï¼[第ååç« æµå¼ç¼ç¨]()ï¼å建çã äºç»´æ°ç» **ARRAY** ä½ä¸ºæµä¼ è¾å° **Map** ä¸ï¼ä½è¯·æ³¨ææä»¬ä¸ä»
ä»
æ¯ä½¿ç¨ç®åçæ¬ç `Collectors.toMap()` ã é£ä¸ªçæ¬çæä¸ä¸ª **HashMap** ï¼å®ä½¿ç¨æ£å彿°æ¥æ§å¶å¯¹é®çæåºã 为äºä¿ç忥ç顺åºï¼æä»¬å¿
é¡»å°é®å¼å¯¹ç´æ¥æ¾å
¥ **TreeMap** ä¸ï¼è¿æå³çæä»¬éè¦ä½¿ç¨æ´å¤æç `Collectors.toMap()` çæ¬ãè¿éè¦ä¸¤ä¸ªå½æ°ä»æ¯ä¸ªæµå
ç´ ä¸æåé®åå¼ï¼å°±åç®åçæ¬ç`Collectors.toMap()` 䏿 ·ã ç¶åå®éè¦ä¸ä¸ª*å并彿°*ï¼merge functionï¼ï¼å®è§£å³äºä¸åä¸ä¸ªé®ç¸å
³ç两个å¼ä¹é´çå²çªãè¿éçæ°æ®å·²ç»é¢å
审æ¥è¿ï¼å æ¤ç»ä¸ä¼åçè¿ç§æ
åµï¼å¦ææçè¯ï¼è¿é伿åºå¼å¸¸ãæåï¼ä¼ éçææéç±»åç空mapç彿°ï¼ç¶åç¨æµæ¥å¡«å
å®ã
`rgb()` æ¹æ³æ¯ä¸ä¸ªä¾¿æ·å½æ°ï¼convenience functionï¼ï¼å®æ¥åé¢è²åç§° **String** åæ°å¹¶çæå
¶æ°åRGBå¼ã为æ¤ï¼æä»¬éè¦ä¸ä¸ªåè½¬çæ¬ç **COLORS** ï¼å®æ¥åä¸ä¸ª **String**é®å¹¶æ¥æ¾RGBç **Integer** å¼ã è¿æ¯éè¿ `invert()` æ¹æ³å®ç°çï¼å¦æä»»ä½ **COLORS** å¼ä¸å¯ä¸ï¼åæåºå¼å¸¸ã
æä»¬è¿å建å
嫿æåç§°ç **LIST** ï¼ä»¥åå
å«åå
è¿å¶è¡¨ç¤ºæ³çRGBå¼ç **RGBLIST** ã
第ä¸ä¸ª `show()` æ¹æ³æ¥åä¸ä¸ª **Map.Entry** å¹¶æ¾ç¤ºä»¥åå
è¿å¶è¡¨ç¤ºçé®ï¼ä»¥ä¾¿è½»æ¾å°å¯¹åå§ **ARRAY** è¿è¡å鿣æ¥ã å称以 **show** å¼å¤´çæ¯ä¸ªæ¹æ³é½ä¼éè½½ä¸¤ä¸ªçæ¬ï¼å
¶ä¸ä¸ä¸ªçæ¬éç¨ **count** åæ°æ¥æç¤ºè¦æ¾ç¤ºçå
ç´ æ°éï¼ç¬¬äºä¸ªçæ¬æ¾ç¤ºåºåä¸çææå
ç´ ã
è¿éæ¯ä¸ä¸ªåºæ¬çæµè¯ï¼
```java
// collectiontopics/HTMLColorTest.java
import static onjava.HTMLColors.*;
public class HTMLColorTest {
static final int DISPLAY_SIZE = 20;
public static void main(String[] args) {
show(MAP, DISPLAY_SIZE);
border();
showInv(INVMAP, DISPLAY_SIZE);
border();
show(LIST, DISPLAY_SIZE);
border();
showrgb(RGBLIST, DISPLAY_SIZE);
}
}
/* Output:
0xF0F8FF: AliceBlue
0xFAEBD7: AntiqueWhite
0x7FFFD4: Aquamarine
0xF0FFFF: Azure
0xF5F5DC: Beige
0xFFE4C4: Bisque
0x000000: Black
0xFFEBCD: BlanchedAlmond
0x0000FF: Blue
0x8A2BE2: BlueViolet
0xA52A2A: Brown
0xDEB887: BurlyWood
0x5F9EA0: CadetBlue
0x7FFF00: Chartreuse
0xD2691E: Chocolate
0xFF7F50: Coral
0x6495ED: CornflowerBlue
0xFFF8DC: Cornsilk
0xDC143C: Crimson
0x00FFFF: Cyan
******************************
AliceBlue 0xF0F8FF
AntiqueWhite 0xFAEBD7
Aquamarine 0x7FFFD4
Azure 0xF0FFFF
Beige 0xF5F5DC
Bisque 0xFFE4C4
Black 0x000000
BlanchedAlmond 0xFFEBCD
Blue 0x0000FF
BlueViolet 0x8A2BE2
Brown 0xA52A2A
BurlyWood 0xDEB887
CadetBlue 0x5F9EA0
Chartreuse 0x7FFF00
Chocolate 0xD2691E
Coral 0xFF7F50
CornflowerBlue 0x6495ED
Cornsilk 0xFFF8DC
Crimson 0xDC143C
Cyan 0x00FFFF
******************************
AliceBlue
AntiqueWhite
Aquamarine
Azure
Beige
Bisque
Black
BlanchedAlmond
Blue
BlueViolet
Brown
BurlyWood
CadetBlue
Chartreuse
Chocolate
Coral
CornflowerBlue
Cornsilk
Crimson
Cyan
******************************
0xF0F8FF
0xFAEBD7
0x7FFFD4
0xF0FFFF
0xF5F5DC
0xFFE4C4
0x000000
0xFFEBCD
0x0000FF
0x8A2BE2
0xA52A2A
0xDEB887
0x5F9EA0
0x7FFF00
0xD2691E
0xFF7F50
0x6495ED
0xFFF8DC
0xDC143C
0x00FFFF
*/
```
å¯ä»¥çå°ï¼ä½¿ç¨ **LinkedHashMap** ç¡®å®è½å¤ä¿ç **HTMLColors.ARRAY** ç顺åºã
## Listè¡ä¸º
**Lists** æ¯åå¨åæ£ç´¢å¯¹è±¡ï¼æ¬¡äºæ°ç»ï¼çæåºæ¬æ¹æ³ãåºæ¬å表æä½å
æ¬ï¼
- `add()` ç¨äºæå
¥å
ç´
- `get()` ç¨äºéæºè®¿é®å
ç´
- `iterator()` è·ååºåä¸çä¸ä¸ª **Iterator**
- `stream()` çæå
ç´ çä¸ä¸ª **Stream**
å表æé æ¹æ³å§ç»ä¿çå
ç´ çæ·»å 顺åºã
以ä¸ç¤ºä¾ä¸çæ¹æ³åèªæ¶µçäºä¸ç»ä¸åçè¡ä¸ºï¼æ¯ä¸ª **List** å¯ä»¥æ§è¡çæä½ï¼ `basicTest()` ï¼ï¼ä½¿ç¨ **Iterator** ï¼ `iterMotion()` ï¼éååºåï¼ä½¿ç¨ **Iterator** ï¼ `iterManipulation()` ï¼æ´æ¹å
å®¹ï¼æ¥ç **List** æä½ï¼ `testVisual()` ï¼çææï¼ä»¥åä»
å¯ç¨äº **LinkedLists** çæä½ï¼
```java
// collectiontopics/ListOps.java
// Things you can do with Lists
import java.util.*;
import onjava.HTMLColors;
public class ListOps {
// Create a short list for testing:
static final List LIST =
HTMLColors.LIST.subList(0, 10);
private static boolean b;
private static String s;
private static int i;
private static Iterator it;
private static ListIterator lit;
public static void basicTest(List a) {
a.add(1, "x"); // Add at location 1
a.add("x"); // Add at end
// Add a collection:
a.addAll(LIST);
// Add a collection starting at location 3:
a.addAll(3, LIST);
b = a.contains("1"); // Is it in there?
// Is the entire collection in there?
b = a.containsAll(LIST);
// Lists allow random access, which is cheap
// for ArrayList, expensive for LinkedList:
s = a.get(1); // Get (typed) object at location 1
i = a.indexOf("1"); // Tell index of object
b = a.isEmpty(); // Any elements inside?
it = a.iterator(); // Ordinary Iterator
lit = a.listIterator(); // ListIterator
lit = a.listIterator(3); // Start at location 3
i = a.lastIndexOf("1"); // Last match
a.remove(1); // Remove location 1
a.remove("3"); // Remove this object
a.set(1, "y"); // Set location 1 to "y"
// Keep everything that's in the argument
// (the intersection of the two sets):
a.retainAll(LIST);
// Remove everything that's in the argument:
a.removeAll(LIST);
i = a.size(); // How big is it?
a.clear(); // Remove all elements
}
public static void iterMotion(List a) {
ListIterator it = a.listIterator();
b = it.hasNext();
b = it.hasPrevious();
s = it.next();
i = it.nextIndex();
s = it.previous();
i = it.previousIndex();
}
public static void iterManipulation(List a) {
ListIterator it = a.listIterator();
it.add("47");
// Must move to an element after add():
it.next();
// Remove the element after the new one:
it.remove();
// Must move to an element after remove():
it.next();
// Change the element after the deleted one:
it.set("47");
}
public static void testVisual(List a) {
System.out.println(a);
List b = LIST;
System.out.println("b = " + b);
a.addAll(b);
a.addAll(b);
System.out.println(a);
// Insert, remove, and replace elements
// using a ListIterator:
ListIterator x =
a.listIterator(a.size()/2);
x.add("one");
System.out.println(a);
System.out.println(x.next());
x.remove();
System.out.println(x.next());
x.set("47");
System.out.println(a);
// Traverse the list backwards:
x = a.listIterator(a.size());
while(x.hasPrevious())
System.out.print(x.previous() + " ");
System.out.println();
System.out.println("testVisual finished");
}
// There are some things that only LinkedLists can do:
public static void testLinkedList() {
LinkedList ll = new LinkedList<>();
ll.addAll(LIST);
System.out.println(ll);
// Treat it like a stack, pushing:
ll.addFirst("one");
ll.addFirst("two");
System.out.println(ll);
// Like "peeking" at the top of a stack:
System.out.println(ll.getFirst());
// Like popping a stack:
System.out.println(ll.removeFirst());
System.out.println(ll.removeFirst());
// Treat it like a queue, pulling elements
// off the tail end:
System.out.println(ll.removeLast());
System.out.println(ll);
}
public static void main(String[] args) {
// Make and fill a new list each time:
basicTest(new LinkedList<>(LIST));
basicTest(new ArrayList<>(LIST));
iterMotion(new LinkedList<>(LIST));
iterMotion(new ArrayList<>(LIST));
iterManipulation(new LinkedList<>(LIST));
iterManipulation(new ArrayList<>(LIST));
testVisual(new LinkedList<>(LIST));
testLinkedList();
}
}
/* Output:
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
b = [AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige, one,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
Bisque
Black
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige, one,
47, BlanchedAlmond, Blue, BlueViolet, AliceBlue,
AntiqueWhite, Aquamarine, Azure, Beige, Bisque, Black,
BlanchedAlmond, Blue, BlueViolet]
BlueViolet Blue BlanchedAlmond Black Bisque Beige Azure
Aquamarine AntiqueWhite AliceBlue BlueViolet Blue
BlanchedAlmond 47 one Beige Azure Aquamarine
AntiqueWhite AliceBlue BlueViolet Blue BlanchedAlmond
Black Bisque Beige Azure Aquamarine AntiqueWhite
AliceBlue
testVisual finished
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
[two, one, AliceBlue, AntiqueWhite, Aquamarine, Azure,
Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
two
two
one
BlueViolet
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
Bisque, Black, BlanchedAlmond, Blue]
*/
```
å¨ `basicTest()` å `iterMotion()` ä¸ï¼æ¹æ³è°ç¨æ¯ä¸ºäºå±ç¤ºæ£ç¡®çè¯æ³ï¼å°½ç®¡è·åäºè¿åå¼ï¼ä½ä¸ä¼ä½¿ç¨å®ãå¨æäºæ
åµä¸ï¼æ ¹æ¬ä¸ä¼å»è·åè¿åå¼ãå¨ä½¿ç¨è¿äºæ¹æ³ä¹åï¼è¯·æ¥çJDKææ¡£ä¸è¿äºæ¹æ³ç宿´ç¨æ³ã
## Setè¡ä¸º
**Set** ç主è¦ç¨å¤æ¯æµè¯æå身份ï¼ä¸è¿ä¹å¯ä»¥å°å
¶ç¨ä½å é¤éå¤å
ç´ çå·¥å
·ã妿ä¸å
³å¿å
ç´ é¡ºåºæå¹¶åæ§ï¼ **HashSet** æ»æ¯æå¥½çéæ©ï¼å ä¸ºå®æ¯ä¸é¨ä¸ºäºå¿«éæ¥æ¾è设计çï¼è¿é使ç¨äºå¨[éå½ï¼çè§£equalsåhashCodeæ¹æ³]()ç« è䏿¢è®¨çæ£å彿°ï¼ã
å
¶å®ç **Set** å®ç°äº§çä¸åçæåºè¡ä¸ºï¼
```java
// collectiontopics/SetOrder.java
import java.util.*;
import onjava.HTMLColors;
public class SetOrder {
static String[] sets = {
"java.util.HashSet",
"java.util.TreeSet",
"java.util.concurrent.ConcurrentSkipListSet",
"java.util.LinkedHashSet",
"java.util.concurrent.CopyOnWriteArraySet",
};
static final List RLIST =
new ArrayList<>(HTMLColors.LIST);
static {
Collections.reverse(RLIST);
}
public static void
main(String[] args) throws Exception {
for(String type: sets) {
System.out.format("[-> %s <-]%n",
type.substring(type.lastIndexOf('.') + 1));
@SuppressWarnings("unchecked")
Set set = (Set)
Class.forName(type).newInstance();
set.addAll(RLIST);
set.stream()
.limit(10)
.forEach(System.out::println);
}
}
}
/* Output:
[-> HashSet <-]
MediumOrchid
PaleGoldenRod
Sienna
LightSlateGray
DarkSeaGreen
Black
Gainsboro
Orange
LightCoral
DodgerBlue
[-> TreeSet <-]
AliceBlue
AntiqueWhite
Aquamarine
Azure
Beige
Bisque
Black
BlanchedAlmond
Blue
BlueViolet
[-> ConcurrentSkipListSet <-]
AliceBlue
AntiqueWhite
Aquamarine
Azure
Beige
Bisque
Black
BlanchedAlmond
Blue
BlueViolet
[-> LinkedHashSet <-]
YellowGreen
Yellow
WhiteSmoke
White
Wheat
Violet
Turquoise
Tomato
Thistle
Teal
[-> CopyOnWriteArraySet <-]
YellowGreen
Yellow
WhiteSmoke
White
Wheat
Violet
Turquoise
Tomato
Thistle
Teal
*/
```
è¿ééè¦ä½¿ç¨ **@SuppressWarnings(âuncheckedâ)** ï¼å 为è¿éå°ä¸ä¸ª **String** ï¼å¯è½æ¯ä»»ä½ä¸è¥¿ï¼ä¼ éç»äº `Class.forName(type).newInstance()` ãç¼è¯å¨å¹¶ä¸è½ä¿è¯è¿æ¯ä¸æ¬¡æåçæä½ã
**RLIST** æ¯ **HTMLColors.LIST** çåè½¬çæ¬ãå 为 `Collections.reverse()` æ¯éè¿ä¿®æ¹åæ°æ¥æ§è¡ååæä½ï¼è䏿¯è¿åå
å«ååå
ç´ çæ° **List** ï¼æä»¥è¯¥è°ç¨å¨ **static** åå
æ§è¡ã **RLIST** å¯ä»¥é²æ¢æä»¬æå¤å°è®¤ä¸º **Set** 对å
¶ç»æè¿è¡äºæåºã
**HashSet** çè¾åºç»æä¼¼ä¹æ²¡æå¯è¾¨å«ç顺åºï¼å ä¸ºå®æ¯åºäºæ£å彿°çã **TreeSet** å **ConcurrentSkipListSet** é½å¯¹å®ä»¬çå
ç´ è¿è¡äºæåºï¼å®ä»¬é½å®ç°äº **SortedSet** æ¥å£æ¥æ è¯è¿ä¸ªç¹ç¹ãå 为å®ç°è¯¥æ¥å£ç **Set** æé¡ºåºæåï¼æä»¥è¯¥æ¥å£è¿æä¸äºå
¶ä»çå¯ç¨æä½ã **LinkedHashSet** å **CopyOnWriteArraySet** 尽管没æç¨äºæ è¯çæ¥å£ï¼ä½å®ä»¬è¿æ¯ä¿çäºå
ç´ çæå
¥é¡ºåºã
**ConcurrentSkipListSet** å **CopyOnWriteArraySet** æ¯çº¿ç¨å®å
¨çã
å¨éå½çæåï¼æä»¬å°äºè§£å¨é **HashSet** å®ç°ç **Set** 䏿·»å é¢å¤æåºçæ§è½ææ¬ï¼ä»¥åä¸åå®ç°ä¸çä»»ä½å
¶ä»åè½çææ¬ã
## å¨Mapä¸ä½¿ç¨å½æ°å¼æä½
ä¸ **Collection** æ¥å£ä¸æ ·ï¼`forEach()` ä¹å
ç½®å¨ **Map** æ¥å£ä¸ã使¯å¦ææ³è¦æ§è¡ä»»ä½å
¶ä»çåºæ¬åè½æä½ï¼æ¯å¦ `map()` ï¼`flatMap()` ï¼`reduce()` æ `filter()` æ¶ï¼è¯¥æä¹åï¼ æ¥ç **Map** æ¥å£åç°å¹¶æ²¡æè¿äºã
å¯ä»¥éè¿ `entrySet()` è¿æ¥å°è¿äºæ¹æ³ï¼è¯¥æ¹æ³ä¼çæä¸ä¸ªç± **Map.Entry** å¯¹è±¡ç»æç **Set** ãè¿ä¸ª **Set** å
å« `stream()` å `parallelStream()` æ¹æ³ãåªéè¦è®°ä½ä¸ä»¶äºï¼è¿éæ£å¨ä½¿ç¨çæ¯ **Map.Entry** 对象ï¼
```java
// collectiontopics/FunctionalMap.java
// Functional operations on a Map
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
import static onjava.HTMLColors.*;
public class FunctionalMap {
public static void main(String[] args) {
MAP.entrySet().stream()
.map(Map.Entry::getValue)
.filter(v -> v.startsWith("Dark"))
.map(v -> v.replaceFirst("Dark", "Hot"))
.forEach(System.out::println);
}
}
/* Output:
HotBlue
HotCyan
HotGoldenRod
HotGray
HotGreen
HotKhaki
HotMagenta
HotOliveGreen
HotOrange
HotOrchid
HotRed
HotSalmon
HotSeaGreen
HotSlateBlue
HotSlateGray
HotTurquoise
HotViolet
*/
```
çæ **Stream** åï¼ææçåºæ¬åè½æ¹æ³ï¼çè³æ´å¤å°±é½å¯ä»¥ä½¿ç¨äºã
## éæ©Mapçæ®µ
ç± **TreeMap** å **ConcurrentSkipListMap** å®ç°ç **NavigableMap** æ¥å£è§£å³äºéè¦éæ©Mapçæ®µçé®é¢ãä¸é¢æ¯ä¸ä¸ªç¤ºä¾ï¼ä½¿ç¨äº **HTMLColors** ï¼
```java
// collectiontopics/NavMap.java
// NavigableMap produces pieces of a Map
import java.util.*;
import java.util.concurrent.*;
import static onjava.HTMLColors.*;
public class NavMap {
public static final
NavigableMap COLORS =
new ConcurrentSkipListMap<>(MAP);
public static void main(String[] args) {
show(COLORS.firstEntry());
border();
show(COLORS.lastEntry());
border();
NavigableMap toLime =
COLORS.headMap(rgb("Lime"), true);
show(toLime);
border();
show(COLORS.ceilingEntry(rgb("DeepSkyBlue") - 1));
border();
show(COLORS.floorEntry(rgb("DeepSkyBlue") - 1));
border();
show(toLime.descendingMap());
border();
show(COLORS.tailMap(rgb("MistyRose"), true));
border();
show(COLORS.subMap(
rgb("Orchid"), true,
rgb("DarkSalmon"), false));
}
}
/* Output:
0x000000: Black
******************************
0xFFFFFF: White
******************************
0x000000: Black
0x000080: Navy
0x00008B: DarkBlue
0x0000CD: MediumBlue
0x0000FF: Blue
0x006400: DarkGreen
0x008000: Green
0x008080: Teal
0x008B8B: DarkCyan
0x00BFFF: DeepSkyBlue
0x00CED1: DarkTurquoise
0x00FA9A: MediumSpringGreen
0x00FF00: Lime
******************************
0x00BFFF: DeepSkyBlue
******************************
0x008B8B: DarkCyan
******************************
0x00FF00: Lime
0x00FA9A: MediumSpringGreen
0x00CED1: DarkTurquoise
0x00BFFF: DeepSkyBlue
0x008B8B: DarkCyan
0x008080: Teal
0x008000: Green
0x006400: DarkGreen
0x0000FF: Blue
0x0000CD: MediumBlue
0x00008B: DarkBlue
0x000080: Navy
0x000000: Black
******************************
0xFFE4E1: MistyRose
0xFFEBCD: BlanchedAlmond
0xFFEFD5: PapayaWhip
0xFFF0F5: LavenderBlush
0xFFF5EE: SeaShell
0xFFF8DC: Cornsilk
0xFFFACD: LemonChiffon
0xFFFAF0: FloralWhite
0xFFFAFA: Snow
0xFFFF00: Yellow
0xFFFFE0: LightYellow
0xFFFFF0: Ivory
0xFFFFFF: White
******************************
0xDA70D6: Orchid
0xDAA520: GoldenRod
0xDB7093: PaleVioletRed
0xDC143C: Crimson
0xDCDCDC: Gainsboro
0xDDA0DD: Plum
0xDEB887: BurlyWood
0xE0FFFF: LightCyan
0xE6E6FA: Lavender
*/
```
å¨ä¸»æ¹æ³ä¸å¯ä»¥çå° **NavigableMap** çåç§åè½ã å 为 **NavigableMap** å
·æé®é¡ºåºï¼æä»¥å®ä½¿ç¨äº `firstEntry()` å `lastEntry()` çæ¦å¿µãè°ç¨ `headMap()` ä¼çæä¸ä¸ª **NavigableMap** ï¼å
¶ä¸å
å«äºä» **Map** çå¼å¤´å° `headMap()` 忰䏿æåçä¸ç»å
ç´ ï¼å
¶ä¸ **boolean** å¼æç¤ºç»æä¸æ¯å¦å
å«è¯¥åæ°ãè°ç¨ `tailMap()` æ§è¡äºç±»ä¼¼çæä½ï¼åªä¸è¿æ¯ä»åæ°å¼å§å° **Map** çæ«å°¾ã `subMap()` åå
è®¸çæ **Map** ä¸é´çä¸é¨åã
`ceilingEntry()` ä»å½åé®å¼å¯¹åä¸æç´¢ä¸ä¸ä¸ªé®å¼å¯¹ï¼`floorEntry()` 忝åä¸æç´¢ã `descendingMap()` åè½¬äº **NavigableMap** ç顺åºã
妿éè¦éè¿åå² **Map** æ¥ç®åææ£å¨è§£å³çé®é¢ï¼å **NavigableMap** å¯ä»¥åå°ãå
·æç±»ä¼¼çåè½çå
¶å®éåå®ç°ä¹å¯ä»¥ç¨æ¥å¸®å©è§£å³é®é¢ã
## å¡«å
éå
ä¸ **Arrays** 䏿 ·ï¼è¿éæä¸ä¸ªå为 **Collections** çä¼´éç±»ï¼companion classï¼ï¼å
å«äºä¸äº **static** çå®ç¨æ¹æ³ï¼å
¶ä¸å
æ¬ä¸ä¸ªå为 `fill()` çæ¹æ³ã `fill()` åªå¤å¶æ´ä¸ªéåä¸çå个对象å¼ç¨ãæ¤å¤ï¼å®ä»
éç¨äº **List** 对象ï¼ä½ç»æå表å¯ä»¥ä¼ éç»æé æ¹æ³æ `addAll()` æ¹æ³ï¼
```java
// collectiontopics/FillingLists.java
// Collections.fill() & Collections.nCopies()
import java.util.*;
class StringAddress {
private String s;
StringAddress(String s) { this.s = s; }
@Override
public String toString() {
return super.toString() + " " + s;
}
}
public class FillingLists {
public static void main(String[] args) {
List list = new ArrayList<>(
Collections.nCopies(4,
new StringAddress("Hello")));
System.out.println(list);
Collections.fill(list,
new StringAddress("World!"));
System.out.println(list);
}
}
/* Output:
[StringAddress@15db9742 Hello, StringAddress@15db9742
Hello, StringAddress@15db9742 Hello,
StringAddress@15db9742 Hello]
[StringAddress@6d06d69c World!, StringAddress@6d06d69c
World!, StringAddress@6d06d69c World!,
StringAddress@6d06d69c World!]
*/
```
è¿ä¸ªç¤ºä¾å±ç¤ºäºä¸¤ç§ä½¿ç¨å¯¹å个对象çå¼ç¨æ¥å¡«å
**Collection** çæ¹æ³ã 第ä¸ä¸ªï¼ `Collections.nCopies()` ï¼å建ä¸ä¸ª **List**ï¼å¹¶ä¼ éç» **ArrayList** çæé æ¹æ³ï¼è¿èå¡«å
äº **ArrayList** ã
**StringAddress** ä¸ç `toString()` æ¹æ³è°ç¨äº `Object.toString()` ï¼å®å
çæç±»åï¼åè·ç对象çåå¸ç çæ ç¬¦å·åå
è¿å¶è¡¨ç¤ºï¼åå¸åç± `hashCode()` æ¹æ³çæï¼ã è¾åºæ¾ç¤ºææçå¼ç¨é½æååä¸ä¸ªå¯¹è±¡ãè°ç¨ç¬¬äºä¸ªæ¹æ³ `Collections.fill()` å乿¯å¦æ¤ã `fill()` æ¹æ³çç¨å¤é常æéï¼å®åªè½æ¿æ¢ **List** ä¸å·²æçå
ç´ ,èä¸ä¸ä¼æ·»å æ°å
ç´ ï¼
### ä½¿ç¨ Suppliers å¡«å
éå
[第äºåç« æ³å]()ç« èä¸ä»ç»ç **onjava.Suppliers** 类为填å
éåæä¾äºéç¨è§£å³æ¹æ¡ã è¿æ¯ä¸ä¸ªä½¿ç¨ **Suppliers** åå§åå ç§ä¸åç±»åç **Collection** ç示ä¾ï¼
```java
// collectiontopics/SuppliersCollectionTest.java
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import onjava.*;
class Government implements Supplier {
static String[] foundation = (
"strange women lying in ponds " +
"distributing swords is no basis " +
"for a system of government").split(" ");
private int index;
@Override
public String get() {
return foundation[index++];
}
}
public class SuppliersCollectionTest {
public static void main(String[] args) {
// Suppliers class from the Generics chapter:
Set set = Suppliers.create(
LinkedHashSet::new, new Government(), 15);
System.out.println(set);
List list = Suppliers.create(
LinkedList::new, new Government(), 15);
System.out.println(list);
list = new ArrayList<>();
Suppliers.fill(list, new Government(), 15);
System.out.println(list);
// Or we can use Streams:
set = Arrays.stream(Government.foundation)
.collect(Collectors.toSet());
System.out.println(set);
list = Arrays.stream(Government.foundation)
.collect(Collectors.toList());
System.out.println(list);
list = Arrays.stream(Government.foundation)
.collect(Collectors
.toCollection(LinkedList::new));
System.out.println(list);
set = Arrays.stream(Government.foundation)
.collect(Collectors
.toCollection(LinkedHashSet::new));
System.out.println(set);
}
}
/* Output:
[strange, women, lying, in, ponds, distributing,
swords, is, no, basis, for, a, system, of, government]
[strange, women, lying, in, ponds, distributing,
swords, is, no, basis, for, a, system, of, government]
[strange, women, lying, in, ponds, distributing,
swords, is, no, basis, for, a, system, of, government]
[ponds, no, a, in, swords, for, is, basis, strange,
system, government, distributing, of, women, lying]
[strange, women, lying, in, ponds, distributing,
swords, is, no, basis, for, a, system, of, government]
[strange, women, lying, in, ponds, distributing,
swords, is, no, basis, for, a, system, of, government]
[strange, women, lying, in, ponds, distributing,
swords, is, no, basis, for, a, system, of, government]
*/
```
**LinkedHashSet** ä¸ççå
ç´ ææå
¥é¡ºåºæåï¼å 为å®ç»´æ¤ä¸ä¸ªé¾è¡¨æ¥ä¿å该顺åºã
使¯è¯·æ³¨æç¤ºä¾ç第äºé¨åï¼å¤§å¤æ°æ
åµä¸é½å¯ä»¥ä½¿ç¨ **Stream** æ¥å建åå¡«å
**Collection** ã卿¬ä¾ä¸ç **Stream** çæ¬ä¸éè¦å£°æ **Supplier** ææ³è¦å建çå
ç´ æ°é;ï¼å®ç´æ¥å¸æ¶äº **Stream** ä¸çææå
ç´ ã
å°½å¯è½ä¼å
éæ© **Stream** æ¥è§£å³é®é¢ã
### Map Suppliers
ä½¿ç¨ **Supplier** æ¥å¡«å
**Map** æ¶éè¦ä¸ä¸ª **Pair** ç±»ï¼å ä¸ºæ¯æ¬¡è°ç¨ä¸ä¸ª **Supplier** ç `get()` æ¹æ³æ¶ï¼é½å¿
é¡»çæä¸å¯¹å¯¹è±¡ï¼ä¸ä¸ªé®åä¸ä¸ªå¼ï¼ï¼
```java
// onjava/Pair.java
package onjava;
public class Pair {
public final K key;
public final V value;
public Pair(K k, V v) {
key = k;
value = v;
}
public K key() { return key; }
public V value() { return value; }
public static Pair make(K k, V v) {
return new Pair(k, v);
}
}
```
**Pair** æ¯ä¸ä¸ªåªè¯»ç *æ°æ®ä¼ è¾å¯¹è±¡* ï¼Data Transfer Objectï¼æ *信使* ï¼Messengerï¼ã è¿ä¸[第äºåç« æ³å]()ç« èä¸ç **Tuple2** åºæ¬ç¸åï¼ä½ååæ´éå **Map** åå§åãæè¿æ·»å äºéæç `make()` æ¹æ³ï¼ä»¥ä¾¿ä¸ºå建 **Pair** 对象æä¾ä¸ä¸ªæ´ç®æ´çååã
Java 8 ç **Stream** æä¾äºå¡«å
**Map** çä¾¿æ·æ¹æ³ï¼
```java
// collectiontopics/StreamFillMaps.java
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import onjava.*;
class Letters
implements Supplier> {
private int number = 1;
private char letter = 'A';
@Override
public Pair get() {
return new Pair<>(number++, "" + letter++);
}
}
public class StreamFillMaps {
public static void main(String[] args) {
Map m =
Stream.generate(new Letters())
.limit(11)
.collect(Collectors
.toMap(Pair::key, Pair::value));
System.out.println(m);
// Two separate Suppliers:
Rand.String rs = new Rand.String(3);
Count.Character cc = new Count.Character();
Map mcs = Stream.generate(
() -> Pair.make(cc.get(), rs.get()))
.limit(8)
.collect(Collectors
.toMap(Pair::key, Pair::value));
System.out.println(mcs);
// A key Supplier and a single value:
Map mcs2 = Stream.generate(
() -> Pair.make(cc.get(), "Val"))
.limit(8)
.collect(Collectors
.toMap(Pair::key, Pair::value));
System.out.println(mcs2);
}
}
/* Output:
{1=A, 2=B, 3=C, 4=D, 5=E, 6=F, 7=G, 8=H, 9=I, 10=J,
11=K}
{b=btp, c=enp, d=ccu, e=xsz, f=gvg, g=mei, h=nne,
i=elo}
{p=Val, q=Val, j=Val, k=Val, l=Val, m=Val, n=Val,
o=Val}
*/
```
ä¸é¢ç示ä¾ä¸åºç°äºä¸ä¸ªæ¨¡å¼ï¼å¯ä»¥ä½¿ç¨å®æ¥å建ä¸ä¸ªèªå¨å建åå¡«å
**Map** çå·¥å
·ï¼
```java
// onjava/FillMap.java
package onjava;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class FillMap {
public static Map
basic(Supplier> pairGen, int size) {
return Stream.generate(pairGen)
.limit(size)
.collect(Collectors
.toMap(Pair::key, Pair::value));
}
public static Map
basic(Supplier keyGen,
Supplier valueGen, int size) {
return Stream.generate(
() -> Pair.make(keyGen.get(), valueGen.get()))
.limit(size)
.collect(Collectors
.toMap(Pair::key, Pair::value));
}
public static >
M create(Supplier keyGen,
Supplier valueGen,
Supplier mapSupplier, int size) {
return Stream.generate( () ->
Pair.make(keyGen.get(), valueGen.get()))
.limit(size)
.collect(Collectors
.toMap(Pair::key, Pair::value,
(k, v) -> k, mapSupplier));
}
}
```
basic() æ¹æ³çæä¸ä¸ªé»è®¤ç **Map** ï¼è `create()` æ¹æ³å
许æå®ä¸ä¸ªç¡®åç **Map** ç±»åï¼å¹¶è¿åé£ä¸ªç¡®åçç±»åã
ä¸é¢æ¯ä¸ä¸ªæµè¯ï¼
```java
// collectiontopics/FillMapTest.java
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import onjava.*;
public class FillMapTest {
public static void main(String[] args) {
Map mcs = FillMap.basic(
new Rand.String(4), new Count.Integer(), 7);
System.out.println(mcs);
HashMap hashm =
FillMap.create(new Rand.String(4),
new Count.Integer(), HashMap::new, 7);
System.out.println(hashm);
LinkedHashMap linkm =
FillMap.create(new Rand.String(4),
new Count.Integer(), LinkedHashMap::new, 7);
System.out.println(linkm);
}
}
/* Output:
{npcc=1, ztdv=6, gvgm=3, btpe=0, einn=4, eelo=5,
uxsz=2}
{npcc=1, ztdv=6, gvgm=3, btpe=0, einn=4, eelo=5,
uxsz=2}
{btpe=0, npcc=1, uxsz=2, gvgm=3, einn=4, eelo=5,
ztdv=6}
*/
```
## 使ç¨äº«å
ï¼Flyweightï¼èªå®ä¹CollectionåMap
æ¬èä»ç»å¦ä½å建èªå®ä¹ **Collection** å **Map** å®ç°ãæ¯ä¸ª **java.util** ä¸çéå齿èªå·±ç **Abstract** ç±»ï¼å®æä¾äºè¯¥éåçé¨åå®ç°ï¼å æ¤åªéè¦å®ç°å¿
è¦çæ¹æ³æ¥çææéçéåãä½ å°çå°éè¿ç»§æ¿ **java.util.Abstract** ç±»æ¥å建èªå®ä¹ **Map** å **Collection** æ¯å¤ä¹ç®åãä¾å¦ï¼è¦å建ä¸ä¸ªåªè¯»ç **Set** ï¼åå¯ä»¥ä» **AbstractSet** ç»§æ¿å¹¶å®ç° `iterator()` å `size()` ãæåä¸ä¸ªç¤ºä¾æ¯çææµè¯æ°æ®çå¦ä¸ç§æ¹æ³ãçæçéåé常æ¯åªè¯»çï¼å¹¶ä¸ææä¾çæ¹æ³æå°ã
è¯¥è§£å³æ¹æ¡è¿æ¼ç¤ºäº *享å
* ï¼Flyweightï¼è®¾è®¡æ¨¡å¼ã彿®éè§£å³æ¹æ¡éè¦å¤ªå¤å¯¹è±¡æ¶ï¼æè
å½çææ®é对象å ç¨å¤ªå¤ç©ºé´æ¶ï¼å¯ä»¥ä½¿ç¨äº«å
ã享å
设计模å¼å°å¯¹è±¡çä¸é¨åå¤é¨åï¼externalizesï¼ãç¸æ¯äºæå¯¹è±¡çææå
容é½å
å«å¨å¯¹è±¡ä¸ï¼è¿æ ·å使å¾å¯¹è±¡çé¨åæè
å
¨é¨å¯ä»¥å¨æ´ææçå¤é¨è¡¨ä¸æ¥æ¾ï¼æéè¿ä¸äºèç空é´çå
¶ä»è®¡ç®çæã
ä¸é¢æ¯ä¸ä¸ªå¯ä»¥æ¯ä»»ä½å¤§å°ç **List** ï¼å¹¶ä¸ï¼ææå°ï¼ä½¿ç¨ **Integer** æ°æ®è¿è¡é¢åå§åãè¦ä» **AbstractList** å建åªè¯» **List** ï¼å¿
é¡»å®ç° `get()` å `size()`ï¼
```java
// onjava/CountingIntegerList.java
// List of any length, containing sample data
// {java onjava.CountingIntegerList}
package onjava;
import java.util.*;
public class CountingIntegerList
extends AbstractList {
private int size;
public CountingIntegerList() { size = 0; }
public CountingIntegerList(int size) {
this.size = size < 0 ? 0 : size;
}
@Override
public Integer get(int index) {
return index;
}
@Override
public int size() { return size; }
public static void main(String[] args) {
List cil =
new CountingIntegerList(30);
System.out.println(cil);
System.out.println(cil.get(500));
}
}
/* Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
500
*/
```
åªæå½æ³è¦éå¶ **List** çé¿åº¦æ¶ï¼ **size** 弿æ¯éè¦çï¼å°±åå¨ä¸»æ¹æ³ä¸é£æ ·ãå³ä½¿å¨è¿ç§æ
åµä¸ï¼ `get()` ä¹ä¼äº§çä»»ä½å¼ã
è¿ä¸ªç±»æ¯äº«å
模å¼çä¸ä¸ªç®æ´çä¾åãå½éè¦çæ¶åï¼ `get()` â计ç®âæéçå¼ï¼å æ¤æ²¡å¿
è¦åå¨ååå§åå®é
çåºå± **List** ç»æã
å¨å¤§å¤æ°ç¨åºä¸ï¼è¿éæä¿åçåå¨ç»ææ°¸è¿é½ä¸ä¼æ¹åã使¯ï¼å®å
许ç¨é常大ç **index** æ¥è°ç¨ `List.get()` ï¼è **List** å¹¶ä¸éè¦å¡«å
å°è¿ä¹å¤§ãæ¤å¤ï¼è¿å¯ä»¥å¨ç¨åºä¸å¤§éä½¿ç¨ **CountingIntegerLists** èæ éæ
å¿åå¨é®é¢ãå®é
ä¸ï¼äº«å
çä¸ä¸ªå¥½å¤æ¯å®å
è®¸ä½¿ç¨æ´å¥½çæ½è±¡èä¸ç¨æ
å¿èµæºã
å¯ä»¥ä½¿ç¨äº«å
è®¾è®¡æ¨¡å¼æ¥å®ç°å
·æä»»ä½å¤§å°æ°æ®éçå
¶ä»âåå§åâèªå®ä¹éåãä¸é¢æ¯ä¸ä¸ª **Map** ï¼å®ä¸ºæ¯ä¸ä¸ª **Integer** é®äº§çå¯ä¸çå¼ï¼
```java
// onjava/CountMap.java
// Unlimited-length Map containing sample data
// {java onjava.CountMap}
package onjava;
import java.util.*;
import java.util.stream.*;
public class CountMap
extends AbstractMap {
private int size;
private static char[] chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static String value(int key) {
return
chars[key % chars.length] +
Integer.toString(key / chars.length);
}
public CountMap(int size) {
this.size = size < 0 ? 0 : size;
}
@Override
public String get(Object key) {
return value((Integer)key);
}
private static class Entry
implements Map.Entry {
int index;
Entry(int index) { this.index = index; }
@Override
public boolean equals(Object o) {
return o instanceof Entry &&
Objects.equals(index, ((Entry)o).index);
}
@Override
public Integer getKey() { return index; }
@Override
public String getValue() {
return value(index);
}
@Override
public String setValue(String value) {
throw new UnsupportedOperationException();
}
@Override
public int hashCode() {
return Objects.hashCode(index);
}
}
@Override
public Set> entrySet() {
// LinkedHashSet retains initialization order:
return IntStream.range(0, size)
.mapToObj(Entry::new)
.collect(Collectors
.toCollection(LinkedHashSet::new));
}
public static void main(String[] args) {
final int size = 6;
CountMap cm = new CountMap(60);
System.out.println(cm);
System.out.println(cm.get(500));
cm.values().stream()
.limit(size)
.forEach(System.out::println);
System.out.println();
new Random(47).ints(size, 0, 1000)
.mapToObj(cm::get)
.forEach(System.out::println);
}
}
/* Output:
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0,
9=J0, 10=K0, 11=L0, 12=M0, 13=N0, 14=O0, 15=P0, 16=Q0,
17=R0, 18=S0, 19=T0, 20=U0, 21=V0, 22=W0, 23=X0, 24=Y0,
25=Z0, 26=A1, 27=B1, 28=C1, 29=D1, 30=E1, 31=F1, 32=G1,
33=H1, 34=I1, 35=J1, 36=K1, 37=L1, 38=M1, 39=N1, 40=O1,
41=P1, 42=Q1, 43=R1, 44=S1, 45=T1, 46=U1, 47=V1, 48=W1,
49=X1, 50=Y1, 51=Z1, 52=A2, 53=B2, 54=C2, 55=D2, 56=E2,
57=F2, 58=G2, 59=H2}
G19
A0
B0
C0
D0
E0
F0
Y9
J21
R26
D33
Z36
N16
*/
```
è¦å建ä¸ä¸ªåªè¯»ç **Map** ï¼åä» **AbstractMap** ç»§æ¿å¹¶å®ç° `entrySet()` ãç§æç `value()` æ¹æ³è®¡ç®ä»»ä½é®çå¼ï¼å¹¶å¨ `get()` å `Entry.getValue()` ä¸ä½¿ç¨ãå¯ä»¥å¿½ç¥ **CountMap** ç大å°ã
è¿éæ¯ä½¿ç¨äº **LinkedHashSet** è䏿¯å建èªå®ä¹ **Set** ç±»ï¼å æ¤å¹¶æªå®å
¨å®ç°äº«å
ãåªæå¨è°ç¨ `entrySet()` æ¶æä¼çææ¤å¯¹è±¡ã
ç°å¨å建ä¸ä¸ªæ´å¤æç享å
ãè¿ä¸ªç¤ºä¾ä¸çæ°æ®éæ¯ä¸çåå½åå
¶é¦é½ç **Map** ã `capitals()` æ¹æ³çæä¸ä¸ªå½å®¶åé¦é½ç **Map** ã `names()` æ¹æ³çæä¸ä¸ªç±å½å®¶ååç»æç **List** ã å½ç»å®äºè¡¨ç¤ºæé大å°ç **int** åæ°æ¶ï¼ä¸¤ç§æ¹æ³é½çæå¯¹åºå¤§å°çåè¡¨çæ®µï¼
```java
// onjava/Countries.java
// "Flyweight" Maps and Lists of sample data
// {java onjava.Countries}
package onjava;
import java.util.*;
public class Countries {
public static final String[][] DATA = {
// Africa
{"ALGERIA","Algiers"},
{"ANGOLA","Luanda"},
{"BENIN","Porto-Novo"},
{"BOTSWANA","Gaberone"},
{"BURKINA FASO","Ouagadougou"},
{"BURUNDI","Bujumbura"},
{"CAMEROON","Yaounde"},
{"CAPE VERDE","Praia"},
{"CENTRAL AFRICAN REPUBLIC","Bangui"},
{"CHAD","N'djamena"},
{"COMOROS","Moroni"},
{"CONGO","Brazzaville"},
{"DJIBOUTI","Dijibouti"},
{"EGYPT","Cairo"},
{"EQUATORIAL GUINEA","Malabo"},
{"ERITREA","Asmara"},
{"ETHIOPIA","Addis Ababa"},
{"GABON","Libreville"},
{"THE GAMBIA","Banjul"},
{"GHANA","Accra"},
{"GUINEA","Conakry"},
{"BISSAU","Bissau"},
{"COTE D'IVOIR (IVORY COAST)","Yamoussoukro"},
{"KENYA","Nairobi"},
{"LESOTHO","Maseru"},
{"LIBERIA","Monrovia"},
{"LIBYA","Tripoli"},
{"MADAGASCAR","Antananarivo"},
{"MALAWI","Lilongwe"},
{"MALI","Bamako"},
{"MAURITANIA","Nouakchott"},
{"MAURITIUS","Port Louis"},
{"MOROCCO","Rabat"},
{"MOZAMBIQUE","Maputo"},
{"NAMIBIA","Windhoek"},
{"NIGER","Niamey"},
{"NIGERIA","Abuja"},
{"RWANDA","Kigali"},
{"SAO TOME E PRINCIPE","Sao Tome"},
{"SENEGAL","Dakar"},
{"SEYCHELLES","Victoria"},
{"SIERRA LEONE","Freetown"},
{"SOMALIA","Mogadishu"},
{"SOUTH AFRICA","Pretoria/Cape Town"},
{"SUDAN","Khartoum"},
{"SWAZILAND","Mbabane"},
{"TANZANIA","Dodoma"},
{"TOGO","Lome"},
{"TUNISIA","Tunis"},
{"UGANDA","Kampala"},
{"DEMOCRATIC REPUBLIC OF THE CONGO (ZAIRE)",
"Kinshasa"},
{"ZAMBIA","Lusaka"},
{"ZIMBABWE","Harare"},
// Asia
{"AFGHANISTAN","Kabul"},
{"BAHRAIN","Manama"},
{"BANGLADESH","Dhaka"},
{"BHUTAN","Thimphu"},
{"BRUNEI","Bandar Seri Begawan"},
{"CAMBODIA","Phnom Penh"},
{"CHINA","Beijing"},
{"CYPRUS","Nicosia"},
{"INDIA","New Delhi"},
{"INDONESIA","Jakarta"},
{"IRAN","Tehran"},
{"IRAQ","Baghdad"},
{"ISRAEL","Jerusalem"},
{"JAPAN","Tokyo"},
{"JORDAN","Amman"},
{"KUWAIT","Kuwait City"},
{"LAOS","Vientiane"},
{"LEBANON","Beirut"},
{"MALAYSIA","Kuala Lumpur"},
{"THE MALDIVES","Male"},
{"MONGOLIA","Ulan Bator"},
{"MYANMAR (BURMA)","Rangoon"},
{"NEPAL","Katmandu"},
{"NORTH KOREA","P'yongyang"},
{"OMAN","Muscat"},
{"PAKISTAN","Islamabad"},
{"PHILIPPINES","Manila"},
{"QATAR","Doha"},
{"SAUDI ARABIA","Riyadh"},
{"SINGAPORE","Singapore"},
{"SOUTH KOREA","Seoul"},
{"SRI LANKA","Colombo"},
{"SYRIA","Damascus"},
{"TAIWAN (REPUBLIC OF CHINA)","Taipei"},
{"THAILAND","Bangkok"},
{"TURKEY","Ankara"},
{"UNITED ARAB EMIRATES","Abu Dhabi"},
{"VIETNAM","Hanoi"},
{"YEMEN","Sana'a"},
// Australia and Oceania
{"AUSTRALIA","Canberra"},
{"FIJI","Suva"},
{"KIRIBATI","Bairiki"},
{"MARSHALL ISLANDS","Dalap-Uliga-Darrit"},
{"MICRONESIA","Palikir"},
{"NAURU","Yaren"},
{"NEW ZEALAND","Wellington"},
{"PALAU","Koror"},
{"PAPUA NEW GUINEA","Port Moresby"},
{"SOLOMON ISLANDS","Honaira"},
{"TONGA","Nuku'alofa"},
{"TUVALU","Fongafale"},
{"VANUATU","Port Vila"},
{"WESTERN SAMOA","Apia"},
// Eastern Europe and former USSR
{"ARMENIA","Yerevan"},
{"AZERBAIJAN","Baku"},
{"BELARUS (BYELORUSSIA)","Minsk"},
{"BULGARIA","Sofia"},
{"GEORGIA","Tbilisi"},
{"KAZAKSTAN","Almaty"},
{"KYRGYZSTAN","Alma-Ata"},
{"MOLDOVA","Chisinau"},
{"RUSSIA","Moscow"},
{"TAJIKISTAN","Dushanbe"},
{"TURKMENISTAN","Ashkabad"},
{"UKRAINE","Kyiv"},
{"UZBEKISTAN","Tashkent"},
// Europe
{"ALBANIA","Tirana"},
{"ANDORRA","Andorra la Vella"},
{"AUSTRIA","Vienna"},
{"BELGIUM","Brussels"},
{"BOSNIA-HERZEGOVINA","Sarajevo"},
{"CROATIA","Zagreb"},
{"CZECH REPUBLIC","Prague"},
{"DENMARK","Copenhagen"},
{"ESTONIA","Tallinn"},
{"FINLAND","Helsinki"},
{"FRANCE","Paris"},
{"GERMANY","Berlin"},
{"GREECE","Athens"},
{"HUNGARY","Budapest"},
{"ICELAND","Reykjavik"},
{"IRELAND","Dublin"},
{"ITALY","Rome"},
{"LATVIA","Riga"},
{"LIECHTENSTEIN","Vaduz"},
{"LITHUANIA","Vilnius"},
{"LUXEMBOURG","Luxembourg"},
{"MACEDONIA","Skopje"},
{"MALTA","Valletta"},
{"MONACO","Monaco"},
{"MONTENEGRO","Podgorica"},
{"THE NETHERLANDS","Amsterdam"},
{"NORWAY","Oslo"},
{"POLAND","Warsaw"},
{"PORTUGAL","Lisbon"},
{"ROMANIA","Bucharest"},
{"SAN MARINO","San Marino"},
{"SERBIA","Belgrade"},
{"SLOVAKIA","Bratislava"},
{"SLOVENIA","Ljuijana"},
{"SPAIN","Madrid"},
{"SWEDEN","Stockholm"},
{"SWITZERLAND","Berne"},
{"UNITED KINGDOM","London"},
{"VATICAN CITY","Vatican City"},
// North and Central America
{"ANTIGUA AND BARBUDA","Saint John's"},
{"BAHAMAS","Nassau"},
{"BARBADOS","Bridgetown"},
{"BELIZE","Belmopan"},
{"CANADA","Ottawa"},
{"COSTA RICA","San Jose"},
{"CUBA","Havana"},
{"DOMINICA","Roseau"},
{"DOMINICAN REPUBLIC","Santo Domingo"},
{"EL SALVADOR","San Salvador"},
{"GRENADA","Saint George's"},
{"GUATEMALA","Guatemala City"},
{"HAITI","Port-au-Prince"},
{"HONDURAS","Tegucigalpa"},
{"JAMAICA","Kingston"},
{"MEXICO","Mexico City"},
{"NICARAGUA","Managua"},
{"PANAMA","Panama City"},
{"ST. KITTS AND NEVIS","Basseterre"},
{"ST. LUCIA","Castries"},
{"ST. VINCENT AND THE GRENADINES","Kingstown"},
{"UNITED STATES OF AMERICA","Washington, D.C."},
// South America
{"ARGENTINA","Buenos Aires"},
{"BOLIVIA","Sucre (legal)/La Paz(administrative)"},
{"BRAZIL","Brasilia"},
{"CHILE","Santiago"},
{"COLOMBIA","Bogota"},
{"ECUADOR","Quito"},
{"GUYANA","Georgetown"},
{"PARAGUAY","Asuncion"},
{"PERU","Lima"},
{"SURINAME","Paramaribo"},
{"TRINIDAD AND TOBAGO","Port of Spain"},
{"URUGUAY","Montevideo"},
{"VENEZUELA","Caracas"},
};
// Use AbstractMap by implementing entrySet()
private static class FlyweightMap
extends AbstractMap {
private static class Entry
implements Map.Entry {
int index;
Entry(int index) { this.index = index; }
@Override
public boolean equals(Object o) {
return o instanceof FlyweightMap &&
Objects.equals(DATA[index][0], o);
}
@Override
public int hashCode() {
return Objects.hashCode(DATA[index][0]);
}
@Override
public String getKey() { return DATA[index][0]; }
@Override
public String getValue() {
return DATA[index][1];
}
@Override
public String setValue(String value) {
throw new UnsupportedOperationException();
}
}
// Implement size() & iterator() for AbstractSet:
static class EntrySet
extends AbstractSet> {
private int size;
EntrySet(int size) {
if(size < 0)
this.size = 0;
// Can't be any bigger than the array:
else if(size > DATA.length)
this.size = DATA.length;
else
this.size = size;
}
@Override
public int size() { return size; }
private class Iter
implements Iterator> {
// Only one Entry object per Iterator:
private Entry entry = new Entry(-1);
@Override
public boolean hasNext() {
return entry.index < size - 1;
}
@Override
public Map.Entry next() {
entry.index++;
return entry;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public
Iterator> iterator() {
return new Iter();
}
}
private static
Set> entries =
new EntrySet(DATA.length);
@Override
public Set> entrySet() {
return entries;
}
}
// Create a partial map of 'size' countries:
static Map select(final int size) {
return new FlyweightMap() {
@Override
public Set> entrySet() {
return new EntrySet(size);
}
};
}
static Map map = new FlyweightMap();
public static Map capitals() {
return map; // The entire map
}
public static Map capitals(int size) {
return select(size); // A partial map
}
static List names =
new ArrayList<>(map.keySet());
// All the names:
public static List names() { return names; }
// A partial list:
public static List names(int size) {
return new ArrayList<>(select(size).keySet());
}
public static void main(String[] args) {
System.out.println(capitals(10));
System.out.println(names(10));
System.out.println(new HashMap<>(capitals(3)));
System.out.println(
new LinkedHashMap<>(capitals(3)));
System.out.println(new TreeMap<>(capitals(3)));
System.out.println(new Hashtable<>(capitals(3)));
System.out.println(new HashSet<>(names(6)));
System.out.println(new LinkedHashSet<>(names(6)));
System.out.println(new TreeSet<>(names(6)));
System.out.println(new ArrayList<>(names(6)));
System.out.println(new LinkedList<>(names(6)));
System.out.println(capitals().get("BRAZIL"));
}
}
/* Output:
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo,
BOTSWANA=Gaberone, BURKINA FASO=Ouagadougou,
BURUNDI=Bujumbura, CAMEROON=Yaounde, CAPE VERDE=Praia,
CENTRAL AFRICAN REPUBLIC=Bangui, CHAD=N'djamena}
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI, CAMEROON, CAPE VERDE, CENTRAL AFRICAN
REPUBLIC, CHAD]
{BENIN=Porto-Novo, ANGOLA=Luanda, ALGERIA=Algiers}
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
[BENIN, BOTSWANA, ANGOLA, BURKINA FASO, ALGERIA,
BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI]
Brasilia
*/
```
äºç»´æ°ç» **String DATA** æ¯ **public** çï¼å æ¤å¯ä»¥å¨å«å¤ä½¿ç¨ã **FlyweightMap** å¿
é¡»å®ç° `entrySet()` æ¹æ³ï¼è¯¥æ¹æ³éè¦ä¸ä¸ªèªå®ä¹ **Set** å®ç°åä¸ä¸ªèªå®ä¹ **Map.Entry** ç±»ãè¿æ¯å®ç°äº«å
çå¦ä¸ç§æ¹æ³ï¼æ¯ä¸ª **Map.Entry** 对象åå¨å®èªèº«çç´¢å¼ï¼è䏿¯å®é
çé®åå¼ãå½è°ç¨ `getKey()` æ `getValue()` æ¶ï¼å®ä½¿ç¨ç´¢å¼è¿åç¸åºç **DATA** å
ç´ ã **EntrySet** ç¡®ä¿å®ç **size** ä¸å¤§äº **DATA** ã
享å
çå¦ä¸é¨åå¨ **EntrySet.Iterator** ä¸å®ç°ãç¸æ¯äºä¸º **DATA** ä¸çæ¯ä¸ªæ°æ®å¯¹å建ä¸ä¸ª **Map.Entry** 对象ï¼è¿éæ¯ä¸ªè¿ä»£å¨åªæä¸ä¸ª **Map.Entry** 对象ã **Entry** 对象ä½ä¸ºæ°æ®ççªå£ï¼å®åªå
å« **String** éææ°ç»çç´¢å¼ãæ¯æ¬¡ä¸ºè¿ä»£å¨è°ç¨ `next()` æ¶ï¼**Entry** ä¸çç´¢å¼é½ä¼éå¢ï¼å æ¤å®ä¼æåä¸ä¸ä¸ªæ°æ®å¯¹ï¼ç¶åä» `next()` è¿å **Iterators** çå个 **Entry** 对象ã[^1]
`select()` æ¹æ³çæä¸ä¸ªå
嫿é大å°ç **EntrySet** ç **FlyweightMap** ï¼è¿ç¨äºå¨ä¸»æ¹æ³ä¸æ¼ç¤ºçéè½½ç `capitals()` å `names()` æ¹æ³ã
## éååè½
ä¸é¢è¿ä¸ªè¡¨æ ¼å±ç¤ºäºå¯ä»¥å¯¹ **Collection** æ§è¡çæææä½ï¼ä¸å
æ¬èªå¨ç»§æ¿èª **Object** çæ¹æ³ï¼ï¼å æ¤ï¼å¯ä»¥ç¨ **List** ï¼ **Set** ï¼ **Queue** æ **Deque** æ§è¡è¿éçæææä½ï¼è¿äºæ¥å£å¯è½ä¹æä¾äºä¸äºå
¶ä»çåè½ï¼ã**Map** 䏿¯ä» **Collection** ç»§æ¿çï¼æä»¥è¦åç¬å¤çå®ã
| æ¹æ³å | æè¿° |
| :---: | :--- |
| **boolean add(T)** | ç¡®ä¿éåå
å«è¯¥æ³åç±»å **T** çåæ°ã妿䏿·»å åæ°ï¼åè¿å **false** ã ï¼è¿æ¯ä¸ç§âå¯éâæ¹æ³ï¼å°å¨ä¸ä¸èä¸ä»ç»ãï¼ |
| **boolean addAll(Collection\ extends T\>)** | æ·»å åæ°éåä¸çææå
ç´ ãåªè¦æå
ç´ è¢«æåæ·»å åè¿å **true**ãï¼âå¯éçâï¼ |
| **void clear()** | å é¤éåä¸çææå
ç´ ãï¼âå¯éçâï¼ |
| **boolean contains(T)** | å¦æç®æ éåå
å«è¯¥æ³åç±»å **T** çåæ°ï¼åè¿å **true** ã |
| **boolean containsAll(Collection\\>)** | å¦æç®æ éåå
å«åæ°éåä¸çææå
ç´ ï¼åè¿å **true** |
| **boolean isEmpty()** | 妿éå为空ï¼åè¿å **true** |
| **Iterator\ iterator() Spliterator\ spliterator()** | è¿åä¸ä¸ªè¿ä»£å¨æ¥éåéåä¸çå
ç´ ã **Spliterators** æ´å¤æä¸äºï¼å®ç¨å¨å¹¶ååºæ¯ |
| **boolean remove(Object)** | å¦æç®æ éåå
å«è¯¥åæ°ï¼åå¨éåä¸å é¤è¯¥åæ°ï¼å¦ææåå é¤åè¿å **true** ãï¼âå¯éçâï¼ |
| **boolean removeAll(Collection\\>)** | å é¤ç®æ éåä¸ï¼åæ°éåæå
å«çå
¨é¨å
ç´ ã妿æå
ç´ è¢«æåå é¤åè¿å **true** ã ï¼âå¯éçâï¼ |
| **boolean removeIf(Predicate\ super E\>)** | å 餿¤éåä¸ï¼æ»¡è¶³ç»å®æè¨ï¼predicateï¼çææå
ç´ |
| **Stream\ stream() Stream\ parallelStream()** | è¿åç±è¯¥ **Collection** ä¸å
ç´ æç»æçä¸ä¸ª **Stream** |
| **int size()** | è¿åéå䏿å
å«å
ç´ çä¸ªæ° |
| **Object[] toArrat()** | è¿åå
å«è¯¥éåææå
ç´ çä¸ä¸ªæ°ç» |
| **\ T[] toArray(T[] a)** | è¿åå
å«è¯¥éåææå
ç´ çä¸ä¸ªæ°ç»ãç»æçè¿è¡æ¶ç±»åæ¯åæ°æ°ç»è䏿¯æ®éç **Object** æ°ç»ã |
è¿é没ææä¾ç¨äºéæºè®¿é®å
ç´ ç **get()** æ¹æ³ï¼å 为 **Collection** è¿å
å« **Set** ï¼å®ç»´æ¤èªå·±çå
鍿åºï¼æä»¥éæºè®¿é®æ¥æ¾å°±æ²¡ææä¹äºãå æ¤ï¼è¦æ¥æ¾ **Collection** ä¸çå
ç´ å¿
须使ç¨è¿ä»£å¨ã
ä¸é¢è¿ä¸ªç¤ºä¾æ¼ç¤ºäº **Collection** çæææ¹æ³ãè¿é以 **ArrayList** 为ä¾ï¼
```java
// collectiontopics/CollectionMethods.java
// Things you can do with all Collections
import java.util.*;
import static onjava.HTMLColors.*;
public class CollectionMethods {
public static void main(String[] args) {
Collection c =
new ArrayList<>(LIST.subList(0, 4));
c.add("ten");
c.add("eleven");
show(c);
border();
// Make an array from the List:
Object[] array = c.toArray();
// Make a String array from the List:
String[] str = c.toArray(new String[0]);
// Find max and min elements; this means
// different things depending on the way
// the Comparable interface is implemented:
System.out.println(
"Collections.max(c) = " + Collections.max(c));
System.out.println(
"Collections.min(c) = " + Collections.min(c));
border();
// Add a Collection to another Collection
Collection c2 =
new ArrayList<>(LIST.subList(10, 14));
c.addAll(c2);
show(c);
border();
c.remove(LIST.get(0));
show(c);
border();
// Remove all components that are
// in the argument collection:
c.removeAll(c2);
show(c);
border();
c.addAll(c2);
show(c);
border();
// Is an element in this Collection?
String val = LIST.get(3);
System.out.println(
"c.contains(" + val + ") = " + c.contains(val));
// Is a Collection in this Collection?
System.out.println(
"c.containsAll(c2) = " + c.containsAll(c2));
Collection c3 =
((List)c).subList(3, 5);
// Keep all the elements that are in both
// c2 and c3 (an intersection of sets):
c2.retainAll(c3);
show(c2);
// Throw away all the elements
// in c2 that also appear in c3:
c2.removeAll(c3);
System.out.println(
"c2.isEmpty() = " + c2.isEmpty());
border();
// Functional operation:
c = new ArrayList<>(LIST);
c.removeIf(s -> !s.startsWith("P"));
c.removeIf(s -> s.startsWith("Pale"));
// Stream operation:
c.stream().forEach(System.out::println);
c.clear(); // Remove all elements
System.out.println("after c.clear():" + c);
}
}
/* Output:
AliceBlue
AntiqueWhite
Aquamarine
Azure
ten
eleven
******************************
Collections.max(c) = ten
Collections.min(c) = AliceBlue
******************************
AliceBlue
AntiqueWhite
Aquamarine
Azure
ten
eleven
Brown
BurlyWood
CadetBlue
Chartreuse
******************************
AntiqueWhite
Aquamarine
Azure
ten
eleven
Brown
BurlyWood
CadetBlue
Chartreuse
******************************
AntiqueWhite
Aquamarine
Azure
ten
eleven
******************************
AntiqueWhite
Aquamarine
Azure
ten
eleven
Brown
BurlyWood
CadetBlue
Chartreuse
******************************
c.contains(Azure) = true
c.containsAll(c2) = true
c2.isEmpty() = true
******************************
PapayaWhip
PeachPuff
Peru
Pink
Plum
PowderBlue
Purple
after c.clear():[]
*/
```
为äºåªæ¼ç¤º **Collection** æ¥å£çæ¹æ³ï¼è没æå
¶å®é¢å¤çå
å®¹ï¼æä»¥è¿éå建å
å«ä¸åæ°æ®éç **ArrayList** ï¼å¹¶åä¸è½¬å为 **Collection** 对象ã
## å¯éæä½
å¨ **Collection** æ¥å£ä¸æ§è¡åç§æ·»å åå 餿ä½çæ¹æ³æ¯ *å¯éæä½* ï¼optional operationsï¼ãè¿æå³çå®ç°ç±»ä¸éè¦ä¸ºè¿äºæ¹æ³æä¾åè½å®ä¹ã
è¿æ¯ä¸ç§é常ä¸å¯»å¸¸çå®ä¹æ¥å£çæ¹å¼ãæ£å¦æä»¬æç¥ï¼æ¥å£æ¯ä¸ç§å约ï¼contractï¼ãå®è¡¨è¾¾çæææ¯ï¼âæ è®ºä½ å¦ä½éæ©å®ç°è¿ä¸ªæ¥å£ï¼æä¿è¯ä½ å¯ä»¥å°è¿äºæ¶æ¯åéå°è¿ä¸ªå¯¹è±¡âï¼æå¨è¿éä½¿ç¨æ¯è¯âæ¥å£âæ¥æè¿°æ£å¼ç **interface** å
³é®ååâä»»ä½ç±»æåç±»é½æ¯æçæ¹æ³âçæ´ä¸è¬å«ä¹ï¼ãä½âå¯éâæä½è¿åäºè¿ä¸åºæ¬ååï¼å®è¡¨ç¤ºè°ç¨æäºæ¹æ³ä¸ä¼æ§è¡ææä¹çè¡ä¸ºãç¸åï¼å®ä»¬ä¼æåºå¼å¸¸ï¼è¿çèµ·æ¥ä¼¼ä¹ä¸¢å¤±äºç¼è¯æ¶çç±»åå®å
¨æ§ã
å
¶å®æ²¡é£ä¹ç³ç³ã妿æä½æ¯å¯éçï¼ç¼è¯å¨ä»ç¶è½å¤éå¶ä½ ä»
è°ç¨è¯¥æ¥å£ä¸çæ¹æ³ãå®ä¸å卿è¯è¨é£æ ·ï¼å¯ä»¥ä¸ºä»»ä½å¯¹è±¡è°ç¨ä»»ä½æ¹æ³ï¼å¹¶å¨è¿è¡æ¶æ¥æ¾ç¹å®çè°ç¨æ¯å¦å¯è¡ã[^2]æ¤å¤ï¼å¤§å¤æ°å° **Collection** ä½ä¸ºåæ°çæ¹æ³ä»
ä»è¯¥ **Collection** ä¸è¯»åï¼å¹¶ä¸ **Collection** çææâ读åâæ¹æ³é½ä¸æ¯å¯éçã
为ä»ä¹è¦å°æ¹æ³å®ä¹ä¸ºâå¯éâçï¼å ä¸ºè¿æ ·åå¯ä»¥é²æ¢è®¾è®¡ä¸çæ¥å£çç¸ãéååºçå
¶ä»è®¾è®¡å¾å¾ä¼äº§çä»¤äººå°æçè¿å¤æ¥å£æ¥æè¿°ä¸»é¢çæ¯ä¸ªåä½ãè¿çè³ä½¿å¾ä¸å¯è½æè·å°æ¥å£ä¸çææç¹æ®æ
åµï¼å ä¸ºæ»æäººè½åæä¸ä¸ªæ°çæ¥å£ãâ䏿¯æçæä½ï¼unsupported operationï¼âè¿ç§æ¹å¼å®ç°äºJavaéååºçä¸ä¸ªéè¦ç®æ ï¼éåè¦æäºå¦ä¹ å使ç¨ã䏿¯æçæä½æ¯ä¸ç§ç¹æ®æ
åµï¼å¯ä»¥æ¨è¿å°å¿
è¦çæ¶åã使¯ï¼è¦ä½¿ç¨æ¤æ¹æ³ï¼
1. **UnsupportedOperationException** å¿
é¡»æ¯ä¸ä¸ªç½è§çäºä»¶ãä¹å°±æ¯è¯´ï¼å¯¹äºå¤§å¤æ°ç±»ï¼æææä½é½åºè¯¥èµ·ä½ç¨ï¼å¹¶ä¸åªæå¨ç¹æ®æ
åµä¸æåºè¯¥ä¸æ¯ææé¡¹æä½ãè¿å¨Javaéååºä¸æ¯æ£ç¡®çï¼å 为99%çæ¶é´ä½¿ç¨å°çç±» ââ **ArrayList** ï¼ **LinkedList** ï¼ **HashSet** å **HashMap** ï¼ä»¥åå
¶ä»å
·ä½å®ç°ï¼é½æ¯ææææä½ã该设计确å®ä¸ºå建ä¸ä¸ªæ°ç **Collection** æä¾äºä¸ä¸ªâåé¨âï¼å¯ä»¥ä¸ä¸º **Collection** æ¥å£ä¸çæææ¹æ³é½æä¾ææä¹çå®ä¹ï¼è¿äºå®ä¹ä»ç¶éåç°æçç±»åºã
2. å½ä¸æ¯ææä¸ªæä½æ¶ï¼ **UnsupportedOperationException** åºè¯¥åºç°å¨å®ç°é¶æ®µï¼è䏿¯å¨å°äº§ååéç»å®¢æ·ä¹åãæ¯ç«ï¼è¿ä¸ªå¼å¸¸è¡¨ç¤ºç¼ç¨é误ï¼é误å°ä½¿ç¨äºä¸ä¸ªå
·ä½å®ç°ã
å¼å¾æ³¨æçæ¯ï¼ä¸æ¯æçæä½åªè½å¨è¿è¡æ¶æ£æµå°ï¼å æ¤è¿ä»£è¡¨å¨æç±»åæ£æ¥ãå¦æä½ æ¥èªå C++ è¿æ ·çéæç±»åè¯è¨ï¼Java å¯è½çèµ·æ¥åªæ¯å¦ä¸ç§éæç±»åè¯è¨ãå½ç¶ï¼ Java è¯å®æéæç±»åæ£æ¥ï¼ä½å®ä¹æå¤§éçå¨æç±»åï¼å æ¤å¾é¾è¯´å®åªæ¯éæè¯è¨æå¨æè¯è¨ã䏿¦ä½ å¼å§æ³¨æå°è¿ä¸ç¹ï¼ä½ å°±ä¼å¼å§çå° Java ä¸å¨æç±»åæ£æ¥çå
¶ä»ç¤ºä¾ã
### 䏿¯æçæä½
䏿¯æçæä½çå¸¸è§æ¥æºæ¯ç±åºå®å¤§å°çæ°æ®ç»æææ¯æçéåãä½¿ç¨ `Arrays.asList()` æ¹æ³å°æ°ç»è½¬æ¢ä¸º **List** æ¶ï¼å°±ä¼å¾å°è¿æ ·çéåãæ¤å¤ï¼è¿å¯ä»¥éæ©ä½¿ç¨ **Collections** ç±»ä¸çâä¸å¯ä¿®æ¹ï¼unmodifiableï¼âæ¹æ³ä½¿ä»»ä½éåï¼å
æ¬ **Map** ï¼æåº **UnsupportedOperationException** å¼å¸¸ãæ¤ç¤ºä¾å±ç¤ºäºè¿ä¸¤ç§æ
åµï¼
```java
// collectiontopics/Unsupported.java
// Unsupported operations in Java collections
import java.util.*;
public class Unsupported {
static void
check(String description, Runnable tst) {
try {
tst.run();
} catch(Exception e) {
System.out.println(description + "(): " + e);
}
}
static void test(String msg, List list) {
System.out.println("--- " + msg + " ---");
Collection c = list;
Collection subList = list.subList(1,8);
// Copy of the sublist:
Collection c2 = new ArrayList<>(subList);
check("retainAll", () -> c.retainAll(c2));
check("removeAll", () -> c.removeAll(c2));
check("clear", () -> c.clear());
check("add", () -> c.add("X"));
check("addAll", () -> c.addAll(c2));
check("remove", () -> c.remove("C"));
// The List.set() method modifies the value but
// doesn't change the size of the data structure:
check("List.set", () -> list.set(0, "X"));
}
public static void main(String[] args) {
List list = Arrays.asList(
"A B C D E F G H I J K L".split(" "));
test("Modifiable Copy", new ArrayList<>(list));
test("Arrays.asList()", list);
test("unmodifiableList()",
Collections.unmodifiableList(
new ArrayList<>(list)));
}
}
/* Output:
--- Modifiable Copy ---
--- Arrays.asList() ---
retainAll(): java.lang.UnsupportedOperationException
removeAll(): java.lang.UnsupportedOperationException
clear(): java.lang.UnsupportedOperationException
add(): java.lang.UnsupportedOperationException
addAll(): java.lang.UnsupportedOperationException
remove(): java.lang.UnsupportedOperationException
--- unmodifiableList() ---
retainAll(): java.lang.UnsupportedOperationException
removeAll(): java.lang.UnsupportedOperationException
clear(): java.lang.UnsupportedOperationException
add(): java.lang.UnsupportedOperationException
addAll(): java.lang.UnsupportedOperationException
remove(): java.lang.UnsupportedOperationException
List.set(): java.lang.UnsupportedOperationException
*/
```
å 为 `Arrays.asList()` çæç **List** ç±ä¸ä¸ªåºå®å¤§å°çæ°ç»ææ¯æï¼æä»¥å¯ä¸æ¯æçæä½æ¯é£äºä¸æ¹åæ°ç»å¤§å°çæä½ãä»»ä½ä¼å¯¼è´æ´æ¹åºç¡æ°æ®ç»æå¤§å°çæ¹æ³é½ä¼äº§ç **UnsupportedOperationException** å¼å¸¸ï¼æ¥è¯´æè¿æ¯å¯¹ä¸æ¯æçæ¹æ³çè°ç¨ï¼ç¼ç¨é误ï¼ã
请注æï¼å§ç»å¯ä»¥å° `Arrays.asList()` çç»æä½ä¸ºä¸ä¸ªåæ°ä¼ éç»ä»»ä½ **Collection** çæé æ¹æ³ï¼æä½¿ç¨ `addAll()` æ¹æ³æéæç `Collections.addAll()` æ¹æ³ï¼æ¥å建ä¸ä¸ªå
è®¸ä½¿ç¨æææ¹æ³ç常è§éåï¼å¨ä¸»æ¹æ³ä¸ç¬¬ä¸æ¬¡è°ç¨ `test()` æ¶æ¾ç¤ºäºè¿ç§æ
åµãè¿ç§è°ç¨äº§çäºä¸ä¸ªæ°çå¯è°æ´å¤§å°çåºå±æ°æ®ç»æã
**Collections** ç±»ä¸çâunmodifiableâæ¹æ³ä¼å°éåå
è£
ä¸ä¸ªä»£çä¸ï¼å¦ææ§è¡ä»»ä½æ³è¦ä¿®æ¹éåçæä½ï¼å该代çä¼çæ **UnsupportedOperationException** å¼å¸¸ã使ç¨è¿äºæ¹æ³çç®çæ¯çæä¸ä¸ªâ常éâéå对象ãç¨åå°æè¿°âunmodifiableâéåæ¹æ³ç宿´å表ã
`test()` ä¸çæåä¸ä¸ª `check()` ç¨äºæµè¯**List** ç `set()` æ¹æ³ãè¿éï¼â䏿¯æçæä½âææ¯çç²åº¦ï¼granularityï¼å°±æ´¾ä¸ç¨åºäºï¼å¾å°çâæ¥å£âå¯ä»¥éè¿ä¸ç§æ¹æ³å¨ `Arrays.asList()` è¿åç对象å `Collections.unmodifiableList()` è¿åç对象ä¹é´åæ¢ã `Arrays.asList()` è¿ååºå®å¤§å°ç **List** ï¼è `Collections.unmodifiableList()` çææ æ³æ´æ¹ç **List** ãå¦è¾åºä¸æç¤ºï¼ `Arrays.asList()` è¿åç **List** ä¸çå
ç´ æ¯å¯ä»¥ä¿®æ¹çï¼å 为è¿ä¸ä¼è¿å该 **List** çâåºå®å¤§å°âç¹æ§ãä½å¾ææ¾ï¼ `unmodifiableList()` çç»æä¸åºè¯¥ä»¥ä»»ä½æ¹å¼ä¿®æ¹ãå¦æä½¿ç¨æ¥å£æ¥æè¿°ï¼åéè¦ä¸¤ä¸ªé¢å¤çæ¥å£ï¼ä¸ä¸ªå
·æå¯ç¨ç `set()` æ¹æ³ï¼èå¦ä¸ä¸ªæ²¡æã **Collection** çåç§ä¸å¯ä¿®æ¹çåç±»åé½å°éè¦é¢å¤çæ¥å£ã
妿ä¸ä¸ªæ¹æ³å°ä¸ä¸ªéåä½ä¸ºå®çåæ°ï¼é£ä¹å®çææ¡£åºè¯¥è¯´æå¿
é¡»å®ç°åªäºå¯éæ¹æ³ã
## Setååå¨é¡ºåº
[第åäºç« éå]()ç« èä¸ç **Set** æå
³ç¤ºä¾å¯¹ **Set** çåºæ¬æä½åäºå¾å¥½çä»ç»ã 使¯ï¼è¿äºç¤ºä¾å¯ä»¥æ¹ä¾¿å°ä½¿ç¨é¢å®ä¹ç Java ç±»åï¼ä¾å¦ **Integer** å **String** ï¼å®ä»¬å¯ä»¥å¨éåä¸ä½¿ç¨ãå¨å建èªå·±çç±»åæ¶è¯·æ³¨æï¼ **Set** ï¼ä»¥åç¨åä¼çå°ç **Map** ï¼éè¦ä¸ç§ç»´æ¤åå¨é¡ºåºçæ¹æ³ï¼è¯¥é¡ºåºå **Set** çä¸åå®ç°èå¼ãå æ¤ï¼ä¸åç **Set** å®ç°ä¸ä»
å
·æä¸åçè¡ä¸ºï¼èä¸å®ä»¬å¯¹å¯ä»¥æ¾å
¥ç¹å® **Set** ä¸ç对象类å乿ä¸åçè¦æ±ï¼
| **Set** ç±»å | 约æ |
| :---: | :--- |
| **Set(interface)** | æ·»å å° **Set** ä¸çæ¯ä¸ªå
ç´ å¿
é¡»æ¯å¯ä¸çï¼å¦åï¼**Set** ä¸ä¼æ·»å éå¤å
ç´ ãæ·»å å° **Set** çå
ç´ å¿
é¡»è³å°å®ä¹ `equals()` æ¹æ³ä»¥å»ºç«å¯¹è±¡å¯ä¸æ§ã **Set** ä¸ **Collection** å
·æå®å
¨ç¸åçæ¥å£ã **Set** æ¥å£ä¸ä¿è¯å®å°ä»¥ä»»ä½ç¹å®é¡ºåºç»´æ¤å
¶å
ç´ ã |
| **HashSet\*** | 注éå¿«éæ¥æ¾å
ç´ çéåï¼å
¶ä¸å
ç´ å¿
é¡»å®ä¹ `hashCode()` å `equals()` æ¹æ³ã |
| **TreeSet** | ç±æ æ¯æçæåº **Set**ãè¿æ ·ï¼å°±å¯ä»¥ä» **Set** ä¸è·åæåºåºåï¼å
¶ä¸å
ç´ å¿
é¡»å®ç° **Comparable** æ¥å£ã |
| **LinkedHashSet** | å
·æ **HashSet** çæ¥æ¾é度ï¼ä½å¨å
é¨ä½¿ç¨é¾è¡¨ç»´æ¤å
ç´ çæå
¥é¡ºåºãå æ¤ï¼å½å¨éå **Set** æ¶ï¼ç»æå°æå
ç´ çæå
¥é¡ºåºæ¾ç¤ºãå
ç´ å¿
é¡»å®ä¹ `hashCode()` å `equals()` æ¹æ³ã |
**HashSet** ä¸çæå·è¡¨ç¤ºï¼å¨æ²¡æå
¶ä»çº¦æçæ
åµä¸ï¼è¿åºè¯¥æ¯ä½ çé»è®¤éæ©ï¼å 为å®é对é度è¿è¡äºä¼åã
å®ä¹ `hashCode()` æ¹æ³å¨[éå½:çè§£equalsåhashCodeæ¹æ³]()ä¸è¿è¡äºæè¿°ãå¿
须为æ£ååæ åå¨ç»æå建 `equals()` æ¹æ³ï¼ä½åªæå½æç±»æ¾å¨ **HashSet** 䏿¶æéè¦ `hashCode()` ï¼å½ç¶è¿å¾æå¯è½ï¼å 为 **HashSet** é常åºè¯¥æ¯ä½ä¸º **Set** å®ç°çé¦éï¼æ **LinkedHashSet** ã 使¯ï¼ä½ä¸ºä¸ç§è¯å¥½çç¼ç¨é£æ ¼ï¼å¨è¦ç `equals()` æ¶åºå§ç»è¦ç `hashCode()` ã
ä¸é¢çç¤ºä¾æ¼ç¤ºäºæå使ç¨å
·æç¹å® **Set** å®ç°çç±»åæéçæ¹æ³ï¼
```java
// collectiontopics/TypesForSets.java
// Methods necessary to put your own type in a Set
import java.util.*;
import java.util.function.*;
import java.util.Objects;
class SetType {
protected int i;
SetType(int n) { i = n; }
@Override
public boolean equals(Object o) {
return o instanceof SetType &&
Objects.equals(i, ((SetType)o).i);
}
@Override
public String toString() {
return Integer.toString(i);
}
}
class HashType extends SetType {
HashType(int n) { super(n); }
@Override
public int hashCode() {
return Objects.hashCode(i);
}
}
class TreeType extends SetType
implements Comparable {
TreeType(int n) { super(n); }
@Override
public int compareTo(TreeType arg) {
return Integer.compare(arg.i, i);
// Equivalent to:
// return arg.i < i ? -1 : (arg.i == i ? 0 : 1);
}
}
public class TypesForSets {
static void
fill(Set set, Function type) {
for(int i = 10; i >= 5; i--) // Descending
set.add(type.apply(i));
for(int i = 0; i < 5; i++) // Ascending
set.add(type.apply(i));
}
static void
test(Set set, Function type) {
fill(set, type);
fill(set, type); // Try to add duplicates
fill(set, type);
System.out.println(set);
}
public static void main(String[] args) {
test(new HashSet<>(), HashType::new);
test(new LinkedHashSet<>(), HashType::new);
test(new TreeSet<>(), TreeType::new);
// Things that don't work:
test(new HashSet<>(), SetType::new);
test(new HashSet<>(), TreeType::new);
test(new LinkedHashSet<>(), SetType::new);
test(new LinkedHashSet<>(), TreeType::new);
try {
test(new TreeSet<>(), SetType::new);
} catch(Exception e) {
System.out.println(e.getMessage());
}
try {
test(new TreeSet<>(), HashType::new);
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
/* Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[1, 6, 8, 6, 2, 7, 8, 9, 4, 10, 7, 5, 1, 3, 4, 9, 9,
10, 5, 3, 2, 0, 4, 1, 2, 0, 8, 3, 0, 10, 6, 5, 7]
[3, 1, 4, 8, 7, 6, 9, 5, 3, 0, 10, 5, 5, 10, 7, 8, 8,
9, 1, 4, 10, 2, 6, 9, 1, 6, 0, 3, 2, 0, 7, 2, 4]
[10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5,
0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
[10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5,
0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
SetType cannot be cast to java.lang.Comparable
HashType cannot be cast to java.lang.Comparable
*/
```
为äºè¯æç¹å® **Set** éè¦åªäºæ¹æ³ï¼åæ¶é¿å
代ç éå¤ï¼è¿éå建äºä¸ä¸ªç±»ãåºç±» **SetType** åå¨ä¸ä¸ª **int** å¼ï¼å¹¶éè¿ `toString()` æ¹æ³æå°å®ãç±äºåå¨å¨ **Set** ä¸çææç±»é½å¿
é¡»å
·æ `equals()` ï¼å æ¤è¯¥æ¹æ³ä¹æ¾å¨åºç±»ä¸ãåºäº `int i` æ¥å¤æå
ç´ æ¯å¦ç¸çã
**HashType** ç»§æ¿èª **SetType** ï¼å¹¶æ·»å äº `hashCode()` æ¹æ³ï¼è¯¥æ¹æ³å¯¹äº **Set** çæ£åå®ç°æ¯å¿
éçã
è¦å¨ä»»ä½ç±»åçæåºéåä¸ä½¿ç¨å¯¹è±¡ï¼ç± **TreeType** å®ç°ç **Comparable** æ¥å£é½æ¯å¿
éçï¼ä¾å¦ **SortedSet** ï¼ **TreeSet** æ¯å
¶å¯ä¸å®ç°ï¼ãå¨ `compareTo()` ä¸ï¼è¯·æ³¨æææ²¡æä½¿ç¨âç®åæäºâçå½¢å¼ï¼ `return i-i2` ãè½ç¶è¿æ¯ä¸ä¸ªå¸¸è§çç¼ç¨é误ï¼ä½åªæå½ **i** å **i2** æ¯âæ 符å·ï¼unsignedï¼âæ´åæ¶æè½æ£å¸¸å·¥ä½ï¼å¦æ Java æä¸ä¸ªâunsignedâå
³é®åçè¯ï¼ä¸è¿å®æ²¡æï¼ãå®ç ´åäº Java çæç¬¦å· **int** ï¼å®ä¸è¶³ä»¥ä»£è¡¨ä¸¤ä¸ªæç¬¦å·æ´æ°çå·®å¼ã妿 **i** æ¯ä¸ä¸ªå¤§çæ£æ´æ°è **j** æ¯ä¸ä¸ªå¤§çè´æ´æ°ï¼ `i-j` å°æº¢åºå¹¶è¿åä¸ä¸ªè´å¼ï¼è¿ä¸æ¯æä»¬æéè¦çã
é叏叿 `compareTo()` æ¹æ³çæä¸ `equals()` æ¹æ³ä¸è´çèªç¶é¡ºåºã妿 `equals()` 对äºç¹å®æ¯è¾äº§ç **true**ï¼å `compareTo()` åºè¯¥ä¸ºè¯¥æ¯è¾è¿åç»æ é¶ï¼å¹¶ä¸å¦æ `equals()` 为æ¯è¾äº§ç **false** ï¼å `compareTo()` åºè¯¥ä¸ºè¯¥æ¯è¾äº§çéé¶ç»æã
å¨ **TypesForSets** ä¸ï¼ `fill()` å `test()` 齿¯ä½¿ç¨æ³åå®ä¹çï¼ä»¥é²æ¢ä»£ç éå¤ã为äºéªè¯ **Set** çè¡ä¸ºï¼ `test()` 卿µè¯éä¸è°ç¨ `fill()` 䏿¬¡ï¼å°è¯å¼å
¥éå¤ç对象ã `fill()` æ¹æ³çåæ°å¯ä»¥æ¥æ¶ä»»æä¸ä¸ª **Set** ç±»åï¼ä»¥åçæè¯¥ç±»åç **Function** 对象ãå 为æ¤ç¤ºä¾ä¸ä½¿ç¨çææå¯¹è±¡é½æä¸ä¸ªå¸¦æå个 **int** åæ°çæé æ¹æ³ï¼æä»¥å¯ä»¥å°æé æ¹æ³ä½ä¸ºæ¤ **Function** ä¼ éï¼å®å°æä¾ç¨äºå¡«å
**Set** ç对象ã
请注æï¼ `fill()` æ¹æ³æéåºæ·»å åäºä¸ªå
ç´ ï¼æååºæ·»å åäºä¸ªå
ç´ ï¼ä»¥æ¤æ¥æåºçæçåå¨é¡ºåºãè¾åºæ¾ç¤º **HashSet** æååºä¿çå
ç´ ï¼ä½æ¯ï¼å¨[éå½:çè§£equalsåhashCodeæ¹æ³]()ä¸ï¼ä½ ä¼åç°è¿åªæ¯å¶ç¶çï¼å 为æ£åä¼å建èªå·±çåå¨é¡ºåºãè¿éåªæ¯å 为å
ç´ æ¯ä¸ä¸ªç®åç **int** ï¼å¨è¿ç§æ
åµä¸å®æ¯ååºçã **LinkedHashSet** æç
§æå
¥é¡ºåºä¿åå
ç´ ï¼**TreeSet** ææåºé¡ºåºç»´æ¤å
ç´ ï¼å¨æ¤ç¤ºä¾ä¸å 为 `compareTo()` çå®ç°æ¹å¼ï¼æä»¥å
ç´ æéåºæåãï¼
ç¹å®ç **Set** ç±»åä¸è¬é½ææå¿
éçæä½ï¼å¦æå°è¯ä½¿ç¨æ²¡è½æ£ç¡®æ¯æè¿äºæä½çç±»åï¼é£ä¹äºæ
å°±ä¼åºéãå°æ²¡æéæ°å®ä¹ `hashCode()` æ¹æ³ç **SetType** æ **TreeType** 对象æ¾å
¥ä»»ä½æ£åå®ç°ä¼å¯¼è´éå¤å¼ï¼å æ¤è¿åäº **Set** ç主è¦å¥çº¦ã è¿æ¯ç¸å½ä»¤äººä¸å®çï¼å 为è¿çè³ä¸äº§çè¿è¡æ¶é误ã使¯ï¼é»è®¤ç `hashCode()` æ¯åæ³çï¼æä»¥å³ä½¿å®æ¯ä¸æ£ç¡®çï¼è¿ä¹æ¯åæ³çè¡ä¸ºãç¡®ä¿æ¤ç±»ç¨åºæ£ç¡®æ§çå¯ä¸å¯é æ¹æ³æ¯å°åå
æµè¯åå¹¶å°æå»ºç³»ç»ä¸ã
妿å°è¯å¨ **TreeSet** ä¸ä½¿ç¨æ²¡æå®ç° **Comparable** æ¥å£çç±»åï¼åä¼å¾å°æ´æç¡®çç»æï¼å½ **TreeSet** å°è¯å°å¯¹è±¡ç¨ä½ä¸ä¸ª **Comparable** æ¶ï¼å°ä¼æåºå¼å¸¸ã
### SortedSet
**SortedSet** ä¸çå
ç´ ä¿è¯ææåºè§å顺åºï¼ **SortedSet** æ¥å£ä¸ç以䏿¹æ³å¯ä»¥äº§çå
¶ä»åè½ï¼
- `Comparator comparator()` ï¼çæç¨äºæ¤ **Set** ç**Comparator** æ **null** æ¥ç¨äºèªç¶æåºã
- `Object first()` ï¼è¿å第ä¸ä¸ªå
ç´ ã
- `Object last()` ï¼è¿åæåä¸ä¸ªå
ç´ ã
- `SortedSet subSet(fromElementï¼toElement)` ï¼ä½¿ç¨ **fromElement** ï¼å
å«ï¼å **toElement** ï¼ä¸å
æ¬ï¼ä¸çå
ç´ çææ¤ **Set** çä¸ä¸ªè§å¾ã
- `SortedSet headSet(toElement)` ï¼ä½¿ç¨é¡ºåºå¨ **toElement** ä¹åçå
ç´ çææ¤ **Set** çä¸ä¸ªè§å¾ã
- `SortedSet tailSet(fromElement)` ï¼ä½¿ç¨é¡ºåºå¨ **fromElement** ä¹åï¼å
å« **fromElement** ï¼çå
ç´ çææ¤ **Set** çä¸ä¸ªè§å¾ã
ä¸é¢æ¯ä¸ä¸ªç®åçæ¼ç¤ºï¼
```java
// collectiontopics/SortedSetDemo.java
import java.util.*;
import static java.util.stream.Collectors.*;
public class SortedSetDemo {
public static void main(String[] args) {
SortedSet sortedSet =
Arrays.stream(
"one two three four five six seven eight"
.split(" "))
.collect(toCollection(TreeSet::new));
System.out.println(sortedSet);
String low = sortedSet.first();
String high = sortedSet.last();
System.out.println(low);
System.out.println(high);
Iterator it = sortedSet.iterator();
for(int i = 0; i <= 6; i++) {
if(i == 3) low = it.next();
if(i == 6) high = it.next();
else it.next();
}
System.out.println(low);
System.out.println(high);
System.out.println(sortedSet.subSet(low, high));
System.out.println(sortedSet.headSet(high));
System.out.println(sortedSet.tailSet(low));
}
}
/* Output:
[eight, five, four, one, seven, six, three, two]
eight
two
one
two
[one, seven, six, three]
[eight, five, four, one, seven, six, three]
[one, seven, six, three, two]
*/
```
注æï¼ **SortedSet** è¡¨ç¤ºâæ ¹æ®å¯¹è±¡çæ¯è¾å½æ°è¿è¡æåºâï¼è䏿¯âæ ¹æ®æå
¥é¡ºåºâãå¯ä»¥ä½¿ç¨ **LinkedHashSet** ä¿çå
ç´ çæå
¥é¡ºåºã
## éå
æè®¸å¤ **Queue** å®ç°ï¼å
¶ä¸å¤§å¤æ°æ¯ä¸ºå¹¶ååºç¨ç¨åºè®¾è®¡çã许å¤å®ç°é½æ¯éè¿æåºè¡ä¸ºè䏿¯æ§è½æ¥åºåçãè¿æ¯ä¸ä¸ªæ¶å大夿° **Queue** å®ç°çåºæ¬ç¤ºä¾ï¼å
æ¬åºäºå¹¶åçéåãéåå°å
ç´ ä»ä¸ç«¯æ¾å
¥å¹¶ä»å¦ä¸ç«¯ååºï¼
```java
// collectiontopics/QueueBehavior.java
// Compares basic behavior
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
public class QueueBehavior {
static Stream strings() {
return Arrays.stream(
("one two three four five six seven " +
"eight nine ten").split(" "));
}
static void test(int id, Queue queue) {
System.out.print(id + ": ");
strings().map(queue::offer).count();
while(queue.peek() != null)
System.out.print(queue.remove() + " ");
System.out.println();
}
public static void main(String[] args) {
int count = 10;
test(1, new LinkedList<>());
test(2, new PriorityQueue<>());
test(3, new ArrayBlockingQueue<>(count));
test(4, new ConcurrentLinkedQueue<>());
test(5, new LinkedBlockingQueue<>());
test(6, new PriorityBlockingQueue<>());
test(7, new ArrayDeque<>());
test(8, new ConcurrentLinkedDeque<>());
test(9, new LinkedBlockingDeque<>());
test(10, new LinkedTransferQueue<>());
test(11, new SynchronousQueue<>());
}
}
/* Output:
1: one two three four five six seven eight nine ten
2: eight five four nine one seven six ten three two
3: one two three four five six seven eight nine ten
4: one two three four five six seven eight nine ten
5: one two three four five six seven eight nine ten
6: eight five four nine one seven six ten three two
7: one two three four five six seven eight nine ten
8: one two three four five six seven eight nine ten
9: one two three four five six seven eight nine ten
10: one two three four five six seven eight nine ten
11:
*/
```
**Deque** æ¥å£ä¹ç»§æ¿èª **Queue** ã é¤ä¼å
级éåå¤ï¼**Queue** æç
§å
ç´ çæå
¥é¡ºåºçæå
ç´ ã 卿¤ç¤ºä¾ä¸ï¼**SynchronousQueue** ä¸ä¼äº§çä»»ä½ç»æï¼å ä¸ºå®æ¯ä¸ä¸ªé»å¡éåï¼å
¶ä¸æ¯ä¸ªæå
¥æä½å¿
é¡»çå¾
å¦ä¸ä¸ªçº¿ç¨æ§è¡ç¸åºçå 餿ä½ï¼åä¹äº¦ç¶ã
### ä¼å
级éå
èèä¸ä¸ªå¾
åäºé¡¹å表ï¼å
¶ä¸æ¯ä¸ªå¯¹è±¡å
å«ä¸ä¸ª **String** 以å主è¦å次è¦ä¼å
级å¼ãéè¿å®ç° **Comparable** æ¥å£æ¥æ§å¶æ¤å¾
åäºé¡¹å表ç顺åºï¼
```java
// collectiontopics/ToDoList.java
// A more complex use of PriorityQueue
import java.util.*;
class ToDoItem implements Comparable {
private char primary;
private int secondary;
private String item;
ToDoItem(String td, char pri, int sec) {
primary = pri;
secondary = sec;
item = td;
}
@Override
public int compareTo(ToDoItem arg) {
if(primary > arg.primary)
return +1;
if(primary == arg.primary)
if(secondary > arg.secondary)
return +1;
else if(secondary == arg.secondary)
return 0;
return -1;
}
@Override
public String toString() {
return Character.toString(primary) +
secondary + ": " + item;
}
}
class ToDoList {
public static void main(String[] args) {
PriorityQueue toDo =
new PriorityQueue<>();
toDo.add(new ToDoItem("Empty trash", 'C', 4));
toDo.add(new ToDoItem("Feed dog", 'A', 2));
toDo.add(new ToDoItem("Feed bird", 'B', 7));
toDo.add(new ToDoItem("Mow lawn", 'C', 3));
toDo.add(new ToDoItem("Water lawn", 'A', 1));
toDo.add(new ToDoItem("Feed cat", 'B', 1));
while(!toDo.isEmpty())
System.out.println(toDo.remove());
}
}
/* Output:
A1: Water lawn
A2: Feed dog
B1: Feed cat
B7: Feed bird
C3: Mow lawn
C4: Empty trash
*/
```
è¿å±ç¤ºäºéè¿ä¼å
级éåèªå¨æåºå¾
åäºé¡¹ã
### å端éå
**Deque** ï¼å端éåï¼å°±åä¸ä¸ªéåï¼ä½æ¯å¯ä»¥ä»ä»»ä¸ç«¯æ·»å åå é¤å
ç´ ã Java 6为 **Deque** æ·»å äºä¸ä¸ªæ¾å¼æ¥å£ã以䏿¯å¯¹å®ç°äº **Deque** çç±»çæåºæ¬ç **Deque** æ¹æ³çæµè¯ï¼
```java
// collectiontopics/SimpleDeques.java
// Very basic test of Deques
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
class CountString implements Supplier {
private int n = 0;
CountString() {}
CountString(int start) { n = start; }
@Override
public String get() {
return Integer.toString(n++);
}
}
public class SimpleDeques {
static void test(Deque deque) {
CountString s1 = new CountString(),
s2 = new CountString(20);
for(int n = 0; n < 8; n++) {
deque.offerFirst(s1.get());
deque.offerLast(s2.get()); // Same as offer()
}
System.out.println(deque);
String result = "";
while(deque.size() > 0) {
System.out.print(deque.peekFirst() + " ");
result += deque.pollFirst() + " ";
System.out.print(deque.peekLast() + " ");
result += deque.pollLast() + " ";
}
System.out.println("\n" + result);
}
public static void main(String[] args) {
int count = 10;
System.out.println("LinkedList");
test(new LinkedList<>());
System.out.println("ArrayDeque");
test(new ArrayDeque<>());
System.out.println("LinkedBlockingDeque");
test(new LinkedBlockingDeque<>(count));
System.out.println("ConcurrentLinkedDeque");
test(new ConcurrentLinkedDeque<>());
}
}
/* Output:
LinkedList
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26,
27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
ArrayDeque
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26,
27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
LinkedBlockingDeque
[4, 3, 2, 1, 0, 20, 21, 22, 23, 24]
4 24 3 23 2 22 1 21 0 20
4 24 3 23 2 22 1 21 0 20
ConcurrentLinkedDeque
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26,
27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
*/
```
æåªä½¿ç¨äº **Deque** æ¹æ³çâofferâåâpollâçæ¬ï¼å ä¸ºå½ **LinkedBlockingDeque** ç大尿鿶ï¼è¿äºæ¹æ³ä¸ä¼æåºå¼å¸¸ã请注æï¼ **LinkedBlockingDeque** ä»
å¡«å
å°å®çéå¶å¤§å°ä¸ºæ¢ï¼ç¶å忽ç¥é¢å¤çæ·»å ã
## çè§£Map
æ£å¦å¨[第åäºç« éå]()ç« è䏿äºè§£å°çï¼**Map**ï¼ä¹ç§°ä¸º *å
³èæ°ç»* ï¼ç»´æ¤é®å¼å
³èï¼å¯¹ï¼ï¼å æ¤å¯ä»¥ä½¿ç¨é®æ¥æ¥æ¾å¼ãæ å Java åºå
å«ä¸åç **Map** åºæ¬å®ç°ï¼ä¾å¦ **HashMap** ï¼ **TreeMap** ï¼ **LinkedHashMap** ï¼ **WeakHashMap** ï¼ **ConcurrentHashMap** å **IdentityHashMap** ã å®ä»¬é½å
·æç¸åçåºæ¬ **Map** æ¥å£ï¼ä½å®ä»¬çè¡ä¸ºä¸åï¼å
æ¬æçï¼é®å¼å¯¹çä¿å顺åºååç°é¡ºåºï¼ä¿åå¯¹è±¡çæ¶é´ï¼å¦ä½å¨å¤çº¿ç¨ç¨åºä¸å·¥ä½ï¼ä»¥åå¦ä½ç¡®å®é®çç¸çæ§ã **Map** æ¥å£çå®ç°æ°éåºè¯¥åè¯ä½ ä¸äºå
³äºæ¤å·¥å
·éè¦æ§çä¿¡æ¯ã
ä¸ºäºæ´æ·±å
¥å°äºè§£ **Map** ï¼å¦ä¹ å¦ä½æé å
³èæ°ç»ä¼å¾æå¸®å©ãä¸é¢æ¯ä¸ä¸ªé常ç®åçå®ç°ï¼
```java
// collectiontopics/AssociativeArray.java
// Associates keys with values
public class AssociativeArray {
private Object[][] pairs;
private int index;
public AssociativeArray(int length) {
pairs = new Object[length][2];
}
public void put(K key, V value) {
if(index >= pairs.length)
throw new ArrayIndexOutOfBoundsException();
pairs[index++] = new Object[]{ key, value };
}
@SuppressWarnings("unchecked")
public V get(K key) {
for(int i = 0; i < index; i++)
if(key.equals(pairs[i][0]))
return (V)pairs[i][1];
return null; // Did not find key
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for(int i = 0; i < index; i++) {
result.append(pairs[i][0].toString());
result.append(" : ");
result.append(pairs[i][1].toString());
if(i < index - 1)
result.append("\n");
}
return result.toString();
}
public static void main(String[] args) {
AssociativeArray map =
new AssociativeArray<>(6);
map.put("sky", "blue");
map.put("grass", "green");
map.put("ocean", "dancing");
map.put("tree", "tall");
map.put("earth", "brown");
map.put("sun", "warm");
try {
map.put("extra", "object"); // Past the end
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Too many objects!");
}
System.out.println(map);
System.out.println(map.get("ocean"));
}
}
/* Output:
Too many objects!
sky : blue
grass : green
ocean : dancing
tree : tall
earth : brown
sun : warm
dancing
*/
```
å
³èæ°ç»ä¸çåºæ¬æ¹æ³æ¯ `put()` å `get()` ï¼ä½ä¸ºäºä¾¿äºæ¾ç¤ºï¼éåäº `toString()` æ¹æ³ä»¥æå°é®å¼å¯¹ãä¸ºäºæ¾ç¤ºå®çå·¥ä½åçï¼ä¸»æ¹æ³å è½½ä¸ä¸ªå¸¦æå符串对ç **AssociativeArray** å¹¶æå°çæçæ å°ï¼ç¶åè°ç¨å
¶ä¸ä¸ä¸ªå¼ç `get()` æ¹æ³ã
è¦ä½¿ç¨ `get()` æ¹æ³ï¼å¯ä»¥ä¼ å
¥è¦æ¥æ¾ç **key** ï¼å®å°çæç¸å
³èçå¼ä½ä¸ºç»æï¼å¦ææ¾ä¸å°åè¿å **null** ã `get()` æ¹æ³ä½¿ç¨å¯è½æ¯æçæä½çæ¹æ³æ¥å®ä½å¼ï¼ä»æ°ç»ç头é¨å¼å§å¹¶ä½¿ç¨ `equals()` æ¥æ¯è¾é®ãä½è¿éæ¯ä¾§éäºç®åï¼è䏿¯æçã
è¿ä¸ªçæ¬å¾æå¯åæ§ï¼ä½å®ä¸æ¯å¾ææï¼èä¸å®åªæä¸ä¸ªåºå®ç大å°ï¼è¿æ¯ä¸çµæ´»çã幸è¿çæ¯ï¼ **java.util** ä¸çé£äº **Map** 没æè¿äºé®é¢ã
### æ§è½
æ§è½æ¯ **Map** çåºæ¬é®é¢ï¼å¨ `get()` ä¸ä½¿ç¨çº¿æ§æ¹æ³æç´¢ä¸ä¸ªé®æ¶ä¼é常æ
¢ãè¿å°±æ¯ **HashMap** è¦å éçå°æ¹ãå®ä½¿ç¨ä¸ä¸ªç§°ä¸º *åå¸ç * çç¹æ®å¼æ¥æ¿ä»£æ
¢éæç´¢ä¸ä¸ªé®ãåå¸ç æ¯ä¸ç§ä»ç¸å
³å¯¹è±¡ä¸è·åä¸äºä¿¡æ¯å¹¶å°å
¶è½¬æ¢ä¸ºè¯¥å¯¹è±¡çâç¸å¯¹å¯ä¸â **int** çæ¹æ³ã `hashCode()` æ¯æ ¹ç±» **Object** ä¸çä¸ä¸ªæ¹æ³ï¼å æ¤ææ Java 对象é½å¯ä»¥çæåå¸ç ã **HashMap** è·å对象ç `hashCode()` 并使ç¨å®æ¥å¿«éæç´¢é®ãè¿å°±ä½¿å¾æ§è½æäºæ¾èçæåã[^3]
以䏿¯åºæ¬ç **Map** å®ç°ã **HashMap**ä¸çæå·è¡¨ç¤ºï¼å¨æ²¡æå
¶ä»çº¦æçæ
åµä¸ï¼è¿åºè¯¥æ¯ä½ çé»è®¤éæ©ï¼å 为å®é对é度è¿è¡äºä¼åãå
¶ä»å®ç°å¼ºè°å
¶ä»ç¹æ§ï¼å æ¤ä¸å¦ **HashMap** å¿«ã
| **Map** å®ç° | æè¿° |
| :---: | :--- |
| **HashMap\*** | åºäºåå¸è¡¨çå®ç°ãï¼ä½¿ç¨æ¤ç±»æ¥ä»£æ¿ **Hashtable** ãï¼ä¸ºæå
¥åå®ä½é®å¼å¯¹æä¾äºå¸¸æ°æ¶é´æ§è½ãå¯ä»¥éè¿æé æ¹æ³è°æ´æ§è½ï¼è¿äºæé æ¹æ³å
è®¸ä½ è®¾ç½®åå¸è¡¨ç容éåè£
å¡«å åã |
| **LinkedHashMap** | ä¸ **HashMap** 类似ï¼ä½æ¯å½éåæ¶ï¼å¯ä»¥ææå
¥é¡ºåºææè¿æå°ä½¿ç¨ï¼LRUï¼é¡ºåºè·åé®å¼å¯¹ãåªæ¯ **HashMap** ç¥æ
¢ï¼ä¸ä¸ªä¾å¤æ¯å¨è¿ä»£æ¶ï¼ç±äºå
¶ä½¿ç¨é¾è¡¨ç»´æ¤å
é¨é¡ºåºï¼æä»¥ä¼æ´å¿«äºã |
| **TreeMap** | åºäºçº¢é»æ çå®ç°ã彿¥ç鮿é®å¼å¯¹æ¶ï¼å®ä»¬ææåºé¡ºåºï¼ç± **Comparable** æ **Comparator** ç¡®å®ï¼ã **TreeMap** çä¾§éç¹æ¯ææåºé¡ºåºè·å¾ç»æã **TreeMap** æ¯å¯ä¸ä½¿ç¨ `subMap()` æ¹æ³ç **Map** ï¼å®è¿åçº¢é»æ çä¸é¨åã |
| **WeakHashMap** | ä¸ç§å
·æ *å¼±é®*ï¼weak keysï¼ ç **Map** ï¼ä¸ºäºè§£å³æäºç±»åçé®é¢ï¼å®å
è®¸éæ¾ **Map** æå¼ç¨ç对象ãå¦æå¨ **Map** 夿²¡æå¯¹ç¹å®é®çå¼ç¨ï¼åå¯ä»¥å¯¹è¯¥é®è¿è¡åå¾åæ¶ã |
| **ConcurrentHashMap** | ä¸ä½¿ç¨åæ¥éå®ç线ç¨å®å
¨ **Map** ãè¿å¨[第äºååç« å¹¶åç¼ç¨]() ä¸ç« ä¸è®¨è®ºã |
| **IdentityHashMap** | ä½¿ç¨ `==` è䏿¯ `equals()` æ¥æ¯è¾é®ãä»
ç¨äºè§£å³ç¹æ®é®é¢ï¼ä¸éç¨äºä¸è¬ç¨éã |
æ£åæ¯å¨ **Map** ä¸åå¨å
ç´ çæå¸¸ç¨æ¹æ³ã
**Map** ä¸ä½¿ç¨çé®çè¦æ±ä¸ **Set** ä¸çå
ç´ çè¦æ±ç¸åãå¯ä»¥å¨ **TypesForSets.java** ä¸çå°è¿äºãä»»ä½é®å¿
é¡»å
·æ `equals()` æ¹æ³ã妿é®ç¨äºæ£åæ å°ï¼åå®è¿å¿
é¡»å
·ææ£ç¡®ç `hashCode()` æ¹æ³ã妿é®å¨ **TreeMap** ä¸ä½¿ç¨ï¼åå¿
é¡»å®ç° **Comparable** æ¥å£ã
以ä¸ç¤ºä¾ä½¿ç¨å
åå®ä¹ç **CountMap** æµè¯æ°æ®éæ¾ç¤ºéè¿ **Map** æ¥å£å¯ç¨çæä½ï¼
```java
// collectiontopics/MapOps.java
// Things you can do with Maps
import java.util.concurrent.*;
import java.util.*;
import onjava.*;
public class MapOps {
public static
void printKeys(Map map) {
System.out.print("Size = " + map.size() + ", ");
System.out.print("Keys: ");
// Produce a Set of the keys:
System.out.println(map.keySet());
}
public static
void test(Map map) {
System.out.println(
map.getClass().getSimpleName());
map.putAll(new CountMap(25));
// Map has 'Set' behavior for keys:
map.putAll(new CountMap(25));
printKeys(map);
// Producing a Collection of the values:
System.out.print("Values: ");
System.out.println(map.values());
System.out.println(map);
System.out.println("map.containsKey(11): " +
map.containsKey(11));
System.out.println(
"map.get(11): " + map.get(11));
System.out.println("map.containsValue(\"F0\"): "
+ map.containsValue("F0"));
Integer key = map.keySet().iterator().next();
System.out.println("First key in map: " + key);
map.remove(key);
printKeys(map);
map.clear();
System.out.println(
"map.isEmpty(): " + map.isEmpty());
map.putAll(new CountMap(25));
// Operations on the Set change the Map:
map.keySet().removeAll(map.keySet());
System.out.println(
"map.isEmpty(): " + map.isEmpty());
}
public static void main(String[] args) {
test(new HashMap<>());
test(new TreeMap<>());
test(new LinkedHashMap<>());
test(new IdentityHashMap<>());
test(new ConcurrentHashMap<>());
test(new WeakHashMap<>());
}
}
/* Output: (First 11 Lines)
HashMap
Size = 25, Keys: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
Values: [A0, B0, C0, D0, E0, F0, G0, H0, I0, J0, K0,
L0, M0, N0, O0, P0, Q0, R0, S0, T0, U0, V0, W0, X0, Y0]
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0,
9=J0, 10=K0, 11=L0, 12=M0, 13=N0, 14=O0, 15=P0, 16=Q0,
17=R0, 18=S0, 19=T0, 20=U0, 21=V0, 22=W0, 23=X0, 24=Y0}
map.containsKey(11): true
map.get(11): L0
map.containsValue("F0"): true
First key in map: 0
Size = 24, Keys: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
map.isEmpty(): true
map.isEmpty(): true
...
*/
```
`printKeys()` æ¹æ³æ¼ç¤ºäºå¦ä½çæ **Map** ç **Collection** è§å¾ã `keySet()` æ¹æ³çæä¸ä¸ªç± **Map** ä¸çé®ç»æç **Set** ã æå° `values()` æ¹æ³çç»æä¼çæä¸ä¸ªå
å« **Map** 䏿æå¼ç **Collection** ãï¼è¯·æ³¨æï¼é®å¿
é¡»æ¯å¯ä¸çï¼ä½å¼å¯ä»¥å
å«éå¤é¡¹ãï¼ç±äºè¿äº **Collection** ç± **Map** æ¯æï¼å æ¤ **Collection** ä¸ç任使´æ¹é½ä¼åæ 卿å
³èç **Map** ä¸ã
ç¨åºçå
¶ä½é¨åæä¾äºæ¯ä¸ª **Map** æä½çç®å示ä¾ï¼å¹¶æµè¯äºæ¯ç§åºæ¬ç±»åç **Map** ã
### SortedMap
ä½¿ç¨ **SortedMap** ï¼ç± **TreeMap** æ **ConcurrentSkipListMap** å®ç°ï¼ï¼é®ä¿è¯ææåºé¡ºåºï¼è¿å
è®¸å¨ **SortedMap** æ¥å£ä¸ä½¿ç¨è¿äºæ¹æ³æ¥æä¾å
¶ä»åè½ï¼
- `Comparator comparator()` ï¼çæç¨äºæ¤ **Map** çæ¯è¾å¨ï¼ **null** 表示èªç¶æåºã
- `T firstKey()` ï¼è¿å第ä¸ä¸ªé®ã
- `T lastKey()` ï¼è¿åæåä¸ä¸ªé®ã
- `SortedMap subMap(fromKeyï¼toKey)` ï¼çææ¤ **Map** çè§å¾ï¼å
¶ä¸é®ä» **fromKey**ï¼å
æ¬ï¼ï¼å° **toKey** ï¼ä¸å
æ¬ï¼ã
- `SortedMap headMap(toKey)` ï¼ä½¿ç¨å°äº **toKey** çé®çææ¤ **Map** çè§å¾ã
- `SortedMap tailMap(fromKey)` ï¼ä½¿ç¨å¤§äºæçäº **fromKey** çé®çææ¤ **Map** çè§å¾ã
è¿æ¯ä¸ä¸ªç±»ä¼¼äº **SortedSetDemo.java** ç示ä¾ï¼æ¾ç¤ºäº **TreeMap** çè¿ç§é¢å¤è¡ä¸ºï¼
```java
// collectiontopics/SortedMapDemo.java
// What you can do with a TreeMap
import java.util.*;
import onjava.*;
public class SortedMapDemo {
public static void main(String[] args) {
TreeMap sortedMap =
new TreeMap<>(new CountMap(10));
System.out.println(sortedMap);
Integer low = sortedMap.firstKey();
Integer high = sortedMap.lastKey();
System.out.println(low);
System.out.println(high);
Iterator it =
sortedMap.keySet().iterator();
for(int i = 0; i <= 6; i++) {
if(i == 3) low = it.next();
if(i == 6) high = it.next();
else it.next();
}
System.out.println(low);
System.out.println(high);
System.out.println(sortedMap.subMap(low, high));
System.out.println(sortedMap.headMap(high));
System.out.println(sortedMap.tailMap(low));
}
}
/* Output:
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0,
9=J0}
0
9
3
7
{3=D0, 4=E0, 5=F0, 6=G0}
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0}
{3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0, 9=J0}
*/
```
è¿éï¼é®å¼å¯¹æç
§é®çæåºé¡ºåºè¿è¡æåºãå 为 **TreeMap** ä¸åå¨é¡ºåºæï¼æä»¥âä½ç½®âçæ¦å¿µå¾ææä¹ï¼å æ¤å¯ä»¥æ¥æç¬¬ä¸ä¸ªãæåä¸ä¸ªå
ç´ æåå¾ã
### LinkedHashMap
**LinkedHashMap** é对é度è¿è¡åå¸å¤çï¼ä½å¨éåæé´ä¹ä¼ææå
¥é¡ºåºçæé®å¼å¯¹ï¼ `System.out.println()` å¯ä»¥éåå®ï¼å æ¤å¯ä»¥çå°éåçç»æï¼ã æ¤å¤ï¼å¯ä»¥å¨æé æ¹æ³ä¸é
ç½® **LinkedHashMap** 以使ç¨åºäºè®¿é®ç *æè¿æå°ä½¿ç¨*ï¼LRUï¼ ç®æ³ï¼å æ¤æªè®¿é®çå
ç´ ï¼å æ¤æ¯å é¤çåéè
ï¼ä¼åºç°å¨å表çåé¢ã è¿æ ·å¯ä»¥è½»æ¾å建ä¸ä¸ªè½å¤å®ææ¸
ç以èç空é´çç¨åºãä¸é¢æ¯ä¸ä¸ªæ¾ç¤ºè¿ä¸¤ä¸ªåè½çç®å示ä¾ï¼
```java
// collectiontopics/LinkedHashMapDemo.java
// What you can do with a LinkedHashMap
import java.util.*;
import onjava.*;
public class LinkedHashMapDemo {
public static void main(String[] args) {
LinkedHashMap linkedMap =
new LinkedHashMap<>(new CountMap(9));
System.out.println(linkedMap);
// Least-recently-used order:
linkedMap =
new LinkedHashMap<>(16, 0.75f, true);
linkedMap.putAll(new CountMap(9));
System.out.println(linkedMap);
for(int i = 0; i < 6; i++)
linkedMap.get(i);
System.out.println(linkedMap);
linkedMap.get(0);
System.out.println(linkedMap);
}
}
/* Output:
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0}
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0}
{6=G0, 7=H0, 8=I0, 0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0}
{6=G0, 7=H0, 8=I0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 0=A0}
*/
```
è¿äºé®å¼å¯¹ç¡®å®æ¯æç
§æå
¥é¡ºåºè¿è¡éåï¼å³ä½¿å¯¹äºLRUçæ¬ä¹æ¯å¦æ¤ã 使¯ï¼å¨LRUçæ¬ä¸è®¿é®åå
项ï¼ä»
éï¼åï¼æåä¸é¡¹å°ç§»è³å表çåé¢ãç¶åï¼å½å次访é®â **0** âåï¼å®ç§»å¨å°äºå表çåé¢ã
## éåå·¥å
·ç±»
éåæè®¸å¤ç¬ç«çå®ç¨å·¥å
·ç¨åºï¼å¨ **java.util.Collections** ä¸è¡¨ç¤ºä¸ºéææ¹æ³ãä¹åå·²ç»è§è¿å
¶ä¸ä¸äºï¼ä¾å¦ `addAll()` ï¼ `reverseOrder()` å `binarySearch()` ã以䏿¯å
¶ä»å
容ï¼åæ¥åä¸å¯ä¿®æ¹çå®ç¨å·¥å
·ç¨åºå°å¨åé¢çç« èä¸ä»ç»ï¼ã卿¤è¡¨ä¸ï¼å¨éè¦çæ¶å使ç¨äºæ³åï¼
| æ¹æ³ | æè¿° |
| :--- | :--- |
| **checkedCollection(Collection\ c, Class\ type)**
**checkedList(List\ list, Class\ type)**
**checkedMap(Map\ m, Class\ keyType, Class\ valueType)**
**checkedSet(Set\ s, Class\ type)**
**checkedSortedMap(SortedMap\ m, Class\ keyType, Class\ valueType)**
**checkedSortedSet(SortedSet\ s, Class\ type)** | çæ **Collection** çå¨æç±»åå®å
¨è§å¾æ **Collection** çç¹å®åç±»åã 彿 æ³ä½¿ç¨éææ£æ¥çæ¬æ¶ä½¿ç¨è¿ä¸ªçæ¬ã
è¿äºæ¹æ³ç使ç¨å¨[第ä¹ç« 夿]()ç« èçâå¨æç±»åå®å
¨âæ é¢ä¸è¿è¡äºå±ç¤ºã |
| **max(Collection)**
**min(Collection)** | ä½¿ç¨ **Collection** ä¸å¯¹è±¡çèªç¶æ¯è¾æ¹æ³çæåæ°éåä¸çæå¤§ææå°å
ç´ ã |
| **max(Collection, Comparator)**
**min(Collection, Comparator)** | ä½¿ç¨ **Comparator** æå®çæ¯è¾æ¹æ³çæåæ°éåä¸çæå¤§ææå°å
ç´ ã |
| **indexOfSubList(List source, List target)** | è¿å **target** å¨ **source** å
ç¬¬ä¸æ¬¡åºç°çèµ·å§ç´¢å¼ï¼å¦æä¸åå¨åè¿å -1ã |
| **lastIndexOfSubList(List source, List target)** | è¿å **target** å¨ **source** å
æå䏿¬¡åºç°çèµ·å§ç´¢å¼ï¼å¦æä¸åå¨åè¿å -1ã |
| **replaceAll(List\ list, T oldVal, T newVal)** | ç¨ **newVal** æ¿æ¢åè¡¨ä¸ææç **oldVal** ã |
| **reverse(List)**| å转å表 |
| **reverseOrder()**
**reverseOrder(Comparator\)** | è¿åä¸ä¸ª **Comparator** ï¼å®ä¸éåä¸å®ç°äº **comparable\** æ¥å£ç对象çèªç¶é¡ºåºç¸åã第äºä¸ªçæ¬é¢ åäºææä¾ç **Comparator** ç顺åºã |
| **rotate(List, int distance)** | å°ææå
ç´ ååç§»å¨ **distance** ï¼å°å°¾é¨çå
ç´ ç§»å°å¼å¤´ãï¼è¯è
注ï¼å³å¾ªç¯ç§»å¨ï¼ |
| **shuffle(List)**
**shuffle(List, Random)** | éæºç½®æ¢æå®å表ï¼å³æä¹±é¡ºåºï¼ã第ä¸ä¸ªçæ¬ä½¿ç¨äºé»è®¤çéæºåæºï¼æè
ä¹å¯ä»¥ä½¿ç¨ç¬¬äºä¸ªçæ¬ï¼æä¾èªå·±çéæºåæºã |
| **sort(List\)**
**sort(List\, Comparator\ super T> c)** | 第ä¸ä¸ªçæ¬ä½¿ç¨å
ç´ çèªç¶é¡ºåºæåºè¯¥ **List\** ã第äºä¸ªçæ¬æ ¹æ®æä¾ç **Comparator** æåºã |
| **copy(List\ super T> dest, List\ extends T> src)** | å° **src** ä¸çå
ç´ å¤å¶å° **dest** ã |
| **swap(List, int i, int j)** | äº¤æ¢ **List** ä¸ä½ç½® **i** å ä½ç½® **j** çå
ç´ ãå¯è½æ¯ä½ æå·¥ç¼åçé度快ã |
| **fill(List\ super T>, T x)** | ç¨ **x** æ¿æ¢ **List** ä¸çææå
ç´ ã|
| **nCopies(int n, T x)** | è¿å大å°ä¸º **n** çä¸å¯å **List\** ï¼å
¶å¼ç¨é½æå **x** ã |
| **disjoint(Collection, Collection)** | å¦æä¸¤ä¸ªéåæ²¡æå
±åå
ç´ ï¼åè¿å **true** ã |
| **frequency(Collection, Object x)** | è¿å **Collection** ä¸ï¼çäº **x** çå
ç´ ä¸ªæ°ã |
| **emptyList()**
**emptyMap()**
**emptySet()** | è¿åä¸å¯åç空 **List** ï¼ **Map** æ **Set** ãè¿äºæ¯æ³åçï¼å æ¤çæç **Collection** å¯ä»¥è¢«åæ°å为æéçç±»åã |
| **singleton(T x)**
**singletonList(T x)**
**singletonMap(K key, V value)** | çæä¸ä¸ªä¸å¯åç **List** ï¼ **Set** æ **Map** ï¼å
¶ä¸åªå
å«åºäºç»å®åæ°çå个å
ç´ ã |
| **list(Enumeration\ e)** | çæä¸ä¸ª **ArrayList\** ï¼å
¶ä¸å
ç´ ä¸ºï¼æ§å¼ï¼ **Enumeration** ï¼ **Iterator** çå身ï¼ä¸çå
ç´ ãç¨äºä»éç代ç åæ°å¼è½¬æ¢ã |
| **enumeration(Collection\)** | ä¸ºåæ°éåçæä¸ä¸ªæ§å¼ç **Enumeration\** ã |
请注æï¼ `minï¼)` å `max()` ä½¿ç¨ **Collection** 对象ï¼èä¸ä½¿ç¨ **List** ï¼å æ¤ä¸å¿
æ
å¿æ¯å¦åºå¯¹ **Collection** è¿è¡æåºãï¼å¦åæè¿°ï¼å¨æ§è¡ `binarySearch()` ä¹åï¼å°ä¼å¯¹ **List** ææ°ç»è¿è¡`sort()` æåºãï¼
ä¸é¢æ¯ä¸ä¸ªç¤ºä¾ï¼å±ç¤ºäºä¸è¡¨ä¸å¤§å¤æ°å®ç¨å·¥å
·ç¨åºçåºæ¬ç¨æ³ï¼
```java
// collectiontopics/Utilities.java
// Simple demonstrations of the Collections utilities
import java.util.*;
public class Utilities {
static List list = Arrays.asList(
"one Two three Four five six one".split(" "));
public static void main(String[] args) {
System.out.println(list);
System.out.println("'list' disjoint (Four)?: " +
Collections.disjoint(list,
Collections.singletonList("Four")));
System.out.println(
"max: " + Collections.max(list));
System.out.println(
"min: " + Collections.min(list));
System.out.println(
"max w/ comparator: " + Collections.max(list,
String.CASE_INSENSITIVE_ORDER));
System.out.println(
"min w/ comparator: " + Collections.min(list,
String.CASE_INSENSITIVE_ORDER));
List sublist =
Arrays.asList("Four five six".split(" "));
System.out.println("indexOfSubList: " +
Collections.indexOfSubList(list, sublist));
System.out.println("lastIndexOfSubList: " +
Collections.lastIndexOfSubList(list, sublist));
Collections.replaceAll(list, "one", "Yo");
System.out.println("replaceAll: " + list);
Collections.reverse(list);
System.out.println("reverse: " + list);
Collections.rotate(list, 3);
System.out.println("rotate: " + list);
List source =
Arrays.asList("in the matrix".split(" "));
Collections.copy(list, source);
System.out.println("copy: " + list);
Collections.swap(list, 0, list.size() - 1);
System.out.println("swap: " + list);
Collections.shuffle(list, new Random(47));
System.out.println("shuffled: " + list);
Collections.fill(list, "pop");
System.out.println("fill: " + list);
System.out.println("frequency of 'pop': " +
Collections.frequency(list, "pop"));
List dups =
Collections.nCopies(3, "snap");
System.out.println("dups: " + dups);
System.out.println("'list' disjoint 'dups'?: " +
Collections.disjoint(list, dups));
// Getting an old-style Enumeration:
Enumeration e =
Collections.enumeration(dups);
Vector v = new Vector<>();
while(e.hasMoreElements())
v.addElement(e.nextElement());
// Converting an old-style Vector
// to a List via an Enumeration:
ArrayList arrayList =
Collections.list(v.elements());
System.out.println("arrayList: " + arrayList);
}
}
/* Output:
[one, Two, three, Four, five, six, one]
'list' disjoint (Four)?: false
max: three
min: Four
max w/ comparator: Two
min w/ comparator: five
indexOfSubList: 3
lastIndexOfSubList: 3
replaceAll: [Yo, Two, three, Four, five, six, Yo]
reverse: [Yo, six, five, Four, three, Two, Yo]
rotate: [three, Two, Yo, Yo, six, five, Four]
copy: [in, the, matrix, Yo, six, five, Four]
swap: [Four, the, matrix, Yo, six, five, in]
shuffled: [six, matrix, the, Four, Yo, five, in]
fill: [pop, pop, pop, pop, pop, pop, pop]
frequency of 'pop': 7
dups: [snap, snap, snap]
'list' disjoint 'dups'?: true
arrayList: [snap, snap, snap]
*/
```
è¾åºè§£éäºæ¯ç§å®ç¨æ¹æ³çè¡ä¸ºã请注æç±äºå¤§å°åçç¼æ
ï¼æ®éçæ¬ç `min()` å `max()` ä¸å¸¦æ **String.CASE_INSENSITIVE_ORDER** æ¯è¾å¨åæ°ççæ¬çåºå«ã
### æåºåæç´¢å表
ç¨äºæ§è¡æåºåæç´¢ **List** çå®ç¨å·¥å
·ç¨åºä¸ç¨äºæåºå¯¹è±¡æ°ç»çç¨åºå
·æç¸åçåååæ¹æ³ç¾åï¼åªä¸è¿æ¯ **Collections** çéææ¹æ³è䏿¯ **Arrays** ã è¿æ¯ä¸ä¸ªä½¿ç¨ **Utilities.java** ä¸ç **list** æ°æ®ç示ä¾ï¼
```java
// collectiontopics/ListSortSearch.java
// Sorting/searching Lists with Collections utilities
import java.util.*;
public class ListSortSearch {
public static void main(String[] args) {
List list =
new ArrayList<>(Utilities.list);
list.addAll(Utilities.list);
System.out.println(list);
Collections.shuffle(list, new Random(47));
System.out.println("Shuffled: " + list);
// Use ListIterator to trim off last elements:
ListIterator it = list.listIterator(10);
while(it.hasNext()) {
it.next();
it.remove();
}
System.out.println("Trimmed: " + list);
Collections.sort(list);
System.out.println("Sorted: " + list);
String key = list.get(7);
int index = Collections.binarySearch(list, key);
System.out.println(
"Location of " + key + " is " + index +
", list.get(" + index + ") = " +
list.get(index));
Collections.sort(list,
String.CASE_INSENSITIVE_ORDER);
System.out.println(
"Case-insensitive sorted: " + list);
key = list.get(7);
index = Collections.binarySearch(list, key,
String.CASE_INSENSITIVE_ORDER);
System.out.println(
"Location of " + key + " is " + index +
", list.get(" + index + ") = " +
list.get(index));
}
}
/* Output:
[one, Two, three, Four, five, six, one, one, Two,
three, Four, five, six, one]
Shuffled: [Four, five, one, one, Two, six, six, three,
three, five, Four, Two, one, one]
Trimmed: [Four, five, one, one, Two, six, six, three,
three, five]
Sorted: [Four, Two, five, five, one, one, six, six,
three, three]
Location of six is 7, list.get(7) = six
Case-insensitive sorted: [five, five, Four, one, one,
six, six, three, three, Two]
Location of three is 7, list.get(7) = three
*/
```
å°±åä½¿ç¨æ°ç»è¿è¡æç´¢åæåºä¸æ ·ï¼å¦æä½¿ç¨ **Comparator** è¿è¡æåºï¼åå¿
须使ç¨ç¸åç **Comparator** æ§è¡ `binarySearch()` ã
该ç¨åºè¿æ¼ç¤ºäº **Collections** ä¸ç `shuffle()` æ¹æ³ï¼è¯¥æ¹æ³éæºæä¹±äº **List** ç顺åºã **ListIterator** æ¯å¨æä¹±åçå表ä¸çç¹å®ä½ç½®å建çï¼ç¨äºä»è¯¥ä½ç½®å é¤å
ç´ ï¼ç´å°å表æ«å°¾ã
### å建ä¸å¯ä¿®æ¹ç Collection æ Map
é常ï¼å建 **Collection** æ **Map** çåªè¯»çæ¬ä¼å¾æ¹ä¾¿ã **Collections** ç±»éè¿å°åå§éåä¼ éç»ä¸ä¸ªæ¹æ³ç¶åè¿åä¸ä¸ªåªè¯»çæ¬çéåã å¯¹äº **Collection** ï¼å¦æä¸è½å° **Collection** è§ä¸ºæ´å
·ä½çç±»åï¼ï¼ **List** ï¼ **Set** å **Map** ï¼è¿ç±»æ¹æ³æè®¸å¤åä½ãè¿ä¸ªç¤ºä¾å±ç¤ºäºé对æ¯ç§ç±»åï¼æ£ç¡®æå»ºåªè¯»çæ¬éåçæ¹æ³ï¼
```java
// collectiontopics/ReadOnly.java
// Using the Collections.unmodifiable methods
import java.util.*;
import onjava.*;
public class ReadOnly {
static Collection data =
new ArrayList<>(Countries.names(6));
public static void main(String[] args) {
Collection c =
Collections.unmodifiableCollection(
new ArrayList<>(data));
System.out.println(c); // Reading is OK
//- c.add("one"); // Can't change it
List a = Collections.unmodifiableList(
new ArrayList<>(data));
ListIterator lit = a.listIterator();
System.out.println(lit.next()); // Reading is OK
//- lit.add("one"); // Can't change it
Set s = Collections.unmodifiableSet(
new HashSet<>(data));
System.out.println(s); // Reading is OK
//- s.add("one"); // Can't change it
// For a SortedSet:
Set ss =
Collections.unmodifiableSortedSet(
new TreeSet<>(data));
Map m =
Collections.unmodifiableMap(
new HashMap<>(Countries.capitals(6)));
System.out.println(m); // Reading is OK
//- m.put("Ralph", "Howdy!");
// For a SortedMap:
Map sm =
Collections.unmodifiableSortedMap(
new TreeMap<>(Countries.capitals(6)));
}
}
/* Output:
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI]
ALGERIA
[BENIN, BOTSWANA, ANGOLA, BURKINA FASO, ALGERIA,
BURUNDI]
{BENIN=Porto-Novo, BOTSWANA=Gaberone, ANGOLA=Luanda,
BURKINA FASO=Ouagadougou, ALGERIA=Algiers,
BURUNDI=Bujumbura}
*/
```
为ç¹å®ç±»åè°ç¨ âunmodifiableâ æ¹æ³ä¸ä¼å¯¼è´ç¼è¯æ¶æ£æ¥ï¼ä½æ¯ä¸æ¦åç转æ¢ï¼å¯¹ä¿®æ¹ç¹å®éåå
容ç任使¹æ³è°ç¨é½å°äº§ç **UnsupportedOperationException** å¼å¸¸ã
卿¯ç§æ
åµä¸ï¼å¨å°éå设置为åªè¯»ä¹åï¼å¿
é¡»ä½¿ç¨ææä¹çæ°æ®å¡«å
éåãå¡«å
宿åï¼æå¥½çæ¹æ³æ¯ç¨ âunmodifiableâ æ¹æ³è°ç¨çæçå¼ç¨æ¿æ¢ç°æå¼ç¨ãè¿æ ·ï¼ä¸æ¦ä½¿å¾å
å®¹æ æ³ä¿®æ¹ï¼é£ä¹å°±ä¸ä¼åææå¤æ´æ¹å
容çé£é©ãå¦ä¸æ¹é¢ï¼æ¤å·¥å
·è¿å
许å°å¯ä¿®æ¹çéåä¿ç为类ä¸ç**ç§æ**éåï¼å¹¶ä»æ¹æ³è°ç¨å¤è¿å对该éåçåªè¯»å¼ç¨ãæä»¥ï¼ä½ å¯ä»¥å¨ç±»å
ä¿®æ¹å®ï¼ä½å
¶ä»äººåªè½è¯»å®ã
### 忥 Collection æ Map
**synchronized** å
³é®åæ¯å¤çº¿ç¨ä¸»é¢çéè¦ç»æé¨åï¼æ´å¤æçå
容å¨[第äºååç« å¹¶åç¼ç¨]()ä¸ä»ç»ãå¨è¿éï¼åªéè¦æ³¨æå° **Collections** ç±»å
å«ä¸ç§èªå¨åæ¥æ´ä¸ªéåçæ¹æ³ã è¯æ³ç±»ä¼¼äº âunmodifiableâ æ¹æ³ï¼
```java
// collectiontopics/Synchronization.java
// Using the Collections.synchronized methods
import java.util.*;
public class Synchronization {
public static void main(String[] args) {
Collection c =
Collections.synchronizedCollection(
new ArrayList<>());
List list = Collections
.synchronizedList(new ArrayList<>());
Set s = Collections
.synchronizedSet(new HashSet<>());
Set ss = Collections
.synchronizedSortedSet(new TreeSet<>());
Map m = Collections
.synchronizedMap(new HashMap<>());
Map sm = Collections
.synchronizedSortedMap(new TreeMap<>());
}
}
```
æå¥½ç«å³éè¿éå½ç âsynchronizedâ æ¹æ³ä¼ éæ°éåï¼å¦ä¸æç¤ºãè¿æ ·ï¼å°±ä¸ä¼æå¤å°æ´é²åºéåæ¥çæ¬ã
#### Fail Fast
Java éåè¿å
·æé²æ¢å¤ä¸ªè¿ç¨ä¿®æ¹éåå
å®¹çæºå¶ã妿å½åæ£å¨è¿ä»£éåï¼ç¶åæå
¶ä»ä¸äºè¿ç¨ä»å
¥å¹¶æå
¥ï¼å é¤ææ´æ¹è¯¥éåä¸ç对象ï¼åä¼åºç°æ¤é®é¢ãä¹è®¸å¨éåä¸å·²ç»éåè¿äºé£ä¸ªå
ç´ ï¼ä¹è®¸è¿æ²¡æéåå°ï¼ä¹è®¸å¨è°ç¨ `size()` ä¹åéåç大å°ä¼ç¼©å°...æè®¸å¤ç¾é¾æ
æ¯ã Java éååºä½¿ç¨ä¸ç§ *fail-fast* çæºå¶ï¼è¯¥æºå¶å¯ä»¥æ£æµå°é¤äºå½åè¿ç¨å¼èµ·çæ´æ¹ä¹å¤ï¼å
¶å®ä»»ä½å¯¹éåçæ´æ¹æä½ã妿宿£æµå°å
¶ä»äººæ£å¨ä¿®æ¹éåï¼åä¼ç«å³çæ **ConcurrentModificationException** å¼å¸¸ãè¿å°±æ¯âfail-fastâçå«ä¹ââå®ä¸ä¼å¨ä»¥åä½¿ç¨æ´å¤æçç®æ³å°è¯æ£æµé®é¢ï¼å¿«é失败ï¼ã
éè¿å建è¿ä»£å¨å¹¶åè¿ä»£å¨æåçéå䏿·»å å
ç´ ï¼å¯ä»¥å¾å®¹æå°çå°æä½ä¸ç fail-fast æºå¶ï¼å¦ä¸æç¤ºï¼
```java
// collectiontopics/FailFast.java
// Demonstrates the "fail-fast" behavior
import java.util.*;
public class FailFast {
public static void main(String[] args) {
Collection c = new ArrayList<>();
Iterator it = c.iterator();
c.add("An object");
try {
String s = it.next();
} catch(ConcurrentModificationException e) {
System.out.println(e);
}
}
}
/* Output:
java.util.ConcurrentModificationException
*/
```
å¼å¸¸æ¥èªäºå¨ä»éåä¸è·å¾è¿ä»£å¨ä¹åï¼åå°è¯å¨éå䏿·»å å
ç´ ãç¨åºç两个é¨åå¯è½ä¼ä¿®æ¹åä¸ä¸ªéåï¼è¿ç§å¯è½æ§çåå¨ä¼äº§çä¸ç¡®å®ç¶æï¼å æ¤å¼å¸¸ä¼éç¥ä½ æ´æ¹ä»£ç ãå¨è¿ç§æ
åµä¸ï¼åºå
å°ææå
ç´ æ·»å å°éåï¼ç¶ååè·åè¿ä»£å¨ã
**ConcurrentHashMap** ï¼ **CopyOnWriteArrayList** å **CopyOnWriteArraySet** 使ç¨äºç¹å®çææ¯æ¥é¿å
产ç **ConcurrentModificationException** å¼å¸¸ã
## ææå¼ç¨
**java.lang.ref** ä¸åºå
å«ä¸ç»ç±»ï¼è¿äºç±»å
许å徿¶éå
·ææ´å¤§ççµæ´»æ§ãç¹å«æ¯å½æ¥æå¯è½å¯¼è´å
åèå°½ç大对象æ¶ï¼è¿äºç±»ç¹å«æç¨ãè¿éæä¸ä¸ªä»æ½è±¡ç±» **Reference** ç»§æ¿æ¥çç±»ï¼ **SoftReference** ï¼è½¯å¼ç¨ï¼ï¼ **WeakReference** ï¼å¼±å¼ç¨ï¼å **PhantomReference** ï¼èå¼ç¨ï¼ç»§æ¿äºä¸ä¸ªç±»ã妿ä¸ä¸ªå¯¹è±¡åªè½éè¿è¿å
¶ä¸çä¸ä¸ª **Reference** 对象访é®ï¼é£ä¹è¿ä¸ç§ç±»åæ¯ä¸ªé½ä¸ºå徿¶é卿ä¾ä¸å级å«çé´æ¥å¼ç¨ï¼indirectionï¼ã
妿ä¸ä¸ªå¯¹è±¡æ¯ *å¯è¾¾ç*ï¼reachableï¼ï¼é£ä¹æå³çå¨ç¨åºä¸çæä¸ªä½ç½®å¯ä»¥æ¾å°è¯¥å¯¹è±¡ãè¿å¯è½æå³ç卿 䏿ä¸ä¸ªç´æ¥å¼ç¨è¯¥å¯¹è±¡çæ®éå¼ç¨ï¼ä½ä¹æå¯è½æ¯å¼ç¨äºä¸ä¸ªå¯¹è¯¥å¯¹è±¡æå¼ç¨ç对象ï¼è¿å¯ä»¥æå¾å¤ä¸é´ç¯èã妿æä¸ªå¯¹è±¡æ¯å¯è¾¾çï¼åå徿¶é卿 æ³éæ¾å®ï¼å 为å®ä»ç¶è¢«ç¨åºæä½¿ç¨ã妿æä¸ªå¯¹è±¡æ¯ä¸å¯è¾¾çï¼åç¨åºæ æ³ä½¿ç¨å®ï¼é£ä¹å徿¶éå¨åæ¶è¯¥å¯¹è±¡å°±æ¯å®å
¨çã
ä½¿ç¨ **Reference** 对象继ç»ä¿æå¯¹è¯¥å¯¹è±¡çå¼ç¨ï¼ä»¥å°è¾¾è¯¥å¯¹è±¡ï¼ä½ä¹å
许å徿¶éå¨éæ¾è¯¥å¯¹è±¡ãå æ¤ï¼ç¨åºå¯ä»¥ä½¿ç¨è¯¥å¯¹è±¡ï¼ä½å¦æå
åå³å°èå°½ï¼åå
è®¸éæ¾è¯¥å¯¹è±¡ã
å¯ä»¥éè¿ä½¿ç¨ **Reference** 对象ä½ä¸ºä½ åæ®éå¼ç¨ä¹é´çä¸ä»ï¼ä»£çï¼æ¥å®ç°æ¤ç®çãæ¤å¤ï¼å¿
须没æå¯¹è±¡çæ®éå¼ç¨ï¼æªå
å«å¨ **Reference** 对象ä¸ç对象ï¼ã妿å徿¶éå¨åç°å¯¹è±¡å¯éè¿æ®éå¼ç¨è®¿é®ï¼åå®ä¸ä¼éæ¾è¯¥å¯¹è±¡ã
æç
§ **SoftReference** ï¼ **WeakReference** å **PhantomReference** ç顺åºï¼æ¯ä¸ªé½æ¯åä¸ä¸ªæ´âå¼±âï¼å¹¶ä¸å¯¹åºäºä¸åçå¯è¾¾æ§çº§å«ã软å¼ç¨ç¨äºå®ç°å¯¹å
åææçç¼åãå¼±å¼ç¨ç¨äºå®ç°âè§èåæ å°âï¼ canonicalized mappingsï¼ââ对象çå®ä¾å¯ä»¥å¨ç¨åºçå¤ä¸ªä½ç½®åæ¶ä½¿ç¨ï¼ä»¥èçåå¨ï¼ä½ä¸ä¼é»æ¢å
¶é®ï¼æå¼ï¼è¢«åæ¶ãèå¼ç¨ç¨äºè°åº¦ pre-mortem æ¸
çæä½ï¼è¿æ¯ä¸ç§æ¯ Java ç»ç»æºå¶ï¼Java finalization mechanismï¼æ´çµæ´»çæ¹å¼ã
ä½¿ç¨ **SoftReference** å **WeakReference** ï¼å¯ä»¥éæ©æ¯å¦å°å®ä»¬æ¾å¨ **ReferenceQueue** ï¼ç¨äº pre-mortem æ¸
çæä½ç设å¤ï¼ä¸ï¼ä½ **PhantomReference** åªè½å¨ **ReferenceQueue** ä¸æå»ºãä¸é¢æ¯ä¸ä¸ªç®åçæ¼ç¤ºï¼
```java
// collectiontopics/References.java
// Demonstrates Reference objects
import java.lang.ref.*;
import java.util.*;
class VeryBig {
private static final int SIZE = 10000;
private long[] la = new long[SIZE];
private String ident;
VeryBig(String id) { ident = id; }
@Override
public String toString() { return ident; }
@Override
protected void finalize() {
System.out.println("Finalizing " + ident);
}
}
public class References {
private static ReferenceQueue rq =
new ReferenceQueue<>();
public static void checkQueue() {
Reference extends VeryBig> inq = rq.poll();
if(inq != null)
System.out.println("In queue: " + inq.get());
}
public static void main(String[] args) {
int size = 10;
// Or, choose size via the command line:
if(args.length > 0)
size = Integer.valueOf(args[0]);
LinkedList> sa =
new LinkedList<>();
for(int i = 0; i < size; i++) {
sa.add(new SoftReference<>(
new VeryBig("Soft " + i), rq));
System.out.println(
"Just created: " + sa.getLast());
checkQueue();
}
LinkedList> wa =
new LinkedList<>();
for(int i = 0; i < size; i++) {
wa.add(new WeakReference<>(
new VeryBig("Weak " + i), rq));
System.out.println(
"Just created: " + wa.getLast());
checkQueue();
}
SoftReference s =
new SoftReference<>(new VeryBig("Soft"));
WeakReference w =
new WeakReference<>(new VeryBig("Weak"));
System.gc();
LinkedList> pa =
new LinkedList<>();
for(int i = 0; i < size; i++) {
pa.add(new PhantomReference<>(
new VeryBig("Phantom " + i), rq));
System.out.println(
"Just created: " + pa.getLast());
checkQueue();
}
}
}
/* Output: (First and Last 10 Lines)
Just created: java.lang.ref.SoftReference@15db9742
Just created: java.lang.ref.SoftReference@6d06d69c
Just created: java.lang.ref.SoftReference@7852e922
Just created: java.lang.ref.SoftReference@4e25154f
Just created: java.lang.ref.SoftReference@70dea4e
Just created: java.lang.ref.SoftReference@5c647e05
Just created: java.lang.ref.SoftReference@33909752
Just created: java.lang.ref.SoftReference@55f96302
Just created: java.lang.ref.SoftReference@3d4eac69
Just created: java.lang.ref.SoftReference@42a57993
...________...________...________...________...
Just created: java.lang.ref.PhantomReference@45ee12a7
In queue: null
Just created: java.lang.ref.PhantomReference@330bedb4
In queue: null
Just created: java.lang.ref.PhantomReference@2503dbd3
In queue: null
Just created: java.lang.ref.PhantomReference@4b67cf4d
In queue: null
Just created: java.lang.ref.PhantomReference@7ea987ac
In queue: null
*/
```
å½è¿è¡æ¤ç¨åºï¼å°è¾åºéå®åå°ææ¬æä»¶ä»¥æ¥ç页é¢ä¸çè¾åºï¼æ¶ï¼å°ä¼çå°å¯¹è±¡æ¯è¢«å徿¶éäºçï¼è½ç¶ä»ç¶å¯ä»¥éè¿ **Reference** 对象访é®å®ä»¬ï¼ä½¿ç¨ `get()` æ¥è·åå®é
ç对象å¼ç¨ï¼ã è¿å¯ä»¥çå° **ReferenceQueue** å§ç»çæå
å« **null** 对象ç **Reference** ã è¦ä½¿ç¨å®ï¼è¯·ä»ç¹å®ç **Reference** 类继æ¿ï¼å¹¶ä¸ºæ°ç±»æ·»å æ´å¤æç¨çæ¹æ³ã
### WeakHashMap
éåç±»åºä¸æä¸ä¸ªç¹æ®ç **Map** æ¥ä¿åå¼±å¼ç¨ï¼ **WeakHashMap** ã æ¤ç±»å¯ä»¥æ´è½»æ¾å°å建è§èåæ å°ãå¨è¿ç§æ å°ä¸ï¼å¯ä»¥éè¿ä»
ä»
å建ä¸ä¸ªç¹å®å¼çå®ä¾æ¥èçåå¨ç©ºé´ãå½ç¨åºéè¦è¯¥å¼æ¶ï¼å®ä¼æ¥æ¾æ å°ä¸çç°æå¯¹è±¡å¹¶ä½¿ç¨å®ï¼è䏿¯ä»å¤´å¼å§å建ä¸ä¸ªï¼ã 该æ å°å¯ä»¥å°å¼ä½ä¸ºå
¶åå§åçä¸é¨åï¼ä½æ´æå¯è½çæ¯å¨éè¦æ¶å建该å¼ã
ç±äºè¿æ¯ä¸ç§èçåå¨ç©ºé´çææ¯ï¼å æ¤ **WeakHashMap** å
许å徿¶éå¨èªå¨æ¸
çé®åå¼ï¼è¿æ¯é常æ¹ä¾¿çãä¸è½å¯¹æ¾å¨ **WeakHashMap** ä¸çé®åå¼åä»»ä½ç¹æ®æä½ï¼å®ä»¬ç± map èªå¨å
è£
å¨ **WeakReference** ä¸ãå½é®ä¸å被使ç¨çæ¶åæå
许æ¸
çï¼å¦ä¸æç¤ºï¼
```java
// collectiontopics/CanonicalMapping.java
// Demonstrates WeakHashMap
import java.util.*;
class Element {
private String ident;
Element(String id) { ident = id; }
@Override
public String toString() { return ident; }
@Override
public int hashCode() {
return Objects.hashCode(ident);
}
@Override
public boolean equals(Object r) {
return r instanceof Element &&
Objects.equals(ident, ((Element)r).ident);
}
@Override
protected void finalize() {
System.out.println("Finalizing " +
getClass().getSimpleName() + " " + ident);
}
}
class Key extends Element {
Key(String id) { super(id); }
}
class Value extends Element {
Value(String id) { super(id); }
}
public class CanonicalMapping {
public static void main(String[] args) {
int size = 1000;
// Or, choose size via the command line:
if(args.length > 0)
size = Integer.valueOf(args[0]);
Key[] keys = new Key[size];
WeakHashMap map =
new WeakHashMap<>();
for(int i = 0; i < size; i++) {
Key k = new Key(Integer.toString(i));
Value v = new Value(Integer.toString(i));
if(i % 3 == 0)
keys[i] = k; // Save as "real" references
map.put(k, v);
}
System.gc();
}
}
```
**Key** ç±»å¿
é¡»å
·æ `hashCode()` å `equals()` ï¼å 为å®å°è¢«ç¨ä½æ£åæ°æ®ç»æä¸çé®ã `hashCode()` çå
容å¨[éå½ï¼çè§£hashCodeåequalsæ¹æ³]()ä¸è¿è¡äºæè¿°ã
è¿è¡ç¨åºï¼ä½ ä¼çå°å徿¶é卿¯ä¸ä¸ªé®è·³è¿ä¸æ¬¡ã对该é®çæ®éå¼ç¨ä¹è¢«æ¾ç½®å¨ **keys** æ°ç»ä¸ï¼å æ¤è¿äºå¯¹è±¡ä¸è½è¢«å徿¶éã
## Java 1.0 / 1.1 çéåç±»
ä¸å¹¸çæ¯ï¼è®¸å¤ä»£ç æ¯ä½¿ç¨ Java 1.0 / 1.1 ä¸çéåç¼åçï¼çè³æ°ä»£ç ææ¶ä¹æ¯ä½¿ç¨è¿äºç±»ç¼åçãç¼åæ°ä»£ç æ¶åå¿ä½¿ç¨æ§éåãæ§çéåç±»æéï¼æä»¥å
³äºå®ä»¬ç讨论ä¸å¤ãç±äºå®ä»¬æ¯ä¸åæ¶å®çï¼æä»¥æä¼å°½éé¿å
è¿å强è°ä¸äºå¯æç设计å³å®ã
### Vector å Enumeration
Java 1.0 / 1.1 ä¸å¯ä¸çèªæ©å±åºåæ¯ **Vector** ï¼å æ¤å®è¢«ç¨äºå¾å¤å°æ¹ãå®ç缺é·å¤ªå¤äºï¼æ æ³å¨è¿éæè¿°ï¼åè§ãJavaç¼ç¨ææ³ã第1çï¼å¯ä»[www.OnJava8.com](www.OnJava8.com)å
è´¹ä¸è½½ï¼ãåºæ¬ä¸ï¼ä½ å¯ä»¥å°å®ç使¯å
·æåé¿ä¸ç¬¨æçæ¹æ³åç§°ç **ArrayList** ãå¨ä¿®è®¢åç Java éååºä¸ï¼**Vector** å·²ç»è¢«è°æ´éé
è¿ï¼å æ¤å¯ä»¥ä½ä¸º **Collection** å **List** æ¥ä½¿ç¨ãäºå®è¯æè¿æç¹ä¸æ£å¸¸ï¼éåç±»åºä»ç¶å
å«å®åªæ¯ä¸ºäºæ¯ææ§ç Java 代ç ï¼ä½è¿ä¼è®©ä¸äºäººè¯¯ä»¥ä¸º **Vector** å·²ç»å徿´å¥½äºã
è¿ä»£å¨ç Java 1.0 / 1.1 çæ¬éæ©å建ä¸ä¸ªæ°åç§°âenumerationâï¼è䏿¯ä½¿ç¨æ¯ä¸ªäººé½çæçæ¯è¯ï¼âiteratorâï¼ã **Enumeration** æ¥å£å°äº **Iterator** ï¼åªå
å«ä¸¤ä¸ªæ¹æ³ï¼å¹¶ä¸å®ä½¿ç¨æ´é¿çæ¹æ³åç§°ï¼å¦æè¿ææ´å¤å
ç´ ï¼å `boolean hasMoreElements()` è¿å `true` ï¼ `Object nextElement()` è¿åæ¤enumerationçä¸ä¸ä¸ªå
ç´ ï¼å¦å伿åºå¼å¸¸ï¼ã
**Enumeration** åªæ¯ä¸ä¸ªæ¥å£ï¼è䏿¯ä¸ä¸ªå®ç°ï¼çè³æ°çç±»åºææ¶ä»ç¶ä½¿ç¨æ§ç **Enumeration** ï¼è¿æ¯ä¸å¹¸çï¼ä½éå¸¸æ¯æ 害çãåºè¯¥æ»æ¯å¨èªå·±ç代ç ä¸ä½¿ç¨ **Iterator** ï¼ä½è¦å好åå¤åºå¯¹é£äºæä¾ **Enumeration** çç±»åºã
æ¤å¤ï¼å¯ä»¥ä½¿ç¨ `Collections.enumeration()` æ¹æ³ä¸ºä»»ä½ **Collection** çæ **Enumeration** ï¼å¦ä¸ä¾æç¤ºï¼
```java
// collectiontopics/Enumerations.java
// Java 1.0/1.1 Vector and Enumeration
import java.util.*;
import onjava.*;
public class Enumerations {
public static void main(String[] args) {
Vector v =
new Vector<>(Countries.names(10));
Enumeration e = v.elements();
while(e.hasMoreElements())
System.out.print(e.nextElement() + ", ");
// Produce an Enumeration from a Collection:
e = Collections.enumeration(new ArrayList<>());
}
}
/* Output:
ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO,
BURUNDI, CAMEROON, CAPE VERDE, CENTRAL AFRICAN
REPUBLIC, CHAD,
*/
```
è¦çæ **Enumeration** ï¼å¯ä»¥è°ç¨ `elements()` ï¼ç¶åå¯ä»¥ä½¿ç¨å®æ¥æ§è¡ååè¿ä»£ã
æåä¸è¡å建ä¸ä¸ª **ArrayList** ï¼å¹¶ä½¿ç¨ `enumeration() ` æ¥å° **ArrayList** éé
为ä¸ä¸ª **Enumeration** ã å æ¤ï¼å¦æææ§ä»£ç éè¦ä½¿ç¨ **Enumeration** ï¼ä½ ä»ç¶å¯ä»¥ä½¿ç¨æ°éåã
### Hashtable
æ£å¦ä½ 卿¬éå½ä¸çæ§è½æ¯è¾ä¸æçå°çï¼åºæ¬ç **Hashtable** ä¸ **HashMap** é常ç¸ä¼¼ï¼çè³æ¹æ³åç§°é½ç¸ä¼¼ã卿°ä»£ç 䏿²¡æçç±ä½¿ç¨ **Hashtable** è䏿¯ **HashMap** ã
### Stack
ä¹åä½¿ç¨ **LinkedList** å¼å
¥äºæ çæ¦å¿µã Java 1.0 / 1.1 **Stack** ç奿ªä¹å¤å¨äºï¼ä¸æ¯ä»¥ç»åæ¹å¼ä½¿ç¨ **Vector** ï¼èæ¯ç»§æ¿èª **Vector** ã å æ¤å®å
·æ **Vector** çææç¹å¾åè¡ä¸ºä»¥åä¸äºé¢å¤ç **Stack** è¡ä¸ºãå¾é¾å»ç¥éè®¾è®¡å¸æ¯å¦ææè¯å°è®¤ä¸ºè¿æ ·åæ¯æç¨çï¼æè
宿¯å¦åªæ¯å¤ªå¤©çäºï¼æ 论å¦ä½ï¼å®å¨è¿å
¥åè¡çä¹åæ¾ç¶æ²¡æç»è¿å®¡æ¥ï¼æä»¥è¿ä¸ªç³ç³ç设计ä»ç¶åå¨ï¼ä½ä¸è¦ä½¿ç¨å®ï¼ã
è¿æ¯ **Stack** çç®åæ¼ç¤ºï¼åæ 䏿¾å
¥æä¸¾ä¸æ¯ä¸ä¸ªç±»åç **String** å½¢å¼ãå®è¿å±ç¤ºäºå¦ä½è½»æ¾å°å° **LinkedList** ç¨ä½æ ï¼æè
使ç¨å¨[第åäºç« ï¼éå]()ç« èä¸å建ç **Stack** ç±»ï¼
```java
// collectiontopics/Stacks.java
// Demonstration of Stack Class
import java.util.*;
enum Month { JANUARY, FEBRUARY, MARCH, APRIL,
MAY, JUNE, JULY, AUGUST, SEPTEMBER,
OCTOBER, NOVEMBER }
public class Stacks {
public static void main(String[] args) {
Stack stack = new Stack<>();
for(Month m : Month.values())
stack.push(m.toString());
System.out.println("stack = " + stack);
// Treating a stack as a Vector:
stack.addElement("The last line");
System.out.println(
"element 5 = " + stack.elementAt(5));
System.out.println("popping elements:");
while(!stack.empty())
System.out.print(stack.pop() + " ");
// Using a LinkedList as a Stack:
LinkedList lstack = new LinkedList<>();
for(Month m : Month.values())
lstack.addFirst(m.toString());
System.out.println("lstack = " + lstack);
while(!lstack.isEmpty())
System.out.print(lstack.removeFirst() + " ");
// Using the Stack class from
// the Collections Chapter:
onjava.Stack stack2 =
new onjava.Stack<>();
for(Month m : Month.values())
stack2.push(m.toString());
System.out.println("stack2 = " + stack2);
while(!stack2.isEmpty())
System.out.print(stack2.pop() + " ");
}
}
/* Output:
stack = [JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE,
JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER]
element 5 = JUNE
popping elements:
The last line NOVEMBER OCTOBER SEPTEMBER AUGUST JULY
JUNE MAY APRIL MARCH FEBRUARY JANUARY lstack =
[NOVEMBER, OCTOBER, SEPTEMBER, AUGUST, JULY, JUNE, MAY,
APRIL, MARCH, FEBRUARY, JANUARY]
NOVEMBER OCTOBER SEPTEMBER AUGUST JULY JUNE MAY APRIL
MARCH FEBRUARY JANUARY stack2 = [NOVEMBER, OCTOBER,
SEPTEMBER, AUGUST, JULY, JUNE, MAY, APRIL, MARCH,
FEBRUARY, JANUARY]
NOVEMBER OCTOBER SEPTEMBER AUGUST JULY JUNE MAY APRIL
MARCH FEBRUARY JANUARY
*/
```
**String** 形弿¯ç± **Month** ä¸çæä¸¾å¸¸éçæçï¼ä½¿ç¨ `push()` åå
¥å°æ ä¸ï¼ç¶åä½¿ç¨ `pop()` 仿 é¡¶é¨ååºã为äºè¯´æä¸ç¹ï¼å° **Vector** çæä½ä¹å¨ **Stack** å¯¹è±¡ä¸æ§è¡ï¼ è¿æ¯å¯è½çï¼å 为ååç»§æ¿ï¼ **Stack** æ¯ **Vector** ã å æ¤ï¼å¯ä»¥å¨ **Vector** 䏿§è¡çæææä½ä¹å¯ä»¥å¨ **Stack** 䏿§è¡ï¼ä¾å¦ `elementAt()` ã
å¦åæè¿°ï¼å¨éè¦æ è¡ä¸ºæ¶ä½¿ç¨ **LinkedList** ï¼æè
ä» **LinkedList** ç±»å建ç **onjava.Stack** ç±»ã
### BitSet
**BitSet** ç¨äºææå°åå¨å¤§éçå¼å
³ä¿¡æ¯ãä»
ä»å°ºå¯¸å¤§å°çè§åº¦æ¥ç宿¯ææçï¼å¦æä½ æ£å¨å¯»æ¾ææç访é®ï¼å®æ¯ä½¿ç¨æ¬æºæ°ç»ï¼native arrayï¼ç¨æ
¢ã
æ¤å¤ï¼ **BitSet** çæå°å¤§å°æ¯ **long** ï¼64ä½ãè¿æå³çå¦æä½ è¦å卿´å°çä¸è¥¿ï¼æ¯å¦8ä½ï¼ **BitSet** å°±æ¯æµªè´¹ï¼å¦æå°ºå¯¸æé®é¢ï¼ä½ æå¥½å建èªå·±çç±»ï¼æè
åªæ¯ç¨ä¸ä¸ªæ°ç»æ¥ä¿åä½ çæ å¿ãï¼åªæå¨ä½ å建许å¤å
å«å¼å
³ä¿¡æ¯å表çå¯¹è±¡æ¶æä¼åºç°è¿ç§æ
åµï¼å¹¶ä¸åªåºæ ¹æ®åæåå
¶ä»ææ æ¥å³å®ãå¦æä½ ååºæ¤å³å®åªæ¯å 为æ¨è®¤ä¸º **BitSet** 太大ï¼é£ä¹æç»ä¼äº§çä¸å¿
è¦ç夿æ§å¹¶ä¸æµªè´¹å¤§éæ¶é´ãï¼
彿·»å æ´å¤å
ç´ æ¶ï¼æ®ééå伿©å±ï¼ **BitSet**ä¹ä¼è¿æ ·åã以ä¸ç¤ºä¾æ¾ç¤ºäº **BitSet** çå·¥ä½åçï¼
```java
// collectiontopics/Bits.java
// Demonstration of BitSet
import java.util.*;
public class Bits {
public static void printBitSet(BitSet b) {
System.out.println("bits: " + b);
StringBuilder bbits = new StringBuilder();
for(int j = 0; j < b.size() ; j++)
bbits.append(b.get(j) ? "1" : "0");
System.out.println("bit pattern: " + bbits);
}
public static void main(String[] args) {
Random rand = new Random(47);
// Take the LSB of nextInt():
byte bt = (byte)rand.nextInt();
BitSet bb = new BitSet();
for(int i = 7; i >= 0; i--)
if(((1 << i) & bt) != 0)
bb.set(i);
else
bb.clear(i);
System.out.println("byte value: " + bt);
printBitSet(bb);
short st = (short)rand.nextInt();
BitSet bs = new BitSet();
for(int i = 15; i >= 0; i--)
if(((1 << i) & st) != 0)
bs.set(i);
else
bs.clear(i);
System.out.println("short value: " + st);
printBitSet(bs);
int it = rand.nextInt();
BitSet bi = new BitSet();
for(int i = 31; i >= 0; i--)
if(((1 << i) & it) != 0)
bi.set(i);
else
bi.clear(i);
System.out.println("int value: " + it);
printBitSet(bi);
// Test bitsets >= 64 bits:
BitSet b127 = new BitSet();
b127.set(127);
System.out.println("set bit 127: " + b127);
BitSet b255 = new BitSet(65);
b255.set(255);
System.out.println("set bit 255: " + b255);
BitSet b1023 = new BitSet(512);
b1023.set(1023);
b1023.set(1024);
System.out.println("set bit 1023: " + b1023);
}
}
/* Output:
byte value: -107
bits: {0, 2, 4, 7}
bit pattern: 101010010000000000000000000000000000000000
0000000000000000000000
short value: 1302
bits: {1, 2, 4, 8, 10}
bit pattern: 011010001010000000000000000000000000000000
0000000000000000000000
int value: -2014573909
bits: {0, 1, 3, 5, 7, 9, 11, 18, 19, 21, 22, 23, 24,
25, 26, 31}
bit pattern: 110101010101000000110111111000010000000000
0000000000000000000000
set bit 127: {127}
set bit 255: {255}
set bit 1023: {1023, 1024}
*/
```
éæºæ°çæå¨ç¨äºåå»ºéæº **byte** ï¼ **short** å **int** ï¼å¹¶ä¸æ¯ä¸ªé½å¨ **BitSet** ä¸è½¬æ¢ä¸ºç¸åºç使¨¡å¼ãè¿æ ·å¯ä»¥æ£å¸¸å·¥ä½ï¼å 为 **BitSet** æ¯64ä½ï¼æä»¥è¿äºé½ä¸ä¼å¯¼è´å®ç大å°å¢å ï¼ç¶åå建æ´å¤§ç **BitSet** ã 请注æï¼ **BitSet** 伿 ¹æ®éè¦è¿è¡æ©å±ã
对äºå¯ä»¥å½åçåºå®æ å¿éï¼ **EnumSet** ï¼åè§[第äºåäºç« ï¼æä¸¾]()ç« èï¼éå¸¸æ¯ **BitSet** æ´å¥½ï¼å 为 **EnumSet** å
许æä½åç§°è䏿¯æ°åä½ä½ç½®ï¼ä»èå¯ä»¥åå°é误ã **EnumSet** è¿å¯ä»¥é²æ¢æå¤å°æ·»å æ°çæ è®°ä½ç½®ï¼è¿å¯è½ä¼å¯¼è´ä¸äºä¸¥éçï¼é¾ä»¥åç°çé误ãä½¿ç¨ **BitSet** è䏿¯ **EnumSet** çå¯ä¸åå æ¯ï¼ä¸ç¥éå¨è¿è¡æ¶éè¦å¤å°æ å¿ï¼æè
为æ å¿åé
åç§°æ¯ä¸åççï¼æè
éè¦ **BitSet** ä¸çä¸ä¸ªç¹æ®æä½ï¼è¯·åé
**BitSet** å **EnumSet** ç JDK ææ¡£ï¼ã
## æ¬ç« å°ç»
éåå¯ä»¥è¯´æ¯ç¼ç¨è¯è¨ä¸æå¸¸ç¨çå·¥å
·ãæäºè¯è¨ï¼ä¾å¦Pythonï¼çè³å°åºæ¬éåç»ä»¶ï¼åè¡¨ï¼æ å°åéåï¼ä½ä¸ºå
ç½®å½æ°å
å«å¨å
¶ä¸ã
æ£å¦å¨[第åäºç« ï¼éå]()ç« èä¸çå°ç飿 ·ï¼å¯ä»¥ä½¿ç¨éåæ§è¡è®¸å¤é常æç¨çæä½ï¼èä¸éè¦å¤ªå¤åªåã使¯ï¼å¨æäºæ¶åï¼ä¸ºäºæ£ç¡®å°ä½¿ç¨å®ä»¬èä¸å¾ä¸æ´å¤å°äºè§£éåï¼ç¹å«æ¯ï¼å¿
é¡»å
åäºè§£æ£åæä½ä»¥ç¼åèªå·±ç `hashCode()` æ¹æ³ï¼å¹¶ä¸å¿
é¡»ç¥é使¶éè¦ï¼ï¼å¹¶ä¸ä½ å¿
é¡»å
åäºè§£åç§éåå®ç°ï¼ä»¥æ ¹æ®ä½ ç鿱鿩åéçéåãæ¬é彿¶µçäºè¿äºæ¦å¿µï¼å¹¶è®¨è®ºäºæå
³éååºçå
¶ä»æç¨è¯¦ç»ä¿¡æ¯ãä½ ç°å¨åºè¯¥å·²ç»åå¤å¥½å¨æ¥å¸¸ç¼ç¨ä»»å¡ä¸ä½¿ç¨ Java éåäºã
éååºç设计å¾å°é¾ï¼å¤§å¤æ°åºè®¾è®¡é®é¢é½æ¯å¦æ¤ï¼ãå¨ C++ ä¸ï¼éå类涵çäºè®¸å¤ä¸åç±»çåºç¡ãè¿æ¯ä¹åå¯ç¨ç C++ éåç±»æ´å¥½ï¼ä½å®æ²¡æå¾å¥½å°è½¬æ¢ä¸º Java ãå¨å¦ä¸ä¸ªæç«¯ï¼æçå°äºä¸ä¸ªç±å个类âcollectionâç»æçéååºï¼å®åæ¶å
å½çº¿æ§åºååå
³èæ°ç»ã Java éååºè¯å¾å¨åè½å夿æ§ä¹é´åå¾å¹³è¡¡ãç»æå¨æäºå°æ¹çèµ·æ¥æç¹å¥æªã䏿©æ Java åºä¸çä¸äºå³çä¸åï¼è¿äºå¥æªç䏿¯äºæ
ï¼èæ¯å¨åºäºå¤ææ§çæè¡¡ä¸èä»ç»èèçå³çã
[^1]: **java.util** ä¸ç **Map** ä½¿ç¨ **Map** ç `getKey()` å `getValue()` æ§è¡æ¹éå¤å¶ï¼å æ¤è¿æ¯ææçã妿èªå®ä¹ **Map** åªæ¯å¤å¶æ´ä¸ª **Map.Entry** ï¼é£ä¹è¿ç§æ¹æ³å°±ä¼åºç°é®é¢ã
[^2]: è½ç¶å½æç¨è¿ç§æ¹å¼æè¿°å®çæ¶åå¬èµ·æ¥å¾å¥æªèä¸å¥½å没ä»ä¹ç¨å¤ï¼ä½å¨[第åä¹ç« ç±»åä¿¡æ¯]()ç« èä¸å·²ç»çå°è¿ï¼è¿ç§å¨æè¡ä¸ºä¹å¯ä»¥é常强大æç¨ã
[^3]: 妿è¿äºå éä»ç¶æ æ³æ»¡è¶³æ§è½éæ±ï¼åå¯ä»¥éè¿ç¼åèªå·±ç **Map** å¹¶å°å
¶èªå®ä¹ä¸ºç¹å®ç±»åæ¥è¿ä¸æ¥å éè¡¨æ¥æ¾ï¼ä»¥é¿å
å å **对象** 转æ¢è导è´çå»¶è¿ã为äºè¾¾å°æ´é«çæ§è½æ°´å¹³ï¼é度ç±å¥½è
å¯ä»¥ä½¿ç¨ Donald Knuth çãè®¡ç®æºç¨åºè®¾è®¡èºæ¯ï¼ç¬¬3å·ï¼ï¼æåºä¸æ¥æ¾ãï¼ç¬¬äºçï¼ï¼å°æº¢åºæ¡¶å表ï¼overflow bucket listsï¼æ¿æ¢ä¸ºå
·æä¸¤ä¸ªé¢å¤ä¼å¿çéµåï¼å®ä»¬å¯ä»¥é对ç£çåå¨è¿è¡ä¼åï¼å¹¶ä¸å®ä»¬å¯ä»¥èç大é¨åå建ååæ¶ä¸ªå«è®°å½ï¼individual recordsï¼çæ¶é´ã