17.1完整的容器分类法
17.2填充容器
17.2.1 一种Generator解决方案
package com17;
import java.util.ArrayList;
/**
* Created by Panda on 2018/5/17.
*/
interface Generator<T>{ T next();}
public class CollectionData<T> extends ArrayList<T> {
public CollectionData(Generator<T> generator,int quality){
for (int i = 0; i <quality ; i++) {
add(generator.next());
}
}
public static <T> CollectionData<T> list(Generator<T> generator,int quality){
return new CollectionData<>(generator,quality);
}
}
package com17;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Created by Panda on 2018/5/17.
*/
class Goverment implements Generator<String>{
String[] foundation=("string women lying in ponds"+"distributing swords is no basis for a system of"+"government").split(" ");
private int index;
@Override
public String next() {
return foundation[index++];
}
}
public class CollectionDataTest {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>(new CollectionData<String>(new Goverment(),13));
set.addAll(CollectionData.list(new Goverment(),13));
System.out.println(set);
}
}
/**
[string, women, lying, in, pondsdistributing, swords, is, no, basis, for, a, system, ofgovernment]
*/
17.2.2Map生成器
1、
/**
* Created by Panda on 2018/5/17.
*/
public class Pair<K,V> {
public K key;
public V value;
public Pair(K k,V v) {
key=k;
value=v;
}
}
17.2.3使用Abstract类
1、享元模式使得对象的一部分可以被具体化,因此,与对象中的所有事物都包含在对象内部不同,可以在更加高效的外部表中查找对象的一部分或整体(或者通过某些其他节省空间的计算来产生对象的一部分或整体)
17.3Collection的功能方法
17.4 可选操作
17.4.1未获支持的操作
package com17;
import java.util.*;
/**
* Created by Panda on 2018/5/17.
*/
public class Unsupported {
static void test(String msg, List<String> list){
System.out.println("----------------"+msg+"----------------------");
Collection<String> collection=list;
Collection<String> sublist=list.subList(1,8);
Collection<String> collection1=new ArrayList<>(sublist);
try{
collection.containsAll(collection1);
}catch (Exception e){
System.out.println("containsAll() :" +e);
}
try{
collection.removeAll(collection1);
}catch (Exception e){
System.out.println("removeAll() :" +e);
}
try{
collection.clear(); //移除容器中所有的元素
}catch (Exception e){
System.out.println("clear() :" +e);
}
try{
collection.add("X");
}catch (Exception e){
System.out.println("add() :" +e);
}
try{
collection.addAll(collection1);
}catch (Exception e){
System.out.println("addAll :" +e);
}
try{
collection.remove("C");
}catch (Exception e){
System.out.println("remove() :" +e);
}
try{
list.set(0,"X");
}catch (Exception e){
System.out.println("list.set() :" +e);
}
}
public static void main(String[] args) {
List<String> list= Arrays.asList("A B C D E F G H I J K L".split(" "));
test("Modifiable Copy",new ArrayList<String>(list));
test("Arrays.List()",list);
test("unmodifiableList()", Collections.unmodifiableList(new ArrayList<String>(list)));
}
//Arrays.asList()会生成一个List,它是基于一个固定大小的数组,仅支持那些不会改变数组大小的操作。对它而言,是有道理的。
//任何会引起对底层数据结构的尺寸进行修改的方法都会产生一个UnsupportedOperationException异常,以表示对未获支持操作的调用
//Arrays.asList()的结果作为构造器的参数传递给任何Collection(或者使用addAll()方法,或Collections.addAll()静态方法).
//这样可以生成允许使用所有的方法的普通容器----在main()中的第一个对test()的调用得到了展示,这样的调用会产生新的尺寸可调的
//底层数据结构。
//对于set方法,Arrays.asList()返回固定尺寸大小的List,而Collections.unmodifiableList()产生不可修改的列表。
//修改Arrays.asList()返回的List中的元素是可以的,因为没有违反该List“尺寸固定”这一特性。
//unmodifiableList()的结果在任何情况下都应该不是可修改的。如果使用的是接口,那么还需要两个附加的接口,一个具有可以工作的set()方法
/**
* ----------------Modifiable Copy----------------------
----------------Arrays.List()----------------------
removeAll() :java.lang.UnsupportedOperationException
clear() :java.lang.UnsupportedOperationException
add() :java.lang.UnsupportedOperationException
addAll :java.lang.UnsupportedOperationException
remove() :java.lang.UnsupportedOperationException
----------------unmodifiableList()----------------------
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
*/
}
17.5 List的功能方法
17.6 Set和存储顺序
1、set需要一种方法来维护存储顺序,而存储顺序如何维护,则是在Set的不同实现之间会有变化。因此,不同的Set实现不仅具有不同的行为,而且它们对于可以在特定的Set中放置的元素类型也有不同的要求。
Set:存入Set的每个元素都必须是唯一的,因为Set不保存重复元素,加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一致的接口。Set接口不保证维护元素的次序。
HashSet:为快速查找而设计的Set。存入HashSet的元素必须定义hashCode()
TreeSet:保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。元素必须实现Comparable接口。
LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序),于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。元素也必须定义hashcode()方法。
2、必须为散列存储和树型存储都创建一个equals()方法,但是hashCode()只有在这个类将会被置于HashSet或者LinkedHashSet中才是必需的。但是,一般在覆盖equals()方法时,会同时覆盖hashcode()方法。
17.6.1SortedSet
1、SortedSet中的元素可以保证处于排序状态,
2、
package com17;
import java.util.Collections;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* Created by Panda on 2018/5/17.
*/
public class SortedSetMap {
public static void main(String[] args) {
SortedSet<String> sortedSet = new TreeSet<>();
Collections.addAll(sortedSet, "one two three four five six seven eight".split(" "));
System.out.println(sortedSet); //[eight, five, four, one, seven, six, three, two]
//返回容器中第一个元素
String low = sortedSet.first();
//返回容器中的最后一个元素
String high = sortedSet.last();
System.out.println(low); //eight
System.out.println(high); //two
Iterator<String> 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); //one ????
System.out.println(high); //two
//生成set子集,范围从 low(包含)到high(不包含)
System.out.println(sortedSet.subSet(low,high)); //[one, seven, six, three]
//生成此set子集,由小于high的元素构成
System.out.println(sortedSet.headSet(high)); //[eight, five, four, one, seven, six, three]
//生成此set子集,由大于或等于low的元素组成
System.out.println(sortedSet.tailSet(low)); //[one, seven, six, three, two]
}
}
17.7 队列
1、Queue 仅有的两个实现是Linked和PriorityQueue。它们的差异在于排序行为而不是性能。
17.7.1 优先级队列
1
package com17;
import java.util.PriorityQueue;
/**
* Created by Panda on 2018/5/17.
*/
public class ToDoList extends PriorityQueue<ToDoList.ToDoItem> {
static class ToDoItem implements Comparable<ToDoItem>{
private char primary;
private int secondary;
private String item;
public ToDoItem(String id,char pri,int sec){
primary=pri;
secondary=sec;
item=id;
}
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;
}
public String toString(){
return Character.toString(primary)+secondary+" : "+item;
}
}
public void add(String td,char pri,int sec){
super.add(new ToDoItem(td,pri,sec));
}
public static void main(String[] args) {
ToDoList toDoItems =new ToDoList();
toDoItems.add("Empty",'C',4);
toDoItems.add("Feed dog",'A',2);
toDoItems.add("Feed bird",'B',7);
toDoItems.add("Mow lawn",'C',3);
toDoItems.add("Water lawn",'B',1);
toDoItems.add("Feed cat",'B',1);
while (!toDoItems.isEmpty()){
System.out.println(toDoItems.remove());
}
}
/**
* A2 : Feed dog
B1 : Water lawn
B1 : Feed cat
B7 : Feed bird
C3 : Mow lawn
C4 : Empty
*/
}
17.8理解Map
1、映射表的基本思想是它维护的键-值关联。
17.8.1性能
1、性能是映射表中的一个重要问题。
2、HashMap使用了特殊的值,称为散列码,来取代对键的缓慢搜索。散列码是“相对唯一”的,用以代表对象的int值,它是通过将该对象的某些信息进行转换而生成的。HashCode()是根类Object中的方法,因此所有Java对象都能产生散列码。HashMap就是使用对象的hashCode()进行快速查询的,此方法能够显著提高性能。
3、HahshMap。Map基于散列表的实现,插入和查询“键值对”的开销是固定的。可以通过构造器设置容量和负载因子,以调整容器的性能。
4、LinkedHashMap类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点,而在迭代访问时反而更快,因为它使用链表维护内部次序。
5、TreeMap基于红黑树的实现。查看“键”或“键值对”时,它们会被排序。TreeMap的特点在于,所得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,可以返回一个子树。
6、WeakHashMap 弱键(weak key)映射,允许释放映射所指向的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向某个“键”,则此“键”可以被垃圾收集器回收。
7、ConcurrentHashMap 一种线程安全的Map,不涉及同步加锁。
8、IdentityHashMap 使用==代替equals()对“键”进行比较的散列映射。
9、散列是映射中存储元素最常用的方式。
10、在Map中,任何键都必须具有一个euqals()方法。如果键被用于散列Map,那么必须具有恰当的HashCode()方法。如果键被用于TreeMap,必须实现Comparable。
17.8.2SortedMap
17.8.3LinkedHashMap
1、为了提高速度,LinkedHashMap散列化所有的元素,但是在遍历键值对时,却又以元素的插入顺序返回键值对。此外,可以在构造器中设定LinkedHashMap,使之采用基于访问的最近最少使用(LRU)算法。于是没有被访问过的元素就会出现在队列的前面。
17.9散列与散列码
1、正确的equals()方法必须满足下列5个条件:
1)自反性。对任意x,x.equals(x)一定返回true。
2)对称性。对任意x和y,如果y.equals(x)返回true,则x.equals(y)也返回true。
3)传递性。对任意x,y,z,如果有x.equals(y)返回true。y.equals(z)返回true,则x.equals(z)一定返回true。
4)一致性。对任意x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false。
5)对任何不适null的x,x.equals(null)一定返回false。
2、默认的Object.equals()只是比较对象的地址。
17.9.1理解hashCode()
1、使用散列表的目的在于:想要使用一个对象来查找另一个对象。
package com17;
import java.util.Map;
/**
* Created by Panda on 2018/5/17.
*/
public class MapEntry<K,V> implements Map.Entry<K,V> {
private K key;
private V value;
public MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V result =this.value;
this.value=value;
return result;
}
@Override
public int hashCode() {
return (key==null?0:key.hashCode())^(value==null?0:value.hashCode());
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof MapEntry)) return false;
MapEntry mapEntry = (MapEntry)obj;
return
(key==null?mapEntry.getKey()==null:key.equals(mapEntry.getKey()))&&
(value==null?mapEntry.getValue()==null:value.equals(mapEntry.getValue()));
}
@Override
public String toString() {
return "MapEntry{" +
"key=" + key +
", value=" + value +
'}';
}
}
17.9.2 为速度而散列
1、键的查询,键没按照任何特定顺序保存,只能使用简单的线性查询,而线性查询是最慢的查询方式。
2、散列的价值在于速度:散列使得查询得以速度执行。
3、数组并不保存键本身,而是通过键对象生成一个数字,将其作为数组的下标,这个数字就是散列码。
3、为解决数组容量被固定的问题,不同键可以产生相同的下标。也就是说,可能会有冲突。因此,数组多大就不重要了,任何键总能在数组中找到它的位置。
4、查询一个值得过程首先就是计算散列码,然后使用散列码查询数组。如果能够保证没有冲突(如果值得数量是固定的,那么就有可能),那可就有了一个完美的散列函数,但是这种情况只是特例。通常,冲突由外部链接处理:数组并不直接保留,而是保存值得list。然后对list中的值使用equals()方法进行线性的查询。这部分的查询自然会比较慢,但是,如果散列函数好的话,数组的每个位置就只有较少的值。因此,不是查询整个list,而是快速地跳到数组的某个位置,只对很少的元素进行比较。这就是HashMap会如此快的原因。
5、散列表中的“槽位”通常被称为桶位。桶的数量通常为质数
package com17下;
import com17.MapEntry;
import java.util.*;
/**
* Created by Panda on 2018/5/18.
*/
public class SimpleHashMap<K,V> extends AbstractMap<K,V> {
static final int SIZE=997;
LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];
public V put(K key,V value){
V oldValue=null;
int index =Math.abs(key.hashCode())%SIZE;
if(buckets[index]==null)
buckets[index]=new LinkedList<MapEntry<K,V>>();
LinkedList<MapEntry<K,V>> bucket=buckets[index];
MapEntry<K,V> pair= new MapEntry<>(key,value);
boolean found =false;
ListIterator<MapEntry<K,V>> iterator = bucket.listIterator();
while(iterator.hasNext()){
MapEntry<K,V> iPair = iterator.next();
if(iPair.getKey().equals(key)){
oldValue = iPair.getValue();
iterator.set(pair);
found=true;
break;
}
}
if(!found){
buckets[index].add(pair);
}
return oldValue;
}
public V get(Object key){
int index = Math.abs(key.hashCode())%SIZE;
if(buckets[index]==null) return null;
for(MapEntry<K,V> iPair:buckets[index]){
if(iPair.getKey().equals(key)){
return iPair.getValue();
}
}
return null;
}
@Override
public Set<Entry<K, V>> entrySet() {
Set<Map.Entry<K,V>> set = new HashSet<>();
for(LinkedList<MapEntry<K,V>> bucket:buckets){
if(bucket==null) continue;
for(MapEntry<K,V> mPair:bucket){
set.add(mPair);
}
}
return set;
}
}
17.9.3覆盖hashcode()
1、设计hashCode()最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。
2、好的hashCode()应该产生分布均匀的散列码。如果散列码都集中在一块,那么HashMap或者HashSet在某些区域的负载会很重,这样就不如分布均匀的散列函数快。
17.10选择接口的不同实现
1、Set可被实现TreeSet、HashSet或LinkedHashSet。每一种都有不同的行为:HashSet是最常见的,查询速度最快;LinkedHashSet保持元素插入的次序。TreeSet基于TreeMap,生成一个总是处于排序状态的Set。
17.10.1性能测试框架
17.10.2对List的选择
17.10.3微基准测试的危险
17.10.4对Set的选择
1、TreeSet存在的唯一原因是它可以维持元素的排序状态。
17.10.5
1、Hashtable的性能大体上与HashMap相当。因为HashMap是用来替代Hashtable的,因此它们使用了相同的底层存储和查找机制。
2、TreeMap通常比HashMap要慢,与使用TreeSet一样,TreeMap是一种创建有序列表的方式。树的行为是:总是保证有序,并且不必进行特殊的排序。HashMap本身就可以被设计为可以快速查找键。还可以很方便地通过单个的对象创建操作。
3、LinkedHashMap在插入时比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表(以保证插入顺序)。正是由于这个链表,使得其迭代速度更快。
4、HashMap的性能因子
容量:表中桶位数。
初始容量:表在创建时所拥有的桶位数。HashMap和HashSet都具有允许指定初始容量的构造器。
尺寸:表中当前存储的项数。
负载因子:尺寸/容量。空表的负载因子是0,而半满表的负载因子是0.5.HashMap和HashSet都具有允许指定负载因子的构造器,表示当负载情况达到该负载因子的水平时,容器将自动增加其容量(桶位数)实现方式是使容量大致加倍,并重新将现有对象分布到新的桶位集中。
17.11实用方法
1、min()和max()只能作用于Collection对象,而不能作用于List,所以无需担心Collection是否应该被排序。
package com17下;
import javax.xml.bind.SchemaOutputResolver;
import java.util.*;
/**
* Created by Panda on 2018/5/18.
*/
public class Utilities {
static List<String> list= Arrays.asList("one two three four five six one".split(" "));
public static void main(String[] args) {
System.out.println(list);
//disjoint(Collection,Collection) 当两个集合没有任何相同元素时,返回true
System.out.println("'list' disjoint (Four)?:"+ Collections.disjoint(list,Collections.singleton("four")));
//max min 返回参数Collection中最大或最小的元素--采用Collection内置的自然比较法
System.out.println("max : "+Collections.max(list));
System.out.println("min : "+Collections.min(list));
//max min 返回参数Collection中最大或最小的元素----采用Comparator进行比较
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));
//indexOfSublist(List source,List target) 返回target在source中第一次出现的位置,或者在找不到时返回-1
//lastOfSublist(List source,List target) 返回target在source中最后一次出现的位置,或者找不到时返回-1
List<String> sublist=Arrays.asList("four five six".split(" "));
System.out.println("indexOfSublist: "+Collections.indexOfSubList(list,sublist));
System.out.println("lastOfSublist: "+Collections.lastIndexOfSubList(list,sublist));
//replaceAll(List<T>,T oldVal ,T newVal) 使用newVal替换所有的oldVal
Collections.replaceAll(list,"one","Yo");
System.out.println("replaceAll; "+list);
//reverse() 逆转所有元素的次序
Collections.reverse(list);
System.out.println("reverse: "+list);
//rotate(List,int distance) 所有元素向后移动distance个位置,将末尾的元素循环到前面来
Collections.rotate(list,3);
System.out.println("rotate: "+list);
//copy(List<?super T>dest,List<? extends T>src) 将src中的元素复制到des中
List<String> source=Arrays.asList("in the matrix".split(" "));
Collections.copy(list,source);
System.out.println("copy: "+list);
//swap(List,int i,int j) 交换list中位置i与位置j的元素
Collections.swap(list,0,list.size()-1);
System.out.println("swap: "+list);
//shuffle()
//shuffle(List,Random) 随机改变指定元素的顺序 .第一种形式提供了其自己的随机机制,可以通过第二种方式提供自己的随机机制
Collections.shuffle(list,new Random(47));
System.out.println("shuffle: "+list);
//fill(List<? super T> ,T x) 用对象x替换list中的所有元素
Collections.fill(list,"pop");
System.out.println("fill: "+list);
//frequency(Collection,Object x) 返回Collection中等于x的元素个数
System.out.println("frequency of pop: "+Collections.frequency(list,"pop"));
//nCopies(int n,T x) 返回大小为n的List<T> 此List不可改变,其中的引用都指向x
List<String> dups=Collections.nCopies(3,"snap");
System.out.println("dups: "+dups);
System.out.println("list disjonit dups?: "+Collections.disjoint(list,dups));
Enumeration<String> enumeration=Collections.enumeration(dups);
Vector<String> vector=new Vector<>();
while(enumeration.hasMoreElements()){
vector.addElement(enumeration.nextElement());
}
ArrayList<String> arrayList = Collections.list(vector.elements());
System.out.println("arrayList: "+arrayList);
}
/**
* [one, two, three, four, five, six, one]
'list' disjoint (Four)?:false
max : two
min : five
max w/ comparator: two
min w/ comparator: five
indexOfSublist: 3
lastOfSublist: 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]
shuffle: [six, matrix, the, four, Yo, five, in]
fill: [pop, pop, pop, pop, pop, pop, pop]
frequency of pop: 7
dups: [snap, snap, snap]
list disjonit dups?: true
arrayList: [snap, snap, snap]
*/
}
17.11.1 List的排序和查询
17.11.2设定Collection或Map为不可更改
1、创建一个只读的Collection或Map,有时可以带来某些方便。Collections类可以帮助达成此目的,它有一个方法,参数为原本的容器,返回值是容器的只读版本。
2、对特定类型的“不可修改的”方法的调用并不会产生编译时的检查,但是转换完成后,任何会改变容器内容的操作都会引起UnsupportedOperationException异常。
3、无论哪一种情况,在将容器设为只读以前,必须填入有意义的数据。装载数据后,就应该使用“不可修改的”方法返回的引用去替换原本的引用。这样,就不用担心无意中修改了只读的内容。另一方面,此方法允许保留一份可修改的容器,作为类的private成员,然后通过某个方法调用返回对该容器的“只读”的引用。这样只有自己可以修改容器的内容,而别人只能读取。
17.11.3Collection或Map的同步控制
1、
public class Synchroniztion {
public static void main(String[] args) {
//直接将新成的容器传递给了适当的“同步”方法 这样就不会有任何暴露出不同步的版本
Collection<String> collection= Collections.synchronizedCollection(new ArrayList<String>());
List<String> list=Collections.synchronizedList(new ArrayList<String>());
Set<String> set=Collections.synchronizedSet(new HashSet<String>());
Set<String> set1=Collections.synchronizedSet(new TreeSet<String>());
Map<String,String> map=Collections.synchronizedMap(new HashMap<String, String>());
Map<String,String> map1=Collections.synchronizedMap(new TreeMap<String, String>());
}
}
2、快速报错。Java容器有一种保护机制,能够防止多个进程同时修改同一个容器的内容,如果在你迭代遍历某个容器的过程中,另一个进程介入其中,并且插入、删除或修改此容器内的某个对象:那么就会出现问题:也许迭代过程已经处理过容器中的该元素了,也许还没处理,也许在调用size()之后容器的尺寸收缩了。
3、Java容器类类库采用快速报错机制。它会探查容器上的任何处理你的进程所进行的操作以外的所有变化,一旦发现其他进程修改了容器,就会立刻抛出ConcurrentModificationException异常。“快速报错”的意思是:不是使用复杂的算法在事后来检查问题。
4、
package com17下;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
/**
* Created by Panda on 2018/5/18.
*/
public class FailFast {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<String>();
Iterator<String> iterator=collection.iterator();
collection.add("An object");
try{
String s=iterator.next();
}catch (ConcurrentModificationException e){
System.out.println(e);
}
}
/**
* java.util.ConcurrentModificationException
*/
//程序运行时发生了异常,因为在容器取得迭代器之后,又有东西被放入到了该容器中,当程序的不同部分修改
//同一个容器时,就可能导致容器的状态不一致。
}
17.12持有引用
1、对象是可获得的,是指此对象可在程序中的某处找到。这意味着在栈中有一个普通的引用,而它正指向此对象;也可能是你的引用指向某个对象,而那个对象含有另一个引用正在讨论的对象,也可能有更多的中间链接。如果一个对象是“可获得的”,垃圾回收器就不能释放它,因为它仍然为你的程序所用。如果一个对象不是“可获得的”,那么你的程序将无法使用它,所以将其回收是安全的。
2、SoftReference WeakReference PhantomReference 由强到弱排列,对应不同级别的“可获得性”。SoftReference用以实现内存敏感的高速缓存。WeakReference是为实现“规范映射”中对象的实例可以在程序的多处被同时使用,以节省存储空间。 PhantomReference 用以调度回收前的清理工作。
17.12.1 WeakHashMap
1、容器类中有一种特殊的Map,即WeakHashMap,它被用来保存WeakReferene。WeakHashMap允许垃圾回收器自动清理键和值。
17.13 Java 1.0/1.1 的容器
17.13.1 Vector和Emumeration
17.13.2
17.13.3 Stack
17.13.4 BitSet
17.14 总结