查看“核心技术:集合”的源代码
←
核心技术:集合
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:JavaCore]] == Java 集合框架 == === 将集合的接口与实现分离 === 与现代的数据结构类库的常见情况一样, Java 集合类库也将接口( interface ) 与实现( implementation) 分离。<br/> 以队列为例: : [[File:队列.png|600px]] 队列接口的最简形式可能类似下面这样: <syntaxhighlight lang="java"> public interface Queue<E> // a simplified form of the interface in the standard library { void add(E element) ; E remove(); int size(); } </syntaxhighlight> 而,队列通常有两种实现方式: # 一种是使用循环数组; # 另一种是使用链表; : [[File:队列的实现.png|600px]] === Colloction 接口 === 在 Java 类库中,集合类的基本接口是 Collection 接口。这个接口有两个基本方法 <syntaxhighlight lang="java"> public interface Collection<E> { boolean add(E element); Iterator<E> iterator(); ... } </syntaxhighlight> # add 方法用于向集合中添加元素。如果添加元素确实改变了集合就返回 true, 如果集合没有发生变化就返回 false; # iterator 方法用于返回一个实现了 Iterator 接口的对象; #: 可以使用这个迭代器对象依次访问集合中的元素。 === 迭代器 === 参考:'''[[关于Iterable与Iterator的那些事]]''' Iterator 接口包含4 个方法: <syntaxhighlight lang="java"> public interface Iterator<E> { E next(); // 逐个访问集合中的每个元素(如果到达了集合的末尾将抛出一个NoSuchElementException) boolean hasNext(); // 遍历时判断是否还有下一个元素 void remove(); // default void forEachRemaining(Consumer<? super E> action) ; // 对迭代器的每一个元素调用action(Consumer是一个函数式接口,所以可用lambda表达式) } </syntaxhighlight> 如果想要査看集合中的所有元素,就请求一个迭代器,并在 hasNext 返回 true 时反复地调用 next 方法。例如: : <syntaxhighlight lang="java"> Collection<String> c = . . .; Iterator<String> iter = c.iterator(); while (iter.hasNextO) { String element = iter.next(); // do something with element } </syntaxhighlight> 用“ '''foreach'''” 循环可以更加简练地表示同样的循环操作: : <syntaxhighlight lang="java"> for (String element : c) { // do something with element } </syntaxhighlight> * '''编译器简单地将“foreach” 循环翻译为带有迭代器的循环''',“foreach”循环可以与任何实现了 '''Iterable''' 接口的对象一起工作; *: Collection 接口扩展了(而非继承)Iterable 接口。因此,对于标准类库中的任何集合都可以使用“foreach” 循环。 * 在 Java SE 8 中,甚至不用写循环。可以调用'''forEachRemaining'''方法并提供 lambda 表达式(它会处理一个元素)。 *: 将对迭代器的每一个元素调用这个 lambda 表达式,直到再没有元素为止。 *: <syntaxhighlight lang="java"> iterator.forEachRemaining(element -> do something with element); </syntaxhighlight> * '''元素被访问的顺序取决于集合类型'''。 *: 如对 ArrayList:迭代器将从索引 0 开始,每次迭代索引值加 1; *: 然而,如对 HashSet 迭代:每个元素将会按照某种随机的次序出现。(能够遍历到集合中的所有元素,但却无法预知元素被访问的次序) ==== 【关于:迭代器的位置】 ==== '''应该将 Java 迭代器认为是位于两个元素之间(而非指向一个元素)'''。当调用 next 时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。 : [[File:迭代器的位置.png|400px]] * Iterator 接口的 '''remove 方法将会删除上次调用 next 方法时返回的元素'''; 如: # 删除集合首个元素: #: <syntaxhighlight lang="java"> Iterator<String> it = c.iterator(); it.next(); // skip over the first element it.remove(); // now remove it </syntaxhighlight> # 删除两个相邻的元素: #: <syntaxhighlight lang="java"> it.remove(); it.next(); it.remove(); // 而非 // it.remove(); // it.remove(); </syntaxhighlight> === 泛型使用方法 === * 由于Collection 与Iterator 都是'''泛型接口''',可以编写操作任何集合类型的实用方法。 * Java 类库提供了一个类AbstractCollection,它将基础方法size和iterator抽象化了,但是提供了例行方法。 *: 所以,一个具体的集合类可以扩展AbstractCollection 类了(实际上也是这样的) *: 然而,这种“伴随类”并不是最好的方式,在原接口中将方法定义为“默认方法”会更好。 '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Collection<E> |- | style="width:50%;" | Iterator < E> iterator() | style="width:50%;" | 返回一个用于访问集合中每个元素的迭代器。 |- | style="width:50%;" | int size() | style="width:50%;" | 返回当前存储在集合中的元素个数。 |- | style="width:50%;" | boolean isEmpty() | style="width:50%;" | 如果集合中没有元素,返回true。 |- | style="width:50%;" | boolean contains(Object obj) | style="width:50%;" | 如果集合中包含了一个与obj 相等的对象,返回true。 |- | style="width:50%;" | boolean containsAll(Collection<?> other) | style="width:50%;" | 如果这个集合包含other 集合中的所有元素,返回trueo |- | style="width:50%;" | boolean add(Object element) | style="width:50%;" | 将一个元素添加到集合中。 * 如果由于这个调用改变了集合,返回true。 |- | style="width:50%;" | boolean addAll(Col1ection<? extends E> other) | style="width:50%;" | 将other 集合中的所有元素添加到这个集合。 * 如果由于这个调用改变了集合,返回true。 |- | style="width:50%;" | boolean remove(Object obj) | style="width:50%;" | 从这个集合中删除等于obj 的对象。 * 如果有匹配的对象被删除, 返回true。 |- | style="width:50%;" | boolean removeAll(Col 1ection<?> other) | style="width:50%;" | 从这个集合中删除other 集合中存在的所有元素。 * 如果由于这个调用改变了集合,返回true。 |- | style="width:50%;" | default boolean removeIf(Predicate<? super E> filter)8 | style="width:50%;" | 从这个集合删除filter 返回true 的所有元素。 * 如果由于这个调用改变了集合,则返回true。 |- | style="width:50%;" | void clear() | style="width:50%;" | 从这个集合中删除所有的元素。 |- | style="width:50%;" | boolean retainAll(Collection<?> other) | style="width:50%;" | 从这个集合中删除所有与other 集合中的元素不同的元素。 * 如果由于这个调用改变了集合,返回true。 |- | style="width:50%;" | Object[] toArray() | style="width:50%;" | 返回这个集合的对象数组。 |- | style="width:50%;" | <T> T[] toArray(T[] arrayToFill) | style="width:50%;" | 返回这个集合的对象数组。 如果 arrayToFill 足够大,就将集合中的元素填入这个数组中。剩余空间填补null; 否则,分配一个新数组,其成员类型与 arrayToFill 的成员类型相同,其长度等于集合的大小,并填充集合元素。 |- ! colspan="2" style="text-align:left;"| java.util.Iterator<E> |- | style="width:50%;" | boolean hasNext() | style="width:50%;" | 如果存在可访问的元素,返回true。 |- | style="width:50%;" | E next() | style="width:50%;" | 返回将要访问的下一个对象。 * 如果已经到达了集合的尾部,将拋出一个 NoSuchElementException。 |- | style="width:50%;" | void remove() | style="width:50%;" | 删除上次访问的对象。 * 这个方法必须紧跟在访问一个元素之后执行。 * 如果上次访问之后,集合已经发生了变化, 这个方法将抛出一个 IllegalStateException。 |} === 集合框架中的接口 === [[File:集合框架的接口.png|800px]] # 集合有两个基本接口:Collection 和Map。 #: 可以用以下方法在集合中插人元素: #: <syntaxhighlight lang="java"> boolean add(E element) </syntaxhighlight> #: 不过,由于映射包含键/ 值对,所以要用put 方法来插人: #: <syntaxhighlight lang="java"> V put(K key, V value) </syntaxhighlight> #: 要从集合读取元素, 可以用迭代器访问元素。不过,从映射中读取值则要使用get 方法: #: <syntaxhighlight lang="java"> V get (K key) </syntaxhighlight> ==== List ==== List 是一个有序集合(ordered collection),元素会增加到容器中的特定位置。可以采用两种方式访问元素: # 迭代器访问 # 随机访问(random access) * List 接口定义了多个用于随机访问的方法: *: void add(int index, E element) *: void remove(int index) *: E get(int index) *: E set(int index, E element) ==== Set ==== Set 接口等同于Collection 接口,不过其方法的行为有更严谨的定义:集( set ) 的add 方法不允许增加重复的元素。 * 要适当地定义集的equals 方法:只要两个集包含同样的元素就认为是相等的,而不要求这些元素有同样的顺序。 * hashCode 方法的定义要保证包含相同元素的两个集会得到相同的散列码。 * '''SortedSet''' 和'''SortedMap'''接口会提供用于排序的比较器对象,这两个接口定义了可以得到集合子集视图的方法。 * Java SE 6 引人了接口'''NavigableSet'''和'''NavigableMap''',其中包含一些用于搜索和遍历有序集和映射的方法。 == 具体的集合 == {| class="wikitable" |+ Java 库中的具体集合 ! 集合类型 !! 描述 |- ! colspan="2"| AbstractCollection |- | ArrayList || 一种可以'''动态增长和缩减'''的索引序列 |- | LinkedList || 一种可以在任何位置进行'''高效地插人和删除'''操作的有序序列 |- | ArrayDeque || 一种用循环数组实现的'''双端队列''' |- | HashSet || 一种没有重复元素的'''无序集合''' |- | TreeSet || —种'''有序集''' |- | EnumSet || 一种包含'''枚举类型值的集''' |- | LinkedHashSet || 一种可以记住元素'''插人次序的集''' |- | PriorityQueue || 一种允许高效'''删除最小元素的集合''' |- ! colspan="2"| AbstractMap |- | HashMap || 一种存储'''键/值关联'''的数据结构 |- | TreeMap || —种键值'''有序排列的映射表''' |- | EnumMap || 一种键值属于'''枚举类型的映射表''' |- | LinkedHashMap || 一种可以记住键/值项'''添加次序的映射表''' |- | WeakHashMap || 一种其值无用武之地后可以被垃圾回收器回收的映射表 |- | IdentityHashMap || 一种用==而不是用equals比较键值的映射表 |} [[File:集合框架中的类.png|800px]] === 链表(LinkedList)=== * 链表不支持随机方法,但便于插入删除; * Java中的所有链表实际上都是双向链接的(双向链表); ==== 添加 ==== # LinkedList.add:将对象添加到链表的尾部; # ListIterator.add:将对象添加到当前位置; ==== 删除 ==== *(Java中删除链表元素不需要考虑内部指向,调用方法即可) # 在调用 next 之后 remove,会删除迭代器左侧的元素(类似键盘的“删除”) # 在调用 previous 之后 remove,删除迭代器右侧的元素(类似键盘的“DEL”) ==== ListItetator ==== * ListItetator:Iterator的子类,专门用于LinkedList的迭代; * 迭代器的位置,并不直接指向元素,而是在元素之间; * 迭代器的 add 方法只依赖于迭代器的位置,而 remove 方法依赖于迭代器的状态(调用了next还是previous); * 同一个LinkedList的多个迭代器之间操作冲突的话(一个修改了集合,一个正在读),会抛出“ConcurrentModificationException”异常。 *: 所以:可以更具需要给容器附加多个迭代器,但只有一个可以进行修改操作; * 尽量使用迭代器,而不使用 LinkedList.get方法来进行读取(效率太低) '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.List<E> |- | style="width:50%;" | ListIterator<E> listIterator ( ) | style="width:50%;" | 返回一个列表迭代器, 以便用来访问列表中的元素。 |- | style="width:50%;" | ListIterator <E> listIterator (int index ) | style="width:50%;" | 返回一个列表迭代器, 以便用来访问列表中的元素, 这个元素是第一次调用next 返回的给定索引的元素。 |- | style="width:50%;" | void add (int i , E element) | style="width:50%;" | 在给定位置添加一个元素。 |- | style="width:50%;" | void addAll (int i , Collection<? extends E> elements) | style="width:50%;" | 将某个集合中的所有元素添加到给定位置。 |- | style="width:50%;" | E remove (int i) | style="width:50%;" | 删除给定位置的元素并返回这个元素。 |- | style="width:50%;" | E get (int i) | style="width:50%;" | 获取给定位置的元素。 |- | style="width:50%;" | E set (int i , E element) | style="width:50%;" | 用新元素取代给定位置的元素, 并返回原来那个元素。 |- | style="width:50%;" | int indexOf (Object element) | style="width:50%;" | 返回与指定元素相等的元素在列表中第一次出现的位置, 如果没有这样的元素将返回-1。 |- | style="width:50%;" | int lastIndexOf(Object element) | style="width:50%;" | 返回与指定元素相等的元素在列表中最后一次出现的位置, 如果没有这样的元素将返回-1。 |- ! colspan="2" style="text-align:left;"| java.util.Listlterator<E> |- | style="width:50%;" | void add(E newElement) | style="width:50%;" | 在当前位置前添加一个元素。 |- | style="width:50%;" | void set(E newElement) | style="width:50%;" | 用新元素取代next 或previous 上次访问的元素。 * 如果在next 或previous 上次调用之后列表结构被修改了,将拋出一个IllegalStateException 异常。 |- | style="width:50%;" | boolean hasPrevious() | style="width:50%;" | 当反向迭代列表时, 还有可供访问的元素, 返回true。 |- | style="width:50%;" | E previous() | style="width:50%;" | 返回前对象。如果已经到达了列表的头部, 謝te出一hNoSuchElementException 异常。 |- | style="width:50%;" | int nextIndex() | style="width:50%;" | 返回下一次调用next 方法时将返回的元素索引。 |- | style="width:50%;" | int previousIndex() | style="width:50%;" | 返回下一次调用previous 方法时将返回的元素索引。 |- ! colspan="2" style="text-align:left;"| java.util.LinkedList<E> |- | style="width:50%;" | LinkedList() | style="width:50%;" | 构造一个空链表。 |- | style="width:50%;" | LinkedList(Collection<? extends E> elements) | style="width:50%;" | 构造一个链表, 并将集合中所有的元素添加到这个链表中。 |- | style="width:50%;" | void addFirst(E element) | style="width:50%;" rowspan="2" | 将某个元素添加到列表的头部或尾部。 |- | style="width:50%;" | void addLast(E element) |- | style="width:50%;" | E getFirst() | style="width:50%;" rowspan="2" | 返回列表头部或尾部的元素。 |- | style="width:50%;" | E getLast() |- | style="width:50%;" | E removeFirst() | style="width:50%;" rowspan="2" | 删除并返回列表头部或尾部的元素。 |- | style="width:50%;" | E removeLast() |} === 数组列表(ArrayList)=== List的数组实现,支持随机读取,不便于插入删除(需要移动元素)。 ==== ArrayList 与 Vector ==== '''Vector 类的所有方法都是同步的''',可以由两个线程安全地访问一个 Vector 对象,但也比 ArrayList 更耗时; * Vector 的方法中,用到了'''synchronized'''来实现同步锁; === 散列集(HashSet)=== 利用对象的hashcode,来将对象存放在散列集的不同位置。 * HashSet 的迭代器将依次访问所有的桶。由于元素散列分布,所以迭代器访问元素是无序的; * 修改元素时,如果元素的散列码变化,则其在数据结构中的位置也会变化 HashSet的实现: * 由其构造函数可以看出,'''HashSet 是由 HashMap 来实现的''': *: <syntaxhighlight lang="java"> public HashSet() { map = new HashMap<>(); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); } </syntaxhighlight> ==== 散列表 ==== 散列表,用于保存集合中对象的散列码。Java中,散列表用链表数组实现: :[[File:散列表.png|400px]] (每个列表被称为一个桶,bucket) 要想査找表中对象的位置,就要先计算它的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的桶的索引。<br/> : 例如, 如果某个对象的散列码为76268, 并且有128个桶, 对象应该保存在第108号桶中(76268除以128余108) ==== 散列冲突 ==== 插入对象时,遇到桶被占满的情况,即为散列冲突。<br/> 这时, 需要用新对象与桶中的所有对象进行比较, 査看这个对象是否已经存在。如果散列码是合理且随机分布的, 桶的数目也足够大, 需要比较的次数就会很少。 * 在JavaSE 8 中, 桶满时会从链表变为平衡二叉树(便于查找?)。 ==== 桶数 ==== 桶数,是指用于收集具有相同散列值的桶的数目。通常,将桶数设置为预计元素个数的75% ~ 150%。<br/> *标准类库使用的桶数是2 的幂, 默认值为16 ==== 再散列 ==== 如果散列表太满,就需要再散列(rehashed):创建一个桶数更多的表,并将所有元素插入到这个新表中,然后丢弃原来的表。 装填因子(load factor) 决定何时对散列表进行再散列。<br/> 例如, 如果装填因子为0.75 (默认值),而表中超过75%的位置已经填人元素, 这个表就会用双倍的桶数自动地进行再散列。 * 对于大多数应用程序来说, 装填因子为 0.75 是比较合理的; '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.HashSet<E> |- | style="width:50%;" | HashSet ( ) | style="width:50%;" | 构造一个空散列表。 |- | style="width:50%;" | HashSet (Collection<? extends E> elements ) | style="width:50%;" | 构造一个散列集,并将集合中的所有元素添加到这个散列集中。 |- | style="width:50%;" | HashSet (int initialCapacity) | style="width:50%;" | 构造一个空的具有指定容量(桶数)的散列集。 |- | style="width:50%;" | HashSet (int initialCapacity , float loadFactor ) | style="width:50%;" | 构造一个具有指定容量和装填因子(一个0.0 ~ 1.0 之间的数值, 确定散列表填充的百分比,当大于这个百分比时,散列表进行再散列)的空散列集。 |- ! colspan="2" style="text-align:left;"| java.lang.Object |- | style="width:50%;" | int hashCode ( ) | style="width:50%;" | 返回这个对象的散列码。散列码可以是任何整数,包括正数或负数。 * equals 和hashCode的定义必须兼容,即如果“x.equals(y)”为“true”,“x.hashCode()”必须等于“y.hashCode()”。 |} === 树集(TreeSet)=== 树集是一个有序集合(sorted collection)。元素的排序是用树结构完成的(当前使用的是<big>“'''[[树:红黑树|红黑树]]'''”</big>); * '''使用树集,元素必须实现 Comparable 接口,或者构造集时必须提供一个 Comparator'''。 * Java6 之后,TreeSet类实现了 NavigableSet 接口。 *: 这个接口增加了几个便于定位元素以及反向遍历的方法。 每次将一个元素添加到树中时,都被放置在正确的排序位置上。因此: # 迭代器总是以排好序的顺序访问每个元素。 # 添加插入较HashSet慢,但查找更快。 # 如果树中包含 n 个元素,査找新元素的正确位置平均需要“log2 n”次比较。 TreeSet的实现: * 由其构造函数可以看出,'''TreeSet 是由 TreeMap 来实现的''': *: <syntaxhighlight lang="java"> public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable { /** * The backing map. */ private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object(); TreeSet(NavigableMap<E,Object> m) { this.m = m; } public TreeSet() { this(new TreeMap<E,Object>()); } public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); } public TreeSet(Collection<? extends E> c) { this(); addAll(c); } public TreeSet(SortedSet<E> s) { this(s.comparator()); addAll(s); } public boolean addAll(Collection<? extends E> c) { // Use linear-time version if applicable if (m.size()==0 && c.size() > 0 && c instanceof SortedSet && m instanceof TreeMap) { SortedSet<? extends E> set = (SortedSet<? extends E>) c; TreeMap<E,Object> map = (TreeMap<E, Object>) m; Comparator<?> cc = set.comparator(); Comparator<? super E> mc = map.comparator(); if (cc==mc || (cc != null && cc.equals(mc))) { map.addAllForTreeSet(set, PRESENT); return true; } } return super.addAll(c); } </syntaxhighlight> '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.TreeSet<E> |- | style="width:50%;" | TreeSet() | style="width:50%;" rowspan="2" | 构造一个空树集。 |- | style="width:50%;" | TreeSet(Comparator<? super E> comparator) |- | style="width:50%;" | TreeSet(Collection<? extends E> elements) | style="width:50%;" rowspan="2" | 构造一个树集, 并增加一个集合或有序集中的所有元素(对于后一种情况,要使用同样的顺序)。 |- | style="width:50%;" | TreeSet(SortedSet<E> s) |- ! colspan="2" style="text-align:left;"| java.util.SortedSet<E> |- | style="width:50%;" | Comparator<? super E> comparator() | style="width:50%;" | 返回用于对元素进行排序的比较器。如果元素用Comparable 接口的compareTo方法进行比较则返回null。 |- | style="width:50%;" | E first() | style="width:50%;" rowspan="2" | 返回有序集中的最小元素或最大元素。 |- | style="width:50%;" | E last() |- ! colspan="2" style="text-align:left;"| java.util.NavigableSet<E> |- | style="width:50%;" | E higher(E value) | style="width:50%;" rowspan="2" | 返回大于value 的最小元素或小于value 的最大元素,如果没有这样的元素则返回null。 |- | style="width:50%;" | E lower(E value) |- | style="width:50%;" | E ceiling(E value) | style="width:50%;" rowspan="2" | 返回大于等于vaiue 的最小元素或小于等于value 的最大元素, 如果没有这样的元素则返回null。 |- | style="width:50%;" | E floor(E value) |- | style="width:50%;" | E pollFirst() | style="width:50%;" rowspan="2" | 删除并返回这个集中的最大元素或最小元素, 这个集为空时返回null。 |- | style="width:50%;" | E pollLast() |- | style="width:50%;" | Iterator<E> descendingIterator() | style="width:50%;" | 返回一个按照递减顺序遍历集中元素的迭代器。 |} === 队列(Queue)双端队列(Deque)=== 在Java SE 6 中引人了Deque 接口,'''ArrayDeque'''和'''LinkedList'''类实现了Deque接口。这两个类都提供了双端队列, 而且在必要时可以增加队列的长度。 <syntaxhighlight lang="java"> public interface Deque<E> extends Queue<E> { </syntaxhighlight> <syntaxhighlight lang="java"> public interface Queue<E> extends Collection<E> { </syntaxhighlight> * (在第14章将会看到有限队列和有限双端队列。) * (看看消息中间件的实现?) '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Queue<E> |- | style="width:50%;" | boolean add (E element) | style="width:50%;" rowspan="2" | 如果队列没有满,将给定的元素添加到这个双端队列的尾部并返回true。 * 如果队列满了,第一个方法将拋出一个 IllegalStateException, 而第二个方法返回 false。 |- | style="width:50%;" | boolean offer (E element) |- | style="width:50%;" | E remove ( ) | style="width:50%;" rowspan="2" | 假如队列不空, 删除并返回这个队列头部的元素。 * 如果队列是空的,第一个方法抛出 NoSuchElementException, 而第二个方法返回 null。 |- | style="width:50%;" | E poll ( ) |- | style="width:50%;" | E element( ) | style="width:50%;" rowspan="2" | 如果队列不空,返回这个队列头部的元素,但不删除。 * 如果队列空,第一个方法将拋出一个 NoSuchElementException, 而第二个方法返回 null。 |- | style="width:50%;" | E peek( ) |- ! colspan="2" style="text-align:left;"| java.util.Deque<E> |- | style="width:50%;" | void addFirst (E element) | style="width:50%;" rowspan="4" | 将给定的对象添加到双端队列的头部或尾部。 * 如果队列满了,前面两个方法将拋出一个 IllegalStateException,而后面两个方法返回 false。 |- | style="width:50%;" | void addLast (E element) |- | style="width:50%;" | boolean offerFirst (E element) |- | style="width:50%;" | boolean offerLast (E element) |- | style="width:50%;" | E removeFirst( ) | style="width:50%;" rowspan="4" | 如果队列不空,删除并返回队列头部的元素。 * 如果队列为空,前面两个方法将拋出一个 NoSuchElementException, 而后面两个方法返回 null。 |- | style="width:50%;" | E removeLast( ) |- | style="width:50%;" | E pollFirst( ) |- | style="width:50%;" | E pollLast( ) |- | style="width:50%;" | E getFirst( ) | style="width:50%;" rowspan="4" | 如果队列非空,返回队列头部的元素,但不删除。 * 如果队列空,前面两个方法将拋出一个 NoSuchElementException, 而后面两个方法返回 null。 |- | style="width:50%;" | E getLast( ) |- | style="width:50%;" | E peekFirst( ) |- | style="width:50%;" | E peekLast( ) |- ! colspan="2" style="text-align:left;"| java.util.ArrayDeque<E> |- | style="width:50%;" | ArrayDeque( ) | style="width:50%;" rowspan="2" | 用初始容量16 或给定的初始容量构造一个无限双端队列。 |- | style="width:50%;" | ArrayDeque(int initialCapacity) |} ==== 【关于:阻塞队列(BlockingQueue)】 ==== BlockingQueue<E> 接口扩展了 Queue<E>接口,用于阻塞队列的实现。 * 见:【'''[[Java中的阻塞队列]]'''】 === 优先级队列(priority queue)=== 优先级队列(priority queue) 中的元素可以按照任意的顺序插人,却总是按照排序的顺序进行检索。 * '''无论何时调用remove 方法, 总会获得当前优先级队列中最小的元素'''。 * 优先级队列'''使用堆(heap),对树执行添加(add) 和删除(remore) 操作''',让最小的元素移动到根,而不必花费时间对元素进行排序。 *: 堆是一个可以自我调整的二叉树; * 与TreeSet—样,一个优先级队列既可以保存实现了Comparable接口的类对象,也可以保存在构造器中提供的Comparator对象。 * 使用优先级队列的典型示例是任务调度。 '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.PriorityQueue |- | style="width:50%;" | PriorityQueue() | style="width:50%;" rowspan="2" | 构造一个用于存放 Comparable 对象的优先级队列。 |- | style="width:50%;" | PriorityQueue(int initialCapacity) |- | style="width:50%;" | PriorityQueue(int initialCapacity, Comparator<? super E> c) | style="width:50%;" | 构造一个优先级队列, 并用指定的比较器对元素进行排序。 |} == 映射 == * 映射“Map”接口并不实现“Iterator”,所以并没有迭代器,但是其“entrySet()”返回值类型是“Set”接口的实现类,可以用它的迭代器对映射进行迭代操作; === 基本映射操作 === Java 类库为映射提供了两个通用的实现:HashMap 和TreeMap。这两个类都实现了Map 接口。 # 散列映射对键进行散列, # 树映射用键的整体顺序对元素进行排序, 并将其组织成搜索树。 * 散列或比较函数只能作用于键。与键关联的值不能进行散列或比较。 '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Map<K, V> |- | style="width:50%;" | V get(Object key) | style="width:50%;" | 获取与键对应的值;返回与键对应的对象,如果在映射中没有这个对象则返回null。键可以为null。 |- | style="width:50%;" | default V getOrDefault(Object key, V defaultValue) | style="width:50%;" | 获得与键关联的值;返回与键关联的对象,或者如果未在映射中找到这个键,则返回defaultValue。 |- | style="width:50%;" | V put(K key, V value) | style="width:50%;" | 将键与对应的值关系插入到映射中。 * 如果这个键已经存在,新的对象将取代与这个键对应的旧对象。 * 这个方法将返回键对应的旧值。如果这个键以前没有出现过则返回null。 * 键可以为null, 但值不能为null。 |- | style="width:50%;" | void putAll(Map<? extends K , ? extends V> entries) | style="width:50%;" |将给定映射中的所有条目添加到这个映射中。 |- | style="width:50%;" | boolean containsKey(Object key) | style="width:50%;" |如果在映射中已经有这个键, 返回true。 |- | style="width:50%;" | boolean containsValue(Object value) | style="width:50%;" |如果映射中已经有这个值, 返回true。 |- | style="width:50%;" | default void forEach(BiConsumer<? super K ,? super V> action)8 | style="width:50%;" |对这个映射中的所有键/ 值对应用这个动作。 |- ! colspan="2" style="text-align:left;"| java.utii.HashMap<K,V> |- | style="width:50%;" | HashMap( ) | style="width:50%;" rowspan="3" | 用给定的容量和装填因子构造一个空散列映射。 *(装填因子是一个 0.0 ~ 1.0 之间的数值。这个数值决定散列表填充的百分比。一旦到了这个比例,就要将其再散列到更大的表中) * 默认的装填因子是0.75。 |- | style="width:50%;" | HashMap(int initialCapacity) |- | style="width:50%;" | HashMap(int initialCapacity, float 1oadFactor) |- ! colspan="2" style="text-align:left;"| java.util.TreeMap<K,V> |- | style="width:50%;" | TreeMap( ) | style="width:50%;" |为实现Comparable 接口的键构造一个空的树映射。 |- | style="width:50%;" | TreeMap(Comparator<? super K> c) | style="width:50%;" |构造一个树映射, 并使用一个指定的比较器对键进行排序。 |- | style="width:50%;" | TreeMap(Map<? extends K, ? extends V> entries) | style="width:50%;" |构造一个树映射, 并将某个映射中的所有条目添加到树映射中。 |- | style="width:50%;" | TreeMap(SortedMap<? extends K, ? extends V> entries) | style="width:50%;" |构造一个树映射, 将某个有序映射中的所有条目添加到树映射中, 并使用与给定的有序映射相同的比较器。 |- ! colspan="2" style="text-align:left;"| java.util.SortedMap<K, V> |- | style="width:50%;" | Comparator< ? super K> comparator() | style="width:50%;" |返回对键进行排序的比较器。如果键是用Comparable 接口的compareTo 方法进行比较的,返回null。 |- | style="width:50%;" | K firstKey( ) | style="width:50%;" rowspan="2" | 返回映射中最小元素和最大元素。 |- | style="width:50%;" | K lastKey( ) |} === 更新映射项 === 以“使用一个映射统计一个单词在文件中出现的频度”为例: # 看到一个单词(word) 时,将计数器增1, 如下所示: #:<syntaxhighlight lang="java"> counts.put(word, counts.get(word)+ 1); </syntaxhighlight> #: 这是可以的, 不过有一种情况除外: 就是第一次看到word 时。在这种情况下,get 会返回null , 因此会出现一个NullPointerException 异常。 #: 作为一个简单的补救, 可以使用'''getOrDefault''' 方法: #:<syntaxhighlight lang="java"> counts.put(word, counts.getOrDefault(word, 0)+ 1); </syntaxhighlight> # 另一种方法是首先调用'''putlfAbsent''' 方法。只有当键原先存在时才会放入一个值。 #:<syntaxhighlight lang="java"> counts.putlfAbsent(word, 0); counts.put(word, counts.get(word)+ 1); // Now we know that get will succeed </syntaxhighlight> # 不过还可以使用 '''merge''' 方法简化这个常见的操作。如果键原先不存在,下面的调用: #:<syntaxhighlight lang="java"> counts.merge(word, 1, Integer::sum); </syntaxhighlight> #: 将把word 与1 关联,否则使用Integer::sum 函数组合原值和1 (也就是将原值与1 求和)。 '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Map<K,V> 1.2 |- | style="width:50%;" | default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) 8 | style="width:50%;" | 如果 key 与一个非 null 值 v 关联,将函数应用到 v 和 value,将key 与结果关联,或者如果结果为 null ,则删除这个键。否则,将key 与value 关联,返回 get(key)。 |- | style="width:50%;" | default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 8 | style="width:50%;" | 将函数应用到 key 和 get(key)。将 key 与结果关联,或者如果结果为 null ,则删除这个键。返回 get(key)。 |- | style="width:50%;" | default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 8 | style="width:50%;" | 如果 key 与一个非 null 值 v 关联,将函数应用到 key 和 v,将 key 与结果关联,或者如果结果为 null ,则删除这个键。返回 get(key)。 |- | style="width:50%;" | default V computeIfAbsent(K key , Function<? super K, ? extends V> mappingFunction) 8 | style="width:50%;" | 将函数应用到 key,除非 key 与一个非 null 值关联。将 key 与结果关联,或者如果结果为 null ,则删除这个键。返回 get(key)。 |- | style="width:50%;" | default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) 8 | style="width:50%;" | 在所有映射项上应用函数。将键与非 null 结果关联,对于 null 结果,则将相应的键删除。 |} === 映射视图(键集、键/值对集) === <pre> 集合框架不认为映射本身是一个集合。(其他数据结构框架认为映射是一个 键/值 对集合,或者是由键索引的值集合)。不过,可以得到映射的视图( View )——这是实现了Collection 接口或某个子接口的对象。 </pre> 三种视图如下: {| class="wikitable" ! 视图 !! 命令 !! 示例 |- | 键集 | <syntaxhighlight lang="java" inline>Set<K> keySet()</syntaxhighlight> | <syntaxhighlight lang="java"> Set<String> keys = map.keySet(); for (String key : keys) { // do something with key } </syntaxhighlight> |- | 值集合 | <syntaxhighlight lang="java" inline>Collection<V> values()</syntaxhighlight> *(不是一个集,因为可以重复) | <syntaxhighlight lang="java"> </syntaxhighlight> |- | 键/值对集 | <syntaxhighlight lang="java" inline>Set<Map.Entry<K, V>> entrySet()</syntaxhighlight> | <syntaxhighlight lang="java"> for (Map.Entry<String, Employee〉entry : staff.entrySet()) { String k = entry.getKey(); Employee v = entry.getValue(); // do something with k, v } </syntaxhighlight> |} * 条目集的元素是实现 Map.Entry 接口的类的对象。 * 如果在“键集”视图上调用迭代器的remove方法,会从映射中删除这个键和与它关联的值;如果试图调用add 方法, 它会抛出一个UnsupportedOperationException。 * 原先“键/值对集”是访问所有映射条目的最高效的方法。如今,只需要使用'''forEach'''方法(使用lambda表达式): *: <syntaxhighlight lang="java"> counts.forEach((k, v) -> { // do something with k, v }); </syntaxhighlight> '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Map<K, V> |- | style="width:50%;" | Set<Map.Entry<K, V>> entrySet( ) | style="width:50%;" | 返回 Map.Entry 对象(映射中的键/ 值对)的一个集视图。 * 可以从这个集中删除元素,它们将从映射中删除,但是不能增加任何元素。 |- | style="width:50%;" | Set<K> keySet( ) | style="width:50%;" | 返回映射中所有键的一个集视图。 * 可以从这个集中删除元素,键和相关联的值将从映射中删除,但是不能增加任何元素。 |- | style="width:50%;" | Collection<V> values( ) | style="width:50%;" | 返回映射中所有值的一个集合视图。 * 可以从这个集合中删除元素,所删除的值及相应的键将从映射中删除,不过不能增加任何元素。 |- ! colspan="2" style="text-align:left;"| java.util.Map.Entry<K, V> |- | style="width:50%;" | K getKey( ) | style="width:50%;" rowspan="2" | 返回这一条目的键或值。 |- | style="width:50%;" | V getValue( ) |- | style="width:50%;" | V setValue(V newValue) | style="width:50%;" | 将相关映射中的值改为新值,并返回原来的值。 |} === 弱散列映射 === 【???】 === 链接散列集与映射(LinkedHashSet 与 LinkedHashMap) === <pre> LinkedHashSet 和 LinkedHashMap 类用来记住插人元素项的顺序。这样就可以避免在散列表中的项从表面上看是随机排列的。当条目插入到表中时,就会并人到双向链表中。 </pre> * LinkedHashSet 由 LinkedHashMap 实现; * LinkedHashMap在HashMap的基础上,'''采用双向链表(doubly-linked list)的形式将所有entry连接起来''',这样是为保证元素的迭代顺序跟插入顺序相同。 [[File:LinkedHashMap.png|600px]] 特点: * 散列表(HashMap)用于元素的存储结构; * '''双向链(List)表用于维护元素的迭代顺序,用于元素遍历'''(可以是插入顺序,也可以是访问顺序); ==== 关于“迭代顺序”:“插入顺序”“访问顺序” ==== 如上所述,迭代(遍历) LinkedHashMap 元素的时候,会按照链接顺序(即:迭代顺序)进行。<br/> 而迭代顺序: # 可以是“插入顺序”:按插入顺序维护链表; # 也可以是“访问顺序”:按访问顺序维护链表(即链表头元素是“最近最少使用”); 而这取决于其“'''accessOrder'''”值域: # 构造对象时,确定 accessOrder: #: <syntaxhighlight lang="java"> public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; } public LinkedHashMap() { super(); accessOrder = false; } public LinkedHashMap(Map<? extends K, ? extends V> m) { super(); accessOrder = false; putMapEntries(m, false); } public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; } </syntaxhighlight> # 调用相关方法时,用accessOrder值判断,是否将被访问的元素放到链表末尾; #: <syntaxhighlight lang="java"> public V get(Object key) { Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return null; if (accessOrder) afterNodeAccess(e); return e.value; } ... void afterNodeAccess(Node<K,V> e) { // move node to last LinkedHashMap.Entry<K,V> last; if (accessOrder && (last = tail) != e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; p.after = null; if (b == null) head = a; else b.after = a; if (a != null) a.before = b; else last = b; if (last == null) head = p; else { p.before = last; last.after = p; } tail = p; ++modCount; } } </syntaxhighlight> === 枚举集与映射(EnumSet 与 EnumMap) === ==== EnumSet ==== <pre> EmimSet 是一个枚举类型元素集的高效实现。由于枚举类型只有有限个实例,所以EnumSet 内部用位序列实现。如果对应的值在集中,则相应的位被置为1。 </pre> * EnumSet 类没有公共的构造器。可以使用静态工厂方法构造这个集: *: <syntaxhighlight lang="java"> enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }; EnumSet<Weekday> always = EnumSet.allOf(Weekday.class); EnumSet<Weekday> never = EnumSet.noneOf(Weekday.class); EnumSet<Weekday> workday = EnumSet.range(Weekday.MONDAY, Weekday.FRIDAY); EnumSet<Weekday> mwf = EnumSet.of(Weekday.MONDAY, Weekday.WEDNESDAY, Weekday.FRIDAY); </syntaxhighlight> * 可以使用Set 接口的常用方法来修改EnumSet。 ==== EnumMap ==== EnumMap 是一个'''键类型为枚举类型的映射'''。它可以直接且高效地用一个值数组实现。 * 在使用时, 需要在构造器中指定键类型: *: <syntaxhighlight lang="java"> EnumMap<Weekday, Employee〉personlnCharge = new EnumMap<>(Weekday.class); </syntaxhighlight> * 所有的枚举类型都扩展于泛型Enum 类。 *: 例如,Weekday 扩展于 Enum<Weekday>。 === 标识散列映射(IdentityHashMap) === <pre> 类 IdentityHashMap 有特殊的作用。在这个类中, 键的散列值不是用 hashCode 函数计算的, 而是用 System.identityHashCode 方法计算的。这是Object.hashCode 方法根据对象的内存地址来计算散列码时所使用的方式。而且, 在对两个对象进行比较时,IdentityHashMap 类使用 ==, 而不使用 equals。 也就是说,不同的键对象,即使内容相同,也被视为是不同的对象。在实现对象遍历算法(如对象串行化)时,这个类非常有用,可以用来跟踪每个对象的遍历状况。 </pre> 特点: # 使用“'''System.identityHashCode'''”方法计算其 hashcode(即,使用对象内存地址计算 hashcode); # 使用“'''=='''”来比较对象; 即,每个对象 hashcode (几乎)唯一,(几乎)不会出现冲突。<br/> '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.WeakHashMap<K,V> 1.2 |- | style="width:50%;" | WeakHashMap( ) | style="width:50%;" rowspan="3" | 用给定的容量和填充因子构造一个空的散列映射表。 |- | style="width:50%;" | WeakHashMap(int initialCapacity) |- | style="width:50%;" | WeakHashMap(int initialCapacity, float loadFactor) |- ! colspan="2" style="text-align:left;"| java.util.LinkedHashSet<E> 1.4 |- | style="width:50%;" | LinkedHashSet( ) | style="width:50%;" rowspan="3" | 用给定的容量和填充因子构造一个空链接散列集。 |- | style="width:50%;" | LinkedHashSet(int initialCapacity) |- | style="width:50%;" | LinkedHashSet(int initialCapacity, float loadFactor) |- ! colspan="2" style="text-align:left;"| java.util.LinkedHashMap<K,V> 1.4 |- | style="width:50%;" | LinkedHashMap( ) | style="width:50%;" rowspan="4" | 用给定的容量、填充因子和顺序构造一个空的链接散列映射表。 * accessOrder 参数为 true 时表示访问顺序,为false 时表示插入顺序。 |- | style="width:50%;" | LinkedHashMap(int initialCapacity) |- | style="width:50%;" | LinkedHashMap(int initialCapacity, float loadFactor) |- | style="width:50%;" | LinkedHashMap(int initialCapacity, float loadFactor , boolean accessOrder) |- | style="width:50%;" | protected boolean removeEldestEntry(Map.Entry<K, V> eldest) | style="width:50%;" | 如果想删除 eldest 元素,并同时返回true ,就应该覆盖这个方法。 * eldest 参数是预期要删除的条目。这个方法将在条目添加到映射中之后调用。 * 其默认的实现将返回false。即在默认情况下,旧元素没有被删除。然而,可以重新定义这个方法,以便有选择地返回的 true。 *: 例如,如果最旧的条目符合一个条件,或者映射超过了一定大小,则返回 true 。 |- ! colspan="2" style="text-align:left;"| java.util.EnumSet<E extends Enum<E>> 5.0 |- | style="width:50%;" | static <E extends Enum<E > EnumSet<E> allOf(Class<E> enumType) | style="width:50%;" | 返回一个包含给定枚举类型的所有值的集。 |- | style="width:50%;" | static <E extends Enum<E > EnumSet<E> noneOf(Class<E> enumType) | style="width:50%;" | 返回一个空集,并有足够的空间保存给定的枚举类型所有的值。 |- | style="width:50%;" | static <E extends Enum<E > EnumSet<E> range(E from, E to) | style="width:50%;" | 返回一个包含 from ~ to 之间的所有值(包括两个边界元素)的集。 |- | style="width:50%;" | static <E extends Enum<E > EnumSet<E> of(E value) | style="width:50%;" rowspan="2" | 返回包括给定值的集。 |- | style="width:50%;" | static <E extends Enum<E > EnumSet<E> of(E value, E ... values) |- ! colspan="2" style="text-align:left;"| java.util.EnumMap<K extends Enum<K>, V> 5.0 |- | style="width:50%;" | EnumMap(Class<K> keyType) | style="width:50%;" | 构造一个键为给定类型的空映射。 |- ! colspan="2" style="text-align:left;"| java.util.IdentityHashMap<K, V> 1.4 |- | style="width:50%;" | IdentityHashMap() | style="width:50%;" rowspan="2" | 构造一个空的标识散列映射集,其容量是大于 1.5 * expectedMaxSize 的2 的最小次幕(expectedMaxSize 的默认值是 21)。 |- | style="width:50%;" | IdentityHashMap(int expectedMaxSize) |- ! colspan="2" style="text-align:left;"| java.lang.System 1.0 |- | style="width:50%;" | static int identityHashCode( Object obj) 1.1 | style="width:50%;" | 返回 Object.hashCode 计算出来的相同散列码(根据对象的内存地址产生),即使 obj 所属的类已经重新定义了 hashCode 方法也是如此。 |} == 视图与包装器 == <pre> 通过使用视图(views)可以获得其他的实现了Collection 接口和Map 接口的对象。 </pre> 以“HashMap<K,V>”为例: <syntaxhighlight lang="java"> public Set<K> keySet() { Set<K> ks = keySet; if (ks == null) { ks = new KeySet(); keySet = ks; } return ks; } final class KeySet extends AbstractSet<K> { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator<K> iterator() { return new KeyIterator(); } public final boolean contains(Object o) { return containsKey(o); } public final boolean remove(Object key) { return removeNode(hash(key), key, null, false, true) != null; } public final Spliterator<K> spliterator() { return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0); } public final void forEach(Consumer<? super K> action) { Node<K,V>[] tab; if (action == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Node<K,V> e = tab[i]; e != null; e = e.next) action.accept(e.key); } if (modCount != mc) throw new ConcurrentModificationException(); } } } </syntaxhighlight> “keySet()”方法返回了一个实现了“Set<K>”接口的类(“KeySet”)的对象,这个类(“KeySet”)的方法可以对原HashMap进行操作,这个集合(“KeySet”)就是视图,这个对象(“ks”)就是视图对象。<br/> '''视图可以理解为一个受限制的(非原集合的)集合。(类比于数据库视图)''' === 轻量级集合包装器 === 在 Arrays 类中有一个静态方法 —— asList 方法,这个方法作用是:将普通的 Java 数组包装成一个 List 集合。 : 例如: : <syntaxhighlight lang="java"> String[] strings = new String[10]; strings[0] = "pby"; strings[1] = "pby1"; strings[2] = "pby2"; List<String> stringList = Arrays.asList(strings); </syntaxhighlight> 返回的对象不是一个 ArrayList 对象。它就是一个视图对象: # 这个对象带有底层数组的 get 和 set 方法。 # 视图对象不能操作所有改变数组大小的方法: #: 在调用这些方法的时候,程序会抛出一个 UnsupportedOperationException 异常;但是普通的 List 对象能够正常的调用改变数组大小的方法。 与 Arrays.asList 方法类似的另一个方法那就是在 Collections 中的 nCopies 方法。例如: : <syntaxhighlight lang="java"> List<String> stringList = Collections.nCopies(100, "pby"); </syntaxhighlight> 上面的代码将创建一个包含 100 个 "pby" 字符串的 List 集合对象。'''这样的操作优势在于存储代价很小,因为这个对象不能修改大小'''。 * 区分 Collections 类和 Collection 接口:'''Collections 类包含了很多实用的方法,这些方法的参数和返回值都是集合'''; *:【如“'''synchronizedCollection(Collection<T> c)'''”可用于:用普通集合实现一个同步集合】; === 子范围 === 可以给很多的集合建立子范围视图。<br/> 例如,假设有一个集合对象list,要从中取出第10个~第19个元素,就可以使用subList方法来获得一个List集合对象的子范围视图: <syntaxhighlight lang="java"> List<String> list2 = list.subList(10, 19); </syntaxhighlight> * Java SE 6 引人的'''NavigableSet'''接口赋予子范围操作更多的控制能力。 === 不可修改的视图 === Collections还有几个方法,用于产生集合的不可修改视图。这些视图对现有的集合增加了一个运行时的检查。如果发现对集合进行修改的话(这里不仅仅是改变数组的大小,并且包括set之类的方法),就会抛出一个异常,同时这个集合将保持未修改的状态。<br/> 可以使用如下8种方法来获得不可修改的视图: # Collections.unmodifiableCollection # Collections.unmodifiableList # Collections.unmodifiableSet # Collections.unmodifiableSortedSet # Collections.unmodifiableNavigableSet # Collections.unmodifiableMap # Collections.unmodifiableSortedMap # Collections.unmodifiableNavigableMap 每个方法都定义于一个接口。例如,Collections.unmodifiableList方法定义于List接口,与ArrayList、LinkedList或者任何实现了List接口的其他类一起协同工作。 * 由于视图只是包装了接口而不是实际的集合对象, 所以只能访问接口中定义的方法。 <pre> unmodifiableCollection 方法(与本节稍后讨论的synchronizedCollection 和checkedCollection 方法一样)将返回一个集合, 它的equals 方法不调用底层集合的equals 方法。相反, 它继承了Object 类的equals 方法, 这个方法只是检测两个对象是否是同一个对象。如果将集或列表转换成集合, 就再也无法检测其内容是否相同了。视图就是以这种方式运行的, 因为内容是否相等的检测在分层结构的这一层上没有定义妥当。视图将以同样的方式处理hashCode 方法。 然而,unmodifiableSet 类和unmodifiableList 类却使用底层集合的equals 方法和hashCode 方法。 </pre> === 同步视图 === 类库的设计者使用视图机制来确保常规集合的线程安全, 而不是实现线程安全的集合类。 例如, Collections 类的静态'''synchronizedMap'''方法可以将任何一个映射表转换成具有同步访问方法的Map: : <syntaxhighlight lang="java"> Map<String, Employee> map = Collections.synchronizedMap(new HashMap<String, Employee>()); </syntaxhighlight> === 受查视图 === “受査”视图用来对泛型类型发生问题时提供调试支持。 例如,下面定义了一个安全列表“safeStrings”: : <syntaxhighlight lang="java"> List<String> safeStrings = Collections.checkedList(strings,String.class); ArrayList rawList = safeStrings; rawList.add(new Date());// checked list throws a ClassCastException </syntaxhighlight> : 视图的 add 方法将检测插人的对象是否属于给定的类。如果不属于给定的类, 就立即抛出一个“ClassCastException”。这样做的好处是错误可以在正确的位置得以报告: === 关于可选操作的说明 === 通常,视图有一些局限性,即可能只可以读、无法改变大小、只支持删除而不支持插人,这些与映射的键视图情况相同。如果试图进行不恰当的操作,受限制的视图就会抛出一个 '''UnsupportedOperationException'''。 在集合和选代器接口的API 文档中,许多方法描述为“可选操作” 。 '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Collections 1.2 |- | style="width:50%;" | static <E> Collection unmodifiableCollection(Collection<E> c) | style="width:50%;" rowspan="8" | 构造一个集合视图;视图的更改器方法抛出一个 UnsupportedOperationException。 |- | style="width:50%;" | static <E> List unmodifiableList(List<E> c) |- | style="width:50%;" | static <E> Set unmodifiableSet(Set<E> c) |- | style="width:50%;" | static <E> SortedSet unmodifiableSortedSet(SortedSet<E> c) |- | style="width:50%;" | static <E> SortedSet unmodifiableNavigableSet(NavigableSet<E> c) 8 |- | style="width:50%;" | static <K, V> Map unmodifiableMap(Map<K, V> c) |- | style="width:50%;" | static <K, V> SortedMap unmodifiableSortedMap(SortedMap<K, V> c) |- | style="width:50%;" | static <K, V> SortedMap unmodifiableNavigableMap(NavigableMap<K , V> c) 8 |- | style="width:50%;" | static <E> Collection<E> synchronizedCollection(Collection<E> c) | style="width:50%;" rowspan="8" | 构造一个集合视图;视图的方法同步。 |- | style="width:50%;" | static <E> List synchronizedlist(List<E> c) |- | style="width:50%;" | static <E> Set synchronizedSet(Set<E> c) |- | style="width:50%;" | static <E> SortedSet synchronizedSortedSet(SortedSet<E> c) |- | style="width:50%;" | static <E> NavigableSet synchronizedNavigableSet(NavigableSet<E> c) 8 |- | style="width:50%;" | static <K, V> Map<K, V> synchronizedMap(Map<K , V> c) |- | style="width:50%;" | static <K, V> SortedMap<K , V> synchronizedSortedMap(SortedMap<K, V> c) |- | style="width:50%;" | static <K, V> NavigableMap<K , V> synchronizedNavigableMap(NavigableMap<K, V> c) 8 |- | style="width:50%;" | static <E> Collection checkedCollection(Collection<E> c , Class<E> elementType) | style="width:50%;" rowspan="9" | 构造一个集合视图:如果插入一个错误类型的元素, 视图的方法抛出一个 ClassCastException。 |- | style="width:50%;" | static <E> List checkedlist(List<E> c, Class<E> elementType) |- | style="width:50%;" | static <E> Set checkedSet(Set<E> c, Class<E> e l ementType) |- | style="width:50%;" | static <E> SortedSet checkedSortedSet(SortedSet<E> c , Class <E> elementType) |- | style="width:50%;" | static <E> NavigableSet checkedNavigableSet(NavigableSet<E> c, Class<E> elementType) 8 |- | style="width:50%;" | static <K, V> Map checkedMap(Map<K, V> c, Class<K> keyType, Class<V> valueType) |- | style="width:50%;" | static <K, V> SortedMap checkedSortedMap(SortedMap<K, V> c ,Class<K> keyType, Class<V> valueType) |- | style="width:50%;" | static <K, V> NavigableMap checkedNavigableMap(NavigableMap<K , V> c, Class<K> keyType , Class<V> valueType) 8 |- | style="width:50%;" | static <E> Queue<E> checkedQueue(Queue<E> queue, Class<E> elementType) 8 |- | style="width:50%;" | static <E> List<E> nCopies(int n, E value) | style="width:50%;" rowspan="4" | 构造一个对象视图,可以是一个包含 n 个相同元素的不可修改列表, 也可以是一个单元素集、列表或映射。 |- | style="width:50%;" | static <E> Set<E> singleton(E value) |- | style="width:50%;" | static <E> List<E> singletonlist(E value) |- | style="width:50%;" | static <K, V >阿ap<K, V> singletonMap(K key, V value) |- | style="width:50%;" | static <E> List<E> emptylist() | style="width:50%;" rowspan="10" | 生成一个空集合、映射或迭代器。 |- | style="width:50%;" | static <T> Set<T> emptySet() |- | style="width:50%;" | static <E> SortedSet<E> emptySortedSet() |- | style="width:50%;" | static NavigableSet<E> emptyNavigableSet() |- | style="width:50%;" | static <K,V> Map<K, V> emptyMap() |- | style="width:50%;" | static <K , V> SortedMap<K, V> emptySortedMap() |- | style="width:50%;" | static <K,V> NavigableMap<K, V> emptyNavigableMap() |- | style="width:50%;" | static <T> Enumeration<T> emptyEnumeration() |- | style="width:50%;" | static <T> Iterator<T> emptyIterator() |- | style="width:50%;" | static <T> ListIterator<T> emptyListIterator() |- ! colspan="2" style="text-align:left;"| java.util.Arrays 1.2 |- | style="width:50%;" | static <E> List<E> aslist(E. .. array) | style="width:50%;" | 返回一个数组元素的列表视图。这个数组是可修改的,但其大小不可变。 |- ! colspan="2" style="text-align:left;"| java.util.List<E> 1.2 |- | style="width:50%;" | List<E> sublist(int firstIncluded, int firstExcluded) | style="width:50%;" | 返回给定位置范围内的所有元素的列表视图。 |- ! colspan="2" style="text-align:left;"| java.util.SortedSet<E> 1.2 |- | style="width:50%;" | SortedSet<E> subSet(E firstIncluded, E firstExcluded) | style="width:50%;" rowspan="3" | 返回给定范围内的元素视图。 |- | style="width:50%;" | SortedSet<E> headSet(E firstExcluded) |- | style="width:50%;" | SortedSet<E> tailSet(E firstIncluded) |- ! colspan="2" style="text-align:left;"| java.util.NavigableSet<E> 6 |- | style="width:50%;" | NavigableSet<E> subSet(E from, boolean fromIncluded, E to, boolean toIncluded) | style="width:50%;" rowspan="3" | 返回给定范围内的元素视图。boolean 标志决定视图是否包含边界。 |- | style="width:50%;" | NavigableSet<E> headSet(E to, boolean toIncluded) |- | style="width:50%;" | NavigableSet<E> tailSet(E from, boolean fromIncluded) |- | style="width:50%;" | SortedMap<K, V> subMap(K firstIncluded, K firstExcluded) | style="width:50%;" rowspan="3" | 返回在给定范围内的键条目的映射视图。 |- | style="width:50%;" | SortedMap<K, V> headMap(K firstExcluded) |- | style="width:50%;" | SortedMap<K, V> tailMap(K firstIncluded) |- | style="width:50%;" | NavigableMap<K, V> subMap(K from, boolean fromIncluded, K to, boolean toIncluded) | style="width:50%;" rowspan="3" | 返回在给定范围内的键条目的映射视图。boolean 标志决定视图是否包含边界。 |- | style="width:50%;" | NavigableMap<K, V> headMap(K from, boolean fromIncluded) |- | style="width:50%;" | NavigableMap<K, V> tailMap(K to, boolean toIncluded) |} == 算法 == 泛型集合接口有一个很大的优点, 即算法只需要实现一次。 === 排序与混排 === Collections 类中的sort 方法可以对实现了List 接口的集合进行排序。 # 这个方法假定列表元素实现了Comparable 接口。 # 如果想采用其他方式对列表进行排序,可以使用List接口的sort方法并传入一个Comparator 对象。 sort方法对列表所采用的排序手段:将所有元素转人一个数组,对数组进行排序,然后,再将排序后的序列复制回列表。【???】 [[常用排序算法]] Collections 类有一个算法shuffle, 其功能与排序刚好相反, 即随机地混排列表中元素的顺序。 '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Collections |- | style="width:50%;" | static <T extends Comparable<? super T>> void sort( List<T> elements ) | style="width:50%;" | 使用稳定的排序算法, 对列表中的元素进行排序。这个算法的时间复杂度是0(n logn), 其中n 为列表的长度。 |- | style="width:50%;" | static void shuffle( List<?> elements ) | style="width:50%;" rowspan="2" | 随机地打乱列表中的元素。这个算法的时间复杂度是0(n a(n)), n 是列表的长度,a(n)是访问元素的平均时间。 |- | style="width:50%;" | static void shuffle( List <?> elements , Random r ) |- ! colspan="2" style="text-align:left;"| java.util.List<E> |- | style="width:50%;" | default void sort(Comparator<? super T> comparator ) | style="width:50%;" | 使用给定比较器对列表排序。 |- ! colspan="2" style="text-align:left;"| java.util.Comparator<T> |- | style="width:50%;" | static <T extends Comparable<? super T>> Comparator<T> reverseOrder( ) | style="width:50%;" | 生成一个比较器, 将逆置 Comparable 接口提供的顺序。【?】 |- | style="width:50%;" | default Comparator<T> reversed( ) | style="width:50%;" | 生成一个比较器, 将逆置这个比较器提供的顺序。【?】 |} === 二分查找 === 使用二分查找,集合必须是已排好序的。 '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Collections |- | style="width:50%;" | static <T extends Comparable<? super T>> int binarySearch( List<T> elements , T key) | style="width:50%;" rowspan="2" | 从有序列表中搜索一个键, 如果元素扩展了 AbstractSequentialList 类, 则采用线性查找,否则将采用二分查找。 * 这个方法的时间复杂度为0 (a(n) logn), n 是列表的长度,a(n) 是访问一个元素的平均时间。 * 这个方法将返回这个键在列表中的索引, 如果在列表中不存在这个键将返回负值i。 在这种情况下,应该将这个键插人到列表索引一i—l的位置上,以保持列表的有序性。 |- | style="width:50%;" | static <T> int binarySearch(List<T> elements, T key, Conparator<? super T> c) |} === 简单算法 === 在 Collections 类中包含了几个简单且很有用的算法。 * 在 Java SE 8 增加了默认方法 Collection.removeIf 和 Collection.replaceAll,这两个方法需要提供 lambda 表达式来测试或转换元素。 *: 如: *: <syntaxhighlight lang="Java" highlight=""> // 删除所有长度小于3的短词 word.removeIf(w -> w.length() <= 3); // 把所有单词字母改为小写 word.replaceAll(String::toLowerCase); </syntaxhighlight> '''相关方法:''' {| class="wikitable mw-collapsible mw-collapsed" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Collections |- | style="width:50%;" | static <T extends Comparab1e<? super T>> T min(Collection<T> elements ) | style="width:50%;" rowspan="4" | 返回集合中最小的或最大的元素(为清楚起见, 参数的边界被简化了)。 |- | style="width:50%;" | static <T extends Comparable<? super T>> T max(Collection<T> elements ) |- | style="width:50%;" | static <T> min(Collection<T> elements, Comparator ? super T> c ) |- | style="width:50%;" | static <T> max (Collection<T> elements, Comparator ? super T> c ) |- | style="width:50%;" | static <T> void copy(List<? super T> to, List<T> from) | style="width:50%;" | 将原列表中的所有元素复制到目辱列表的相应位1上。目标列表的长度至少与原列表一样。 |- | style="width:50%;" | static <T> void fill(List<? super T> l, T value) | style="width:50%;" | 将列表中所有位置设置为相同的值。 |- | style="width:50%;" | static <T> boolean addAll(Collection<? super T> c, T . . . values ) 5.0 | style="width:50%;" | 将所有的值添加到集合中。如果集合改变了, 则返回tme。 |- | style="width:50%;" | static <T> boolean replaceAll(List<T> l, T oldValue, T newValue) 1.4 | style="width:50%;" | 用 newValue 取代所有值为oldValue 的元素。 |- | style="width:50%;" | static int indexOfSubList (List<?> l , List<?> s ) 1.4 | style="width:50%;" rowspan="2" | 返回 l 中第一个或最后一个等于 S 子列表的索引。 * 如果 l 中不存在等于S 的子列表, 则返回-1。 *: 例如, l 为[s,t,a,r] , s 为[t, a, r], 两个方法都将返回索引1。 |- | style="width:50%;" | static int lastIndexOfSubList (List<?> l , List<?> s ) 1.4 |- | style="width:50%;" | static void swap(List<?> l , int i, int j) 1.4 | style="width:50%;" | 交换给定偏移量的两个元素。 |- | style="width:50%;" | static void reverse(List<?> l) | style="width:50%;" | 逆置列表中元素的顺序。 : 例如, 逆置列表[t,a, r] 后将得到列表[r, a, t]。 * 这个方法的时间复杂度为O(n),n 为列表的长度。 |- | style="width:50%;" | static void rotate(List<?> l, int d) 1.4 | style="width:50%;" | 旋转列表中的元素, 将索引i 的条目移动到位置(i + d) % l.size()。 : 例如, 将列表[t, a, r] 旋转移2 个位置后得到[a, r,t]。 这个方法的时间复杂度为O(n) , n 为列表的长度。 |- | style="width:50%;" | static int frequency(Collection<?> c, Object o) 5.0 | style="width:50%;" | 返回 c 中与对象o 相同的元素个数。 |- | style="width:50%;" | boolean disjoint (Collection<?> cl, Collection<?> c2 ) 5.0 | style="width:50%;" | 如果两个集合没有共同的元素, 则返回true。 |- ! colspan="2" style="text-align:left;"| java.util.Collection<T> |- | style="width:50%;" | default boolean removeIf (Predicate<? super E> filter ) 8 | style="width:50%;" | 删除所有匹配的元素。 |- ! colspan="2" style="text-align:left;"| java.util.List<E> |- | style="width:50%;" | default void replaceAll(UnaryOperator<E> op) 8 | style="width:50%;" | 对这个列表的所有元素应用这个操作。 |} === 批操作 === 集合中的“removeAll()”、“retainAll()”、“addAll()”、“clear()”等方法。 === 集合与数组的转换 === ==== 数组 -> 集合 ==== 如果需要把一个数组转换为集合,'''Arrays.asList 包装器'''可以达到这个目的。例如: <syntaxhighlight lang="java" highlight="2"> String[] values = . . .; HashSet<String> staff = new HashSet<>(Arrays.asList(values)); </syntaxhighlight> ==== 集合 -> 数组 ==== 从集合得到数组会更困难一些。当然,可以使用toArray 方法: <syntaxhighlight lang="java"> Object[] values = staff.toArray(); </syntaxhighlight> * toArray 方法返回的数组是一个 Object[] 数组,不能改变它的类型。 *: <syntaxhighlight lang="java"> String[] values = (String[]) staff.toArray(); // Error! 不能使用强制类型转换! </syntaxhighlight> 实际上, 必须使用 toArray 方法的变体形式: # '''提供一个所需类型而且长度为 0 的数组'''。 #: <syntaxhighlight lang="java" highlight="1"> String[] values = staff.toArray(new String[0]); </syntaxhighlight> # 或'''构造一个指定大小的数组''': #: <syntaxhighlight lang="java" highlight="1"> String[] values = staff.toArray(new String[staff.size()]); </syntaxhighlight> 【???】 你可能奇怪为什么不能直接将一个 Class 对象(如String.class) 传递到 toArray 方法。 —— 原因是这个方法有“ 双重职责”,不仅要填充一个已有的数组(如果它足够长),还要创建一个新数组。 == 遗留的集合 == [[File:集合框架中的遗留类.png|600px]] === Hashtable === * 作用与 HashMap 一样,但继承自抽象类 Dictionary ,而实现了 Map 接口(HahsMap 继承自AbstractMap,实现了Map) *: <syntaxhighlight lang="java"> public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { // (Dictionary 类已过时,新的实现类应该实现Map接口) public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { </syntaxhighlight> * HashTable 的方法都是同步的(与Vector类似,方法使用'''Synchronized'''修饰) * 没有同步性要求应该使用 HashMap,而并发访问应该使用 '''ConcurrentHashMap''' *: Collections 类中存在一个静态方法:synchronizedMap(),同样可以创建一个线程安全的Map对象; *: ConcurrentHashMap 的实现更加精细,同步操作精确控制到桶 === 枚举(Enumeration)=== 遗留集合使用 Enumeration 接口对元素序列进行遍历。Enumeration 接口有两个方法,即 hasMoreElements 和 nextElement。这两个方法与 Iterator 接口的 hasNext 方法和 next 方法十分类似。(可以看作遗留集合的迭代器?) 例如,Hashtable 类的 elements 方法将产生一个用于描述表中各个枚举值的对象: : <syntaxhighlight lang="java"> Enumeration<Employee> e = staff.elements(); whi1e(e.hasMoreElements()) { Employee e = e.nextElement(); } </syntaxhighlight> 静态方法'''Collections.enumeration''' 将产生一个枚举对象,枚举集合中的元素。例如: : <syntaxhighlight lang="java"> List<InputStream> streams = . . .; SequenceInputStream in = new SequenceInputStream(Collections.enumeration(streams)) ; // the SequencelnputStream constructor expects an enumeration </syntaxhighlight> 传递集合要比传递迭代器更为明智。集合对象的用途更大。当接受方如果需要时,总是可以从集合中获得迭代器,而且,还可以随时地使用集合的所有方法。 '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Enumeration<E> |- | style="width:50%;" | boolean hasMoreElements( ) | style="width:50%;" | 如果还有更多的元素可以査看, 则返回true。 |- | style="width:50%;" | E nextElement( ) | style="width:50%;" | 返回被检测的下一个元素。 * 如果 hasMoreElements( ) 返回 false, 则不要调用这个方法。 |- ! colspan="2" style="text-align:left;"| java.util.HashTable<K, V> |- | style="width:50%;" | Enumeration<K> keys( ) | style="width:50%;" | 返回一个遍历散列表中键的枚举对象。 |- | style="width:50%;" | Enumeration<V> elements( ) | style="width:50%;" | 返回一个遍历散列表中元素的枚举对象。 |- ! colspan="2" style="text-align:left;"| java.util.Vector<E> |- | style="width:50%;" | Enumeration<E> elements( ) | style="width:50%;" | 返回遍历向量中元素的枚举对象。 |} === 属性映射(Properties)=== 属性映射(property map) 是一个类型非常特殊的映射结构。它有下面3 个特性: # 键与值都是字符串。 # 表可以保存到一个文件中, 也可以从文件中加载。 # 使用一个默认的辅助表。 实现属性映射的Java 平台类称为'''Properties'''。 * Properties 类使用 HashTable 实现: *:<syntaxhighlight lang="java"> public class Properties extends Hashtable<Object,Object> { </syntaxhighlight> '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Properties |- | style="width:50%;" | Properties() | style="width:50%;" | 创建一个空的属性映射。 |- | style="width:50%;" | Properties(Properties defaults) | style="width:50%;" | 创建一个带有一组默认值的空的属性映射。 |- | style="width:50%;" | String getProperty(String key) | style="width:50%;" | 获得属性的对应关系;返回与键对应的字符串。如果在映射中不存在,返回默认表中与这个键对应的字符串。 |- | style="width:50%;" | String getProperty(String key, String defaultValue) | style="width:50%;" | 获得在键没有找到时具有的默认值属性;它将返回与键对应的字符串,如果在映射中不存在,就返回默认的字符串。 |- | style="width:50%;" | void load(InputStream in) | style="width:50%;" | 从 InputStream 加载属性映射。 |- | style="width:50%;" | void store(OutputStream out, String commentstring) | style="width:50%;" | 把属性映射存储到 OutputStream。 |} === 栈(Stack)=== 从 1.0 版开始,标准类库中就包含了 Stack 类,其中有大家熟悉的 push 方法和 pop 方法。但是,'''Stack 类扩展自 Vector 类''',从理论角度看,Vector 类并不太令人满意,'''它可以让栈使用不属于栈操作的 insert 和 remove 方法''',即可以在任何地方进行插入或删除操作,而不仅仅是在栈顶。 '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.Stack<E> |- | style="width:50%;" | E push(E item) | style="width:50%;" | 将 item 压人桟并返回 item。 |- | style="width:50%;" | E pop() | style="width:50%;" | 弹出并返回栈顶的 item。 * 如果栈为空,请不要调用这个方法。 |- | style="width:50%;" | E peek() | style="width:50%;" | 返回栈顶元素,但不弹出。 * 如果栈为空,请不要调用这个方法。 |} === 位集(BitSet)=== <pre> Java 平台的BitSet 类用于存放一个位序列(它不是数学上的集, 称为位向量或位数组更为合适)。如果需要高效地存储位序列(例如,标志)就可以使用位集。由于位集将位包装在字节里, 所以,使用位集要比使用Boolean 对象的ArrayList 更加高效。 </pre> ==== “Eratosthenes 筛子” ==== <pre> 作为位集应用的一个示例,这里给出一个采用“ Eratosthenes 筛子” 算法查找素数的实现(素数是指只能被1 和本身整除的数, 例如2、3 或5,“ Eratosthenes 筛子” 算法是最早发现的用来枚举这些基本数字的方法之一)。 这并不是一种查找素数的最好方法, 但是由于某种原因,它已经成为测试编译程序性能的一种流行的基准。(这也不是一种最好的基准测试方法,它主要用于测试位操作。) 在此,将尊重这个传统,并给出实现。其程序将计算2 - 2 000 000 之间的所有素数(一共有148 933 个素数, 或许不打算把它们全部打印出来吧)。 这里并不想深人程序的细节, 关键是要遍历一个拥有200 万个位的位集。首先将所有的位置为“ 开” 状态,然后,将已知素数的倍数所对应的位都置为“ 关” 状态。经过这个操作保留下来的位对应的就是素数。 </pre> '''相关方法:''' {| class="wikitable" style="width:100%;" |- ! colspan="2" style="text-align:left;"| java.util.BitSet |- | style="width:50%;" | BitSet( int initialCapacity ) | style="width:50%;" | 创建一个位集。 |- | style="width:50%;" | int length( ) | style="width:50%;" | 返回位集的“ 逻辑长度”, 即1 加上位集的最高设置位的索引。 |- | style="width:50%;" | boolean get( int bit ) | style="width:50%;" | 获得一个位。 |- | style="width:50%;" | void set( int bit ) | style="width:50%;" | 设置一个位。 |- | style="width:50%;" | void clear ( int bit ) | style="width:50%;" | 清除一个位。 |- | style="width:50%;" | void and( BitSet set ) | style="width:50%;" | 这个位集与另一个位集进行逻辑“AND”。 |- | style="width:50%;" | void or( BitSet set ) | style="width:50%;" | 这个位集与另一个位集进行逻辑“OR”。 |- | style="width:50%;" | void xor( BitSet set ) | style="width:50%;" | 这个位集与另一个位集进行逻辑“X0R”。 |- | style="width:50%;" | void andNot( BitSet set ) | style="width:50%;" | 清除这个位集中对应另一个位集中设置的所有位。 |}
返回至“
核心技术:集合
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息