Pepole who make a greate contribution on common libaraies deserve our respect.
Component(Widget) / STL / Container(Collection)
- 合成不会强迫我们的程序设计进入继承的分级结构中has-a relationship。同时,合成显得更加灵活,因为可以动态选择一种类型(以及行为),而继承要求在编译期间准确地知道一种类型。
- Java的工具(实用程序)库提供了一些“集合类”(亦称作“容器类”,但该术语已由AWT使用,所以这里仍采用“集合”这一称呼)。利用这些集合类,我们可以容纳乃至操纵自己的对象。Aggregate; container;
- 有两方面的问题将数组与其他集合类型区分开来:效率efficiency 和类型type。
- 对于Java来说,为保存和访问一系列对象(实际是对象的句柄 handle, or pointer in C++)数组,最有效的方法莫过于数组。数组实际代表一个简单的线性序列,它使得元素的访问速度非常快,但我们却要为这种速度付出代价:创建一个数组对象时,它的大小是固定的,而且不可在那个数组对象的“存在时间”内发生改变。可创建特定大小的一个数组,然后假如用光了存储空间,就再创建一个新数组,将所有句柄从旧数组移到新数组。这属于“矢量”(Vector)类的行为.
- 在Java中,由于对数组和集合都要进行范围检查,所以对性能有一定的影响。
- 这些类都涉及对对象的处理——好象它们没有特定的类型。换言之,它们将其当作Object类型处理(Object类型是Java中所有类的“根”类)。从某个角度看,这种处理方法是非常合理的:我们仅需构建一个集合,然后任何Java对象都可以进入那个集合(除基本数据类型外built-in type——可用Java的基本类型封装类将其作为常数置入集合,或者将其封装到自己的类内,作为可以变化的值使用)。这再一次反映了数组优于常规集合:创建一个数组时,可令其容纳一种特定的类型。这意味着可进行编译期类型检查,预防自己设置了错误的类型,或者错误指定了准备提取的类型。
- 无论使用的数组属于什么类型,数组标识符实际都是指向真实对象的一个句柄。那些对象本身是在内存“堆”里创建的。堆对象既可“隐式”创建(即默认产生),亦可“显式”创建(即明确指定,用一个new表达式)。堆对象的一部分(实际是我们能访问的唯一字段或方法)是只读的length(长度)成员,它告诉我们那个数组对象里最多能容纳多少元素。
- 集合类只能容纳对象句柄。但对一个数组,却既可令其直接容纳基本类型的数据,亦可容纳指向对象的句柄。利用象Integer、Double之类的“封装器”类,可将基本数据类型的值置入一个集合里。
- 象C和C++这样的语言会使问题复杂化,因为我们不能返回一个数组,只能返回指向数组的一个指针。这样就非常麻烦,因为很难控制数组的“存在时间”,它很容易造成内存“漏洞”的出现。Java采用的是类似的方法,但我们能“返回一个数组”。当然,此时返回的实际仍是指向数组的指针。但在Java里,我们永远不必担心那个数组的是否可用——只要需要,它就会自动存在。而且垃圾收集器会在我们完成后自动将其清除。
- 为容纳一组对象,最适宜的选择应当是数组。而且假如容纳的是一系列基本数据类型,更是必须采用数组。Have to use array when containing built-in type.
- 当我们编写程序时,通常并不能确切地知道最终需要多少个对象。有些时候甚至想用更复杂的方式来保存对象。为解决这个问题,Java提供了四种类型的“集合类”:Vector(矢量)、BitSet(位集)、Stack(堆栈)以及Hashtable(散列表)。
- 使用Java集合的“缺点”是在将对象置入一个集合时丢失了类型信息。之所以会发生这种情况,是由于当初编写集合时,那个集合的程序员根本不知道用户到底想把什么类型置入集合。若指示某个集合只允许特定的类型,会妨碍它成为一个“常规用途”的工具,为用户带来麻烦。为解决这个问题,集合实际容纳的是类型为Object的一些对象的句柄。这种类型当然代表Java中的所有对象,因为它是所有类的根。当然,也要注意这并不包括基本数据类型,因为它们并不是从“任何东西”继承来的。(It is solved with template in C++)这是一个很好的方案,只是不适用下述场合:
- (1) 将一个对象句柄置入集合时,由于类型信息会被抛弃,所以任何类型的对象都可进入我们的集合——即便特别指示它只能容纳特定类型的对象。举个例子来说,虽然指示它只能容纳猫,但事实上任何人都可以把一条狗扔进来。
- (2) 由于类型信息不复存在,所以集合能肯定的唯一事情就是自己容纳的是指向一个对象的句柄。正式使用它之前,必须对其进行造型,使其具有正确的类型。
- 参数化类型 parameterization type这类问题并不是孤立的——我们许多时候都要在其他类型的基础上创建新类型。此时,在编译期间拥有特定的类型信息是非常有帮助的。这便是“参数化类型”的概念。在C++中,它由语言通过“模板Template” 获得了直接支持。至少,Java保留了关键字generic,期望有一天能够支持参数化类型。但我们现在无法确定这一天何时会来临。
- 可利用“反复器”(Iterator)的概念达到这个目的。它可以是一个对象,作用是遍历一系列对象,并选择那个序列中的每个对象,同时不让客户程序员知道或关注那个序列的基础结构。此外,我们通常认为反复器是一种“轻量级”对象;也就是说,创建它只需付出极少的代价。但也正是由于这个原因,我们常发现反复器存在一些似乎很奇怪的限制。例如,有些反复器只能朝一个方向移动。Java的Enumeration(枚举,注释②)便是具有这些限制的一个反复器的例子。除下面这些外,不可再用它做其他任何事情:
- (1) 用一个名为elements()的方法要求集合为我们提供一个Enumeration。我们首次调用它的nextElement()时 The de facto meaning is to move to next element and return the current element,这个Enumeration会返回序列中的第一个元素。
- (2) 用nextElement()获得下一个对象。
- (3) 用hasMoreElements()检查序列中是否还有更多的对象。
- ②:“反复器”这个词在C++和OOP的其他地方是经常出现的,所以很难确定为什么Java的开发者采用了这样一个奇怪的名字。Java 1.2的集合库修正了这个问题以及其他许多问题。
- BitSet实际是由“二进制位”构成的一个Vector。如果希望高效率地保存大量“开-关”信息,就应使用BitSet。它只有从尺寸的角度看才有意义;如果希望的高效率的访问,那么它的速度会比使用一些固有类型的数组慢一些。此外,BitSet的最小长度是一个长整数(Long)的长度:64位。这意味着假如我们准备保存比这更小的数据,如8位数据,那么BitSet就显得浪费了。所以最好创建自己的类,用它容纳自己的标志位。
- Stack有时也可以称为“后入先出”(LIFO)集合。换言之,我们在堆栈里最后“压入”的东西将是以后第一个“弹出”的。和其他所有Java集合一样,我们压入和弹出的都是“对象”,所以必须对自己弹出的东西进行“造型”。一种很少见的做法是拒绝使用Vector作为一个Stack的基本构成元素,而是从Vector里“继承”一个Stack。这样一来,它就拥有了一个Vector的所有特征及行为,另外加上一些额外的Stack行为。很难判断出设计者到底是明确想这样做,还是属于一种固有的设计。
- 这种“从一系列对象中选择”的概念亦可叫作一个“映射 map”、“字典 dictionary”或者“关联数组 relation array”。从概念上讲,它看起来象一个Vector,但却不是通过数字来查找对象,而是用另一个对象来查找它们!这通常都属于一个程序中的重要进程。
- 这个概念具体反映到抽象类Dictionary身上。该类的接口是非常直观的size()告诉我们其中包含了多少元素;isEmpty()判断是否包含了元素(是则为true);put(Object key, Object value)添加一个值(我们希望的东西),并将其同一个键关联起来(想用于搜索它的东西);get(Object key)获得与某个键对应的值;而remove(Object Key)用于从列表中删除“键-值”对。还可以使用枚举技术:keys()产生对键的一个枚举(Enumeration);而elements()产生对所有值的一个枚举。这便是一个Dictionary(字典)的全部。
- 散列码可以获取对象中的信息,然后将其转换成那个对象“相对唯一”的整数(int)。所有对象都有一个散列码,而hashCode()是根类Object的一个方法。Hashtable获取对象的hashCode(),然后用它快速查找键。这样可使性能得到大幅度提升(④)。
- 大家或许认为此时要做的全部事情就是正确地覆盖hashCode()。但这样做依然行不能,除非再做另一件事情:覆盖也属于Object一部分的equals()。当散列表试图判断我们的键是否等于表内的某个键时,就会用到这个方法。同样地,默认的Object.equals()只是简单地比较对象地址,了在散列表中将自己的类作为键使用,必须同时覆盖override hashCode() 和equals() befor objectize
- 调用了一个名为getProperties()的static方法,用于获得一个特殊的Properties对象,对系统的某些特征进行描述。list()属于Properties的一个方法,可将内容发给我们选择的任何流式输出。也有一个save()方法,可用它将属性列表写入一个文件,以便日后用load()方法读取。尽管Properties类是从Hashtable继承的,但它也包含了一个散列表,用于容纳“默认”属性的列表。所以假如没有在主列表里找到一个属性,就会自动搜索默认属性。
- JGL实现了许多功能,可满足对一个集合库的大多数常规需求,它与C++的模板机制非常相似。JGL包括相互链接起来的列表、设置、队列、映射、堆栈、序列以及反复器,它们的功能比Enumeration(枚举)强多了。同时提供了一套完整的算法,如检索和排序等。
- JGL已包括到一些厂商发行的Java套件中,而且ObjectSpace公司自己也允许所有用户免费使用JGL,包括商业性的使用。详细情况和软件下载可访问http://www.ObjectSpace.com。与JGL配套提供的联机文档做得非常好,可作为自己的一个绝佳起点使用。
- 我感觉特别好的一个是用“反复器”(Inerator)代替了“枚举”(Enumeration)。
- 此次重新设计也加强了集合库的功能。现在新增的行为包括链接列表、队列以及撤消组队(即“双终点队列”)。集合库的设计是相当困难的(会遇到大量库设计问题)。在C++中,STL用多个不同的类来覆盖基础。这种做法比起STL以前是个很大的进步,那时根本没做这方面的考虑。但仍然没有很好地转换到Java里面。结果就是一大堆特别容易混淆的类。在另一个极端,我曾发现一个集合库由单个类构成:colleciton,它同时作为Vector和Hashtable使用。新集合库的设计者则希望达到一种新的平衡:实现人们希望从一个成熟集合库上获得的完整功能,同时又要比STL和其他类似的集合库更易学习和使用。这样得到的结果在某些场合显得有些古怪。但和早期Java库的一些决策不同,这些古怪之处并非偶然出现的,而是以复杂性作为代价,在进行仔细权衡之后得到的结果。这样做也许会延长人们掌握一些库概念的时间,但很快就会发现自己很乐于使用那些新工具,而且变得越来越离不了它。
- 新的集合库考虑到了“容纳自己对象”的问题,并将其分割成两个明确的概念:
- (1) 集合(Collection):一组单独的元素,通常应用了某种规则。在这里,一个List(列表)必须按特定的顺序容纳元素,而一个Set(集)不可包含任何重复的元素。相反,“包”(Bag)的概念未在新的集合库中实现,因为“列表”已提供了类似的功能。
- (2) 映射(Map):一系列“键-值”对(这已在散列表身上得到了充分的体现)。从表面看,这似乎应该成为一个“键-值”对的“集合”,但假若试图按那种方式实现它,就会发现实现过程相当笨拙。这进一步证明了应该分离成单独的概念。另一方面,可以方便地查看Map的某个部分。只需创建一个集合,然后用它表示那一部分即可。这样一来,Map就可以返回自己键的一个Set、一个包含自己值的List或者包含自己“键-值”对的一个List。
- 利用iterator()方法,所有集合都能生成一个“反复器”(Iterator)。反复器其实就象一个“枚举”(Enumeration),是后者的一个替代物,只是:
- (1) 它采用了一个历史上默认、而且早在OOP中得到广泛采纳的名字(反复器)。
- (2) 采用了比Enumeration更短的名字:hasNext()代替了hasMoreElement(),而next()代替了nextElement()。
- (3) 添加了一个名为remove()的新方法,可删除由Iterator生成的上一个元素。所以每次调用next()的时候,只需调用remove()一次。在SimpleCollection.java中,大家可看到创建了一个反复器,并用它在集合里遍历,打印出每个元素。
- 用一个集合能做的所有事情(亦可对Set和List做同样的事情,尽管List还提供了一些额外的功能)。Map不是从Collection继承的,所以要单独对待
- Set拥有与Collection完全相同的接口,所以和两种不同的List不同,它没有什么额外的功能。相反,Set完全就是一个Collection,只是具有不同的行为(这是实例和多形性最理想的应用:用于表达不同的行为)。在这里,一个Set只允许每个对象存在一个实例(正如大家以后会看到的那样,一个对象的“值”的构成是相当复杂的)。
- Set(接口) 添加到Set的每个元素都必须是独一无二的;否则Set就不会添加重复的元素。添加到Set里的对象必须定义equals(),从而建立对象的唯一性。Set拥有与Collection完全相同的接口。一个Set不能保证自己可按任何特定的顺序维持自己的元素
- HashSet* 用于除非常小的以外的所有Set。对象也必须定义hashCode()
- ArraySet 由一个数组后推得到的Set。面向非常小的Set设计,特别是那些需要频繁创建和删除的。对于小Set,与HashSet相比,ArraySet创建和反复所需付出的代价都要小得多。但随着Set的增大,它的性能也会大打折扣。不需要HashCode()
- TreeSet 由一个“红黑树”后推得到的顺序Set(注释⑦)。这样一来,我们就可以从一个Set里提到一个顺序集合
- Map(接口) 维持“键-值”对应关系(对),以便通过一个键查找相应的值
- HashMap* 基于一个散列表实现(用它代替Hashtable)。针对“键-值”对的插入和检索,这种形式具有最稳定的性能。可通过构建器对这一性能进行调整,以便设置散列表的“能力”和“装载因子”ArrayMap 由一个ArrayList后推得到的Map。对反复的顺序提供了精确的控制。面向非常小的Map设计,特别是那些需要经常创建和删除的。对于非常小的Map,创建和反复所付出的代价要比HashMap低得多。但在Map变大以后,性能也会相应地大幅度降低TreeMap 在一个“红-黑”树的基础上实现。
- 可在ArraySet以及HashSet间作出选择,具体取决于Set的大小(如果需要从一个Set中获得一个顺序列表,请用TreeSet;注释⑧)
- 选择不同的Map实施方案时,注意Map的大小对于性能的影响是最大的.
- Arrays类为所有基本数据类型的数组提供了一个过载的sort()和binarySearch(),它们亦可用于String和Object。
- 可用与数组相同的形式排序和搜索一个列表(List)。用于排序和搜索列表的静态方法包含在类Collections中,但它们拥有与Arrays中差不多的签名:sort(List)用于对一个实现了Comparable的对象列表进行排序;binarySearch(List,Object)用于查找列表中的某个对象;sort(List,Comparator)利用一个“比较器”对一个列表进行排序;而binarySearch(List,Object,Comparator)则用于查找那个列表中的一个对象(注释⑨)。
- Synchronized关键字是“多线程”机制一个非常重要的部分。
- 数组包含了对象的数字化索引。它容纳的是一种已知类型的对象,所以在查找一个对象时,不必对结果进行造型处理。数组可以是多维的,而且能够容纳基本数据类型。但是,一旦把它创建好以后,大小便不能变化了。
- Vector(矢量)也包含了对象的数字索引——可将数组和Vector想象成随机访问集合。当我们加入更多的元素时,Vector能够自动改变自身的大小。但Vector只能容纳对象的句柄,所以它不可包含基本数据类型;而且将一个对象句柄从集合中取出来的时候,必须对结果进行造型处理。
- Hashtable(散列表)属于Dictionary(字典)的一种类型,是一种将对象(而不是数字)同其他对象关联到一起的方式。散列表也支持对对象的随机访问,事实上,它的整个设计方案都在突出访问的“高速度”。
- Stack(堆栈)是一种“后入先出”(LIFO)的队列.
• Collection Interfaces - Represent different types of collections, such as sets, lists and maps. These interfaces form the basis of the framework.
• General-purpose Implementations - Primary implementations of the collection interfaces.
• Legacy Implementations
- The collection classes from earlier releases, Vector and Hashtable,
have been retrofitted to implement the collection interfaces.
• Special-purpose Implementations
- Implementations designed for use in special situations. These
implementations display nonstandard performance characteristics, usage
restrictions, or behavior.
• Concurrent Implementations - Implementations designed for highly concurrent use.
• Wrapper Implementations - Add functionality, such as synchronization, to other implementations.
• Convenience Implementations - High-performance "mini-implementations" of the collection interfaces.
• Abstract Implementations - Partial implementations of the collection interfaces to facilitate custom implementations.
• Algorithms - Static methods that perform useful functions on collections, such as sorting a list.
• Infrastructure - Interfaces that provide essential support for the collection interfaces.
• Array Utilities
- Utility functions for arrays of primitives and reference objects.
Not, strictly speaking, a part of the Collections Framework, this
functionality was added to the Java platform at the same time and relies
on some of the same infrastructure.
Iterable Interface

1 import java.util.Iterator; 2 /** 3 * Instances of classes that implement this interface can be used with 4 * the enhanced for loop. 5 * 6 * @since 1.5 7 */ 8 public interface Iterable<T> { 9 10 /** 11 * Returns an {@link Iterator} for the elements in this object. 12 * 13 * @return An {@code Iterator} instance. 14 */ 15 Iterator<T> iterator(); 16 }
Collection Interface

1 package java.util; 2 3 4 /** 5 * {@code Collection} is the root of the collection hierarchy. It defines operations on 6 * data collections and the behavior that they will have in all implementations 7 * of {@code Collection}s. 8 * 9 * All direct or indirect implementations of {@code Collection} should implement at 10 * least two constructors. One with no parameters which creates an empty 11 * collection and one with a parameter of type {@code Collection}. This second 12 * constructor can be used to create a collection of different type as the 13 * initial collection but with the same elements. Implementations of {@code Collection} 14 * cannot be forced to implement these two constructors but at least all 15 * implementations under {@code java.util} do. 16 * 17 * Methods that change the content of a collection throw an 18 * {@code UnsupportedOperationException} if the underlying collection does not 19 * support that operation, though it's not mandatory to throw such an {@code Exception} 20 * in cases where the requested operation would not change the collection. In 21 * these cases it's up to the implementation whether it throws an 22 * {@code UnsupportedOperationException} or not. 23 * 24 * Methods marked with (optional) can throw an 25 * {@code UnsupportedOperationException} if the underlying collection doesn't 26 * support that method. 27 */ 28 public interface Collection<E> extends Iterable<E> { 29 30 /** 31 * Attempts to add {@code object} to the contents of this 32 * {@code Collection} (optional). 33 * 34 * After this method finishes successfully it is guaranteed that the object 35 * is contained in the collection. 36 * 37 * If the collection was modified it returns {@code true}, {@code false} if 38 * no changes were made. 39 * 40 * An implementation of {@code Collection} may narrow the set of accepted 41 * objects, but it has to specify this in the documentation. If the object 42 * to be added does not meet this restriction, then an 43 * {@code IllegalArgumentException} is thrown. 44 * 45 * If a collection does not yet contain an object that is to be added and 46 * adding the object fails, this method <i>must</i> throw an appropriate 47 * unchecked Exception. Returning false is not permitted in this case 48 * because it would violate the postcondition that the element will be part 49 * of the collection after this method finishes. 50 * 51 * @param object 52 * the object to add. 53 * @return {@code true} if this {@code Collection} is 54 * modified, {@code false} otherwise. 55 * 56 * @throws UnsupportedOperationException 57 * if adding to this {@code Collection} is not supported. 58 * @throws ClassCastException 59 * if the class of the object is inappropriate for this 60 * collection. 61 * @throws IllegalArgumentException 62 * if the object cannot be added to this {@code Collection}. 63 * @throws NullPointerException 64 * if null elements cannot be added to the {@code Collection}. 65 */ 66 public boolean add(E object); 67 68 /** 69 * Attempts to add all of the objects contained in {@code Collection} 70 * to the contents of this {@code Collection} (optional). If the passed {@code Collection} 71 * is changed during the process of adding elements to this {@code Collection}, the 72 * behavior is not defined. 73 * 74 * @param collection 75 * the {@code Collection} of objects. 76 * @return {@code true} if this {@code Collection} is modified, {@code false} 77 * otherwise. 78 * @throws UnsupportedOperationException 79 * if adding to this {@code Collection} is not supported. 80 * @throws ClassCastException 81 * if the class of an object is inappropriate for this 82 * {@code Collection}. 83 * @throws IllegalArgumentException 84 * if an object cannot be added to this {@code Collection}. 85 * @throws NullPointerException 86 * if {@code collection} is {@code null}, or if it 87 * contains {@code null} elements and this {@code Collection} does 88 * not support such elements. 89 */ 90 public boolean addAll(Collection<? extends E> collection); 91 92 /** 93 * Removes all elements from this {@code Collection}, leaving it empty (optional). 94 * 95 * @throws UnsupportedOperationException 96 * if removing from this {@code Collection} is not supported. 97 * 98 * @see #isEmpty 99 * @see #size 100 */ 101 public void clear(); 102 103 /** 104 * Tests whether this {@code Collection} contains the specified object. Returns 105 * {@code true} if and only if at least one element {@code elem} in this 106 * {@code Collection} meets following requirement: 107 * {@code (object==null ? elem==null : object.equals(elem))}. 108 * 109 * @param object 110 * the object to search for. 111 * @return {@code true} if object is an element of this {@code Collection}, 112 * {@code false} otherwise. 113 * @throws ClassCastException 114 * if the object to look for isn't of the correct 115 * type. 116 * @throws NullPointerException 117 * if the object to look for is {@code null} and this 118 * {@code Collection} doesn't support {@code null} elements. 119 */ 120 public boolean contains(Object object); 121 122 /** 123 * Tests whether this {@code Collection} contains all objects contained in the 124 * specified {@code Collection}. If an element {@code elem} is contained several 125 * times in the specified {@code Collection}, the method returns {@code true} even 126 * if {@code elem} is contained only once in this {@code Collection}. 127 * 128 * @param collection 129 * the collection of objects. 130 * @return {@code true} if all objects in the specified {@code Collection} are 131 * elements of this {@code Collection}, {@code false} otherwise. 132 * @throws ClassCastException 133 * if one or more elements of {@code collection} isn't of the 134 * correct type. 135 * @throws NullPointerException 136 * if {@code collection} contains at least one {@code null} 137 * element and this {@code Collection} doesn't support {@code null} 138 * elements. 139 * @throws NullPointerException 140 * if {@code collection} is {@code null}. 141 */ 142 public boolean containsAll(Collection<?> collection); 143 144 /** 145 * Compares the argument to the receiver, and returns true if they represent 146 * the <em>same</em> object using a class specific comparison. 147 * 148 * @param object 149 * the object to compare with this object. 150 * @return {@code true} if the object is the same as this object and 151 * {@code false} if it is different from this object. 152 * @see #hashCode 153 */ 154 public boolean equals(Object object); 155 156 /** 157 * Returns an integer hash code for the receiver. Objects which are equal 158 * return the same value for this method. 159 * 160 * @return the receiver's hash. 161 * 162 * @see #equals 163 */ 164 public int hashCode(); 165 166 /** 167 * Returns if this {@code Collection} contains no elements. 168 * 169 * @return {@code true} if this {@code Collection} has no elements, {@code false} 170 * otherwise. 171 * 172 * @see #size 173 */ 174 public boolean isEmpty(); 175 176 /** 177 * Returns an instance of {@link Iterator} that may be used to access the 178 * objects contained by this {@code Collection}. The order in which the elements are 179 * returned by the iterator is not defined. Only if the instance of the 180 * {@code Collection} has a defined order the elements are returned in that order. 181 * 182 * @return an iterator for accessing the {@code Collection} contents. 183 */ 184 public Iterator<E> iterator(); 185 186 /** 187 * Removes one instance of the specified object from this {@code Collection} if one 188 * is contained (optional). The element {@code elem} that is removed 189 * complies with {@code (object==null ? elem==null : object.equals(elem)}. 190 * 191 * @param object 192 * the object to remove. 193 * @return {@code true} if this {@code Collection} is modified, {@code false} 194 * otherwise. 195 * @throws UnsupportedOperationException 196 * if removing from this {@code Collection} is not supported. 197 * @throws ClassCastException 198 * if the object passed is not of the correct type. 199 * @throws NullPointerException 200 * if {@code object} is {@code null} and this {@code Collection} 201 * doesn't support {@code null} elements. 202 */ 203 public boolean remove(Object object); 204 205 /** 206 * Removes all occurrences in this {@code Collection} of each object in the 207 * specified {@code Collection} (optional). After this method returns none of the 208 * elements in the passed {@code Collection} can be found in this {@code Collection} 209 * anymore. 210 * 211 * @param collection 212 * the collection of objects to remove. 213 * @return {@code true} if this {@code Collection} is modified, {@code false} 214 * otherwise. 215 * 216 * @throws UnsupportedOperationException 217 * if removing from this {@code Collection} is not supported. 218 * @throws ClassCastException 219 * if one or more elements of {@code collection} 220 * isn't of the correct type. 221 * @throws NullPointerException 222 * if {@code collection} contains at least one 223 * {@code null} element and this {@code Collection} doesn't support 224 * {@code null} elements. 225 * @throws NullPointerException 226 * if {@code collection} is {@code null}. 227 */ 228 public boolean removeAll(Collection<?> collection); 229 230 /** 231 * Removes all objects from this {@code Collection} that are not also found in the 232 * {@code Collection} passed (optional). After this method returns this {@code Collection} 233 * will only contain elements that also can be found in the {@code Collection} 234 * passed to this method. 235 * 236 * @param collection 237 * the collection of objects to retain. 238 * @return {@code true} if this {@code Collection} is modified, {@code false} 239 * otherwise. 240 * @throws UnsupportedOperationException 241 * if removing from this {@code Collection} is not supported. 242 * @throws ClassCastException 243 * if one or more elements of {@code collection} 244 * isn't of the correct type. 245 * @throws NullPointerException 246 * if {@code collection} contains at least one 247 * {@code null} element and this {@code Collection} doesn't support 248 * {@code null} elements. 249 * @throws NullPointerException 250 * if {@code collection} is {@code null}. 251 */ 252 public boolean retainAll(Collection<?> collection); 253 254 /** 255 * Returns a count of how many objects this {@code Collection} contains. 256 * 257 * @return how many objects this {@code Collection} contains, or Integer.MAX_VALUE 258 * if there are more than Integer.MAX_VALUE elements in this 259 * {@code Collection}. 260 */ 261 public int size(); 262 263 /** 264 * Returns a new array containing all elements contained in this {@code Collection}. 265 * 266 * If the implementation has ordered elements it will return the element 267 * array in the same order as an iterator would return them. 268 * 269 * The array returned does not reflect any changes of the {@code Collection}. A new 270 * array is created even if the underlying data structure is already an 271 * array. 272 * 273 * @return an array of the elements from this {@code Collection}. 274 */ 275 public Object[] toArray(); 276 277 /** 278 * Returns an array containing all elements contained in this {@code Collection}. If 279 * the specified array is large enough to hold the elements, the specified 280 * array is used, otherwise an array of the same type is created. If the 281 * specified array is used and is larger than this {@code Collection}, the array 282 * element following the {@code Collection} elements is set to null. 283 * 284 * If the implementation has ordered elements it will return the element 285 * array in the same order as an iterator would return them. 286 * 287 * {@code toArray(new Object[0])} behaves exactly the same way as 288 * {@code toArray()} does. 289 * 290 * @param array 291 * the array. 292 * @return an array of the elements from this {@code Collection}. 293 * 294 * @throws ArrayStoreException 295 * if the type of an element in this {@code Collection} cannot be 296 * stored in the type of the specified array. 297 */ 298 public <T> T[] toArray(T[] array); 299 }
List Interface

1 package java.util; 2 3 4 /** 5 * A {@code List} is a collection which maintains an ordering for its elements. Every 6 * element in the {@code List} has an index. Each element can thus be accessed by its 7 * index, with the first index being zero. Normally, {@code List}s allow duplicate 8 * elements, as compared to Sets, where elements have to be unique. 9 */ 10 public interface List<E> extends Collection<E> { 11 /** 12 * Inserts the specified object into this {@code List} at the specified location. 13 * The object is inserted before the current element at the specified 14 * location. If the location is equal to the size of this {@code List}, the object 15 * is added at the end. If the location is smaller than the size of this 16 * {@code List}, then all elements beyond the specified location are moved by one 17 * position towards the end of the {@code List}. 18 * 19 * @param location 20 * the index at which to insert. 21 * @param object 22 * the object to add. 23 * @throws UnsupportedOperationException 24 * if adding to this {@code List} is not supported. 25 * @throws ClassCastException 26 * if the class of the object is inappropriate for this 27 * {@code List}. 28 * @throws IllegalArgumentException 29 * if the object cannot be added to this {@code List}. 30 * @throws IndexOutOfBoundsException 31 * if {@code location < 0 || location > size()} 32 */ 33 public void add(int location, E object); 34 35 /** 36 * Adds the specified object at the end of this {@code List}. 37 * 38 * @param object 39 * the object to add. 40 * @return always true. 41 * @throws UnsupportedOperationException 42 * if adding to this {@code List} is not supported. 43 * @throws ClassCastException 44 * if the class of the object is inappropriate for this 45 * {@code List}. 46 * @throws IllegalArgumentException 47 * if the object cannot be added to this {@code List}. 48 */ 49 public boolean add(E object); 50 51 /** 52 * Inserts the objects in the specified collection at the specified location 53 * in this {@code List}. The objects are added in the order they are returned from 54 * the collection's iterator. 55 * 56 * @param location 57 * the index at which to insert. 58 * @param collection 59 * the collection of objects to be inserted. 60 * @return true if this {@code List} has been modified through the insertion, false 61 * otherwise (i.e. if the passed collection was empty). 62 * @throws UnsupportedOperationException 63 * if adding to this {@code List} is not supported. 64 * @throws ClassCastException 65 * if the class of an object is inappropriate for this 66 * {@code List}. 67 * @throws IllegalArgumentException 68 * if an object cannot be added to this {@code List}. 69 * @throws IndexOutOfBoundsException 70 * if {@code location < 0 || > size()} 71 */ 72 public boolean addAll(int location, Collection<? extends E> collection); 73 74 /** 75 * Adds the objects in the specified collection to the end of this {@code List}. The 76 * objects are added in the order in which they are returned from the 77 * collection's iterator. 78 * 79 * @param collection 80 * the collection of objects. 81 * @return {@code true} if this {@code List} is modified, {@code false} otherwise 82 * (i.e. if the passed collection was empty). 83 * @throws UnsupportedOperationException 84 * if adding to this {@code List} is not supported. 85 * @throws ClassCastException 86 * if the class of an object is inappropriate for this 87 * {@code List}. 88 * @throws IllegalArgumentException 89 * if an object cannot be added to this {@code List}. 90 */ 91 public boolean addAll(Collection<? extends E> collection); 92 93 /** 94 * Removes all elements from this {@code List}, leaving it empty. 95 * 96 * @throws UnsupportedOperationException 97 * if removing from this {@code List} is not supported. 98 * @see #isEmpty 99 * @see #size 100 */ 101 public void clear(); 102 103 /** 104 * Tests whether this {@code List} contains the specified object. 105 * 106 * @param object 107 * the object to search for. 108 * @return {@code true} if object is an element of this {@code List}, {@code false} 109 * otherwise 110 */ 111 public boolean contains(Object object); 112 113 /** 114 * Tests whether this {@code List} contains all objects contained in the 115 * specified collection. 116 * 117 * @param collection 118 * the collection of objects 119 * @return {@code true} if all objects in the specified collection are 120 * elements of this {@code List}, {@code false} otherwise. 121 */ 122 public boolean containsAll(Collection<?> collection); 123 124 /** 125 * Compares the given object with the {@code List}, and returns true if they 126 * represent the <em>same</em> object using a class specific comparison. For 127 * {@code List}s, this means that they contain the same elements in exactly the same 128 * order. 129 * 130 * @param object 131 * the object to compare with this object. 132 * @return boolean {@code true} if the object is the same as this object, 133 * and {@code false} if it is different from this object. 134 * @see #hashCode 135 */ 136 public boolean equals(Object object); 137 138 /** 139 * Returns the element at the specified location in this {@code List}. 140 * 141 * @param location 142 * the index of the element to return. 143 * @return the element at the specified location. 144 * @throws IndexOutOfBoundsException 145 * if {@code location < 0 || >= size()} 146 */ 147 public E get(int location); 148 149 /** 150 * Returns the hash code for this {@code List}. It is calculated by taking each 151 * element' hashcode and its position in the {@code List} into account. 152 * 153 * @return the hash code of the {@code List}. 154 */ 155 public int hashCode(); 156 157 /** 158 * Searches this {@code List} for the specified object and returns the index of the 159 * first occurrence. 160 * 161 * @param object 162 * the object to search for. 163 * @return the index of the first occurrence of the object or -1 if the 164 * object was not found. 165 */ 166 public int indexOf(Object object); 167 168 /** 169 * Returns whether this {@code List} contains no elements. 170 * 171 * @return {@code true} if this {@code List} has no elements, {@code false} 172 * otherwise. 173 * @see #size 174 */ 175 public boolean isEmpty(); 176 177 /** 178 * Returns an iterator on the elements of this {@code List}. The elements are 179 * iterated in the same order as they occur in the {@code List}. 180 * 181 * @return an iterator on the elements of this {@code List}. 182 * @see Iterator 183 */ 184 public Iterator<E> iterator(); 185 186 /** 187 * Searches this {@code List} for the specified object and returns the index of the 188 * last occurrence. 189 * 190 * @param object 191 * the object to search for. 192 * @return the index of the last occurrence of the object, or -1 if the 193 * object was not found. 194 */ 195 public int lastIndexOf(Object object); 196 197 /** 198 * Returns a {@code List} iterator on the elements of this {@code List}. The elements are 199 * iterated in the same order that they occur in the {@code List}. 200 * 201 * @return a {@code List} iterator on the elements of this {@code List} 202 * 203 * @see ListIterator 204 */ 205 public ListIterator<E> listIterator(); 206 207 /** 208 * Returns a list iterator on the elements of this {@code List}. The elements are 209 * iterated in the same order as they occur in the {@code List}. The iteration 210 * starts at the specified location. 211 * 212 * @param location 213 * the index at which to start the iteration. 214 * @return a list iterator on the elements of this {@code List}. 215 * @throws IndexOutOfBoundsException 216 * if {@code location < 0 || location > size()} 217 * @see ListIterator 218 */ 219 public ListIterator<E> listIterator(int location); 220 221 /** 222 * Removes the object at the specified location from this {@code List}. 223 * 224 * @param location 225 * the index of the object to remove. 226 * @return the removed object. 227 * @throws UnsupportedOperationException 228 * if removing from this {@code List} is not supported. 229 * @throws IndexOutOfBoundsException 230 * if {@code location < 0 || >= size()} 231 */ 232 public E remove(int location); 233 234 /** 235 * Removes the first occurrence of the specified object from this {@code List}. 236 * 237 * @param object 238 * the object to remove. 239 * @return true if this {@code List} was modified by this operation, false 240 * otherwise. 241 * @throws UnsupportedOperationException 242 * if removing from this {@code List} is not supported. 243 */ 244 public boolean remove(Object object); 245 246 /** 247 * Removes all occurrences in this {@code List} of each object in the specified 248 * collection. 249 * 250 * @param collection 251 * the collection of objects to remove. 252 * @return {@code true} if this {@code List} is modified, {@code false} otherwise. 253 * @throws UnsupportedOperationException 254 * if removing from this {@code List} is not supported. 255 */ 256 public boolean removeAll(Collection<?> collection); 257 258 /** 259 * Removes all objects from this {@code List} that are not contained in the 260 * specified collection. 261 * 262 * @param collection 263 * the collection of objects to retain. 264 * @return {@code true} if this {@code List} is modified, {@code false} otherwise. 265 * @throws UnsupportedOperationException 266 * if removing from this {@code List} is not supported. 267 */ 268 public boolean retainAll(Collection<?> collection); 269 270 /** 271 * Replaces the element at the specified location in this {@code List} with the 272 * specified object. This operation does not change the size of the {@code List}. 273 * 274 * @param location 275 * the index at which to put the specified object. 276 * @param object 277 * the object to insert. 278 * @return the previous element at the index. 279 * @throws UnsupportedOperationException 280 * if replacing elements in this {@code List} is not supported. 281 * @throws ClassCastException 282 * if the class of an object is inappropriate for this 283 * {@code List}. 284 * @throws IllegalArgumentException 285 * if an object cannot be added to this {@code List}. 286 * @throws IndexOutOfBoundsException 287 * if {@code location < 0 || >= size()} 288 */ 289 public E set(int location, E object); 290 291 /** 292 * Returns the number of elements in this {@code List}. 293 * 294 * @return the number of elements in this {@code List}. 295 */ 296 public int size(); 297 298 /** 299 * Returns a {@code List} of the specified portion of this {@code List} from the given start 300 * index to the end index minus one. The returned {@code List} is backed by this 301 * {@code List} so changes to it are reflected by the other. 302 * 303 * @param start 304 * the index at which to start the sublist. 305 * @param end 306 * the index one past the end of the sublist. 307 * @return a list of a portion of this {@code List}. 308 * @throws IndexOutOfBoundsException 309 * if {@code start < 0, start > end} or {@code end > 310 * size()} 311 */ 312 public List<E> subList(int start, int end); 313 314 /** 315 * Returns an array containing all elements contained in this {@code List}. 316 * 317 * @return an array of the elements from this {@code List}. 318 */ 319 public Object[] toArray(); 320 321 /** 322 * Returns an array containing all elements contained in this {@code List}. If the 323 * specified array is large enough to hold the elements, the specified array 324 * is used, otherwise an array of the same type is created. If the specified 325 * array is used and is larger than this {@code List}, the array element following 326 * the collection elements is set to null. 327 * 328 * @param array 329 * the array. 330 * @return an array of the elements from this {@code List}. 331 * @throws ArrayStoreException 332 * if the type of an element in this {@code List} cannot be stored 333 * in the type of the specified array. 334 */ 335 public <T> T[] toArray(T[] array); 336 }
Set Interface

1 package java.util; 2 3 4 /** 5 * A {@code Set} is a data structure which does not allow duplicate elements. 6 * 7 * @since 1.2 8 */ 9 public interface Set<E> extends Collection<E> { 10 11 /** 12 * Adds the specified object to this set. The set is not modified if it 13 * already contains the object. 14 * 15 * @param object 16 * the object to add. 17 * @return {@code true} if this set is modified, {@code false} otherwise. 18 * @throws UnsupportedOperationException 19 * when adding to this set is not supported. 20 * @throws ClassCastException 21 * when the class of the object is inappropriate for this set. 22 * @throws IllegalArgumentException 23 * when the object cannot be added to this set. 24 */ 25 public boolean add(E object); 26 27 /** 28 * Adds the objects in the specified collection which do not exist yet in 29 * this set. 30 * 31 * @param collection 32 * the collection of objects. 33 * @return {@code true} if this set is modified, {@code false} otherwise. 34 * @throws UnsupportedOperationException 35 * when adding to this set is not supported. 36 * @throws ClassCastException 37 * when the class of an object is inappropriate for this set. 38 * @throws IllegalArgumentException 39 * when an object cannot be added to this set. 40 */ 41 public boolean addAll(Collection<? extends E> collection); 42 43 /** 44 * Removes all elements from this set, leaving it empty. 45 * 46 * @throws UnsupportedOperationException 47 * when removing from this set is not supported. 48 * @see #isEmpty 49 * @see #size 50 */ 51 public void clear(); 52 53 /** 54 * Searches this set for the specified object. 55 * 56 * @param object 57 * the object to search for. 58 * @return {@code true} if object is an element of this set, {@code false} 59 * otherwise. 60 */ 61 public boolean contains(Object object); 62 63 /** 64 * Searches this set for all objects in the specified collection. 65 * 66 * @param collection 67 * the collection of objects. 68 * @return {@code true} if all objects in the specified collection are 69 * elements of this set, {@code false} otherwise. 70 */ 71 public boolean containsAll(Collection<?> collection); 72 73 /** 74 * Compares the specified object to this set, and returns true if they 75 * represent the <em>same</em> object using a class specific comparison. 76 * Equality for a set means that both sets have the same size and the same 77 * elements. 78 * 79 * @param object 80 * the object to compare with this object. 81 * @return boolean {@code true} if the object is the same as this object, 82 * and {@code false} if it is different from this object. 83 * @see #hashCode 84 */ 85 public boolean equals(Object object); 86 87 /** 88 * Returns the hash code for this set. Two set which are equal must return 89 * the same value. 90 * 91 * @return the hash code of this set. 92 * 93 * @see #equals 94 */ 95 public int hashCode(); 96 97 /** 98 * Returns true if this set has no elements. 99 * 100 * @return {@code true} if this set has no elements, {@code false} 101 * otherwise. 102 * @see #size 103 */ 104 public boolean isEmpty(); 105 106 /** 107 * Returns an iterator on the elements of this set. The elements are 108 * unordered. 109 * 110 * @return an iterator on the elements of this set. 111 * @see Iterator 112 */ 113 public Iterator<E> iterator(); 114 115 /** 116 * Removes the specified object from this set. 117 * 118 * @param object 119 * the object to remove. 120 * @return {@code true} if this set was modified, {@code false} otherwise. 121 * @throws UnsupportedOperationException 122 * when removing from this set is not supported. 123 */ 124 public boolean remove(Object object); 125 126 /** 127 * Removes all objects in the specified collection from this set. 128 * 129 * @param collection 130 * the collection of objects to remove. 131 * @return {@code true} if this set was modified, {@code false} otherwise. 132 * @throws UnsupportedOperationException 133 * when removing from this set is not supported. 134 */ 135 public boolean removeAll(Collection<?> collection); 136 137 /** 138 * Removes all objects from this set that are not contained in the specified 139 * collection. 140 * 141 * @param collection 142 * the collection of objects to retain. 143 * @return {@code true} if this set was modified, {@code false} otherwise. 144 * @throws UnsupportedOperationException 145 * when removing from this set is not supported. 146 */ 147 public boolean retainAll(Collection<?> collection); 148 149 /** 150 * Returns the number of elements in this set. 151 * 152 * @return the number of elements in this set. 153 */ 154 public int size(); 155 156 /** 157 * Returns an array containing all elements contained in this set. 158 * 159 * @return an array of the elements from this set. 160 */ 161 public Object[] toArray(); 162 163 /** 164 * Returns an array containing all elements contained in this set. If the 165 * specified array is large enough to hold the elements, the specified array 166 * is used, otherwise an array of the same type is created. If the specified 167 * array is used and is larger than this set, the array element following 168 * the collection elements is set to null. 169 * 170 * @param array 171 * the array. 172 * @return an array of the elements from this set. 173 * @throws ArrayStoreException 174 * when the type of an element in this set cannot be stored in 175 * the type of the specified array. 176 * @see Collection#toArray(Object[]) 177 */ 178 public <T> T[] toArray(T[] array); 179 }
Queue Interface

1 public interface Queue<E> extends Collection<E> { 2 /** 3 * Inserts the specified element into this queue if it is possible to do so 4 * immediately without violating capacity restrictions, returning 5 * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt> 6 * if no space is currently available. 7 * 8 * @param e the element to add 9 * @return <tt>true</tt> (as specified by {@link Collection#add}) 10 * @throws IllegalStateException if the element cannot be added at this 11 * time due to capacity restrictions 12 * @throws ClassCastException if the class of the specified element 13 * prevents it from being added to this queue 14 * @throws NullPointerException if the specified element is null and 15 * this queue does not permit null elements 16 * @throws IllegalArgumentException if some property of this element 17 * prevents it from being added to this queue 18 */ 19 boolean add(E e); 20 21 /** 22 * Inserts the specified element into this queue if it is possible to do 23 * so immediately without violating capacity restrictions. 24 * When using a capacity-restricted queue, this method is generally 25 * preferable to {@link #add}, which can fail to insert an element only 26 * by throwing an exception. 27 * 28 * @param e the element to add 29 * @return <tt>true</tt> if the element was added to this queue, else 30 * <tt>false</tt> 31 * @throws ClassCastException if the class of the specified element 32 * prevents it from being added to this queue 33 * @throws NullPointerException if the specified element is null and 34 * this queue does not permit null elements 35 * @throws IllegalArgumentException if some property of this element 36 * prevents it from being added to this queue 37 */ 38 boolean offer(E e); 39 40 /** 41 * Retrieves and removes the head of this queue. This method differs 42 * from {@link #poll poll} only in that it throws an exception if this 43 * queue is empty. 44 * 45 * @return the head of this queue 46 * @throws NoSuchElementException if this queue is empty 47 */ 48 E remove(); 49 50 /** 51 * Retrieves and removes the head of this queue, 52 * or returns <tt>null</tt> if this queue is empty. 53 * 54 * @return the head of this queue, or <tt>null</tt> if this queue is empty 55 */ 56 E poll(); 57 58 /** 59 * Retrieves, but does not remove, the head of this queue. This method 60 * differs from {@link #peek peek} only in that it throws an exception 61 * if this queue is empty. 62 * 63 * @return the head of this queue 64 * @throws NoSuchElementException if this queue is empty 65 */ 66 E element(); 67 68 /** 69 * Retrieves, but does not remove, the head of this queue, 70 * or returns <tt>null</tt> if this queue is empty. 71 * 72 * @return the head of this queue, or <tt>null</tt> if this queue is empty 73 */ 74 E peek(); 75 }
SortedSet Interface

1 package java.util; 2 3 public interface SortedSet<E> extends Set<E> { 4 public Comparator<? super E> comparator(); 5 public E first(); 6 public SortedSet<E> headSet(E end); 7 public E last(); 8 public SortedSet<E> subSet(E start, E end); 9 public SortedSet<E> tailSet(E start); 10 }
NavigableSet Interface

1 public interface NavigableSet<E> extends SortedSet<E> { 2 E lower(E e); 3 E floor(E e); 4 E ceiling(E e); 5 E higher(E e); 6 E pollFirst(); 7 E pollLast(); 8 Iterator<E> iterator(); 9 NavigableSet<E> descendingSet(); 10 Iterator<E> descendingIterator(); 11 NavigableSet<E> subSet(E fromElement, boolean fromInclusive, 12 E toElement, boolean toInclusive); 13 NavigableSet<E> headSet(E toElement, boolean inclusive); 14 NavigableSet<E> tailSet(E fromElement, boolean inclusive); 15 SortedSet<E> subSet(E fromElement, E toElement); 16 SortedSet<E> headSet(E toElement); 17 SortedSet<E> tailSet(E fromElement); 18 }
AbstractCollection Abstract Class

1 public abstract class AbstractCollection<E> implements Collection<E> { 2 3 /** 4 * Constructs a new instance of this AbstractCollection. 5 */ 6 protected AbstractCollection() { 7 } 8 9 public boolean add(E object) { 10 throw new UnsupportedOperationException(); 11 } 12 13 /** 14 * Attempts to add all of the objects contained in {@code collection} 15 * to the contents of this {@code Collection} (optional). This implementation 16 * iterates over the given {@code Collection} and calls {@code add} for each 17 * element. If any of these calls return {@code true}, then {@code true} is 18 * returned as result of this method call, {@code false} otherwise. If this 19 * {@code Collection} does not support adding elements, an {@code 20 * UnsupportedOperationException} is thrown. 21 * <p> 22 * If the passed {@code Collection} is changed during the process of adding elements 23 * to this {@code Collection}, the behavior depends on the behavior of the passed 24 * {@code Collection}. 25 * 26 * @param collection 27 * the collection of objects. 28 * @return {@code true} if this {@code Collection} is modified, {@code false} 29 * otherwise. 30 * @throws UnsupportedOperationException 31 * if adding to this {@code Collection} is not supported. 32 * @throws ClassCastException 33 * if the class of an object is inappropriate for this 34 * {@code Collection}. 35 * @throws IllegalArgumentException 36 * if an object cannot be added to this {@code Collection}. 37 * @throws NullPointerException 38 * if {@code collection} is {@code null}, or if it contains 39 * {@code null} elements and this {@code Collection} does not support 40 * such elements. 41 */ 42 public boolean addAll(Collection<? extends E> collection) { 43 boolean result = false; 44 Iterator<? extends E> it = collection.iterator(); 45 while (it.hasNext()) { 46 if (add(it.next())) { 47 result = true; 48 } 49 } 50 return result; 51 } 52 53 /** 54 * Removes all elements from this {@code Collection}, leaving it empty (optional). 55 * This implementation iterates over this {@code Collection} and calls the {@code 56 * remove} method on each element. If the iterator does not support removal 57 * of elements, an {@code UnsupportedOperationException} is thrown. 58 * <p> 59 * Concrete implementations usually can clear a {@code Collection} more efficiently 60 * and should therefore overwrite this method. 61 * 62 * @throws UnsupportedOperationException 63 * it the iterator does not support removing elements from 64 * this {@code Collection} 65 * @see #iterator 66 * @see #isEmpty 67 * @see #size 68 */ 69 public void clear() { 70 Iterator<E> it = iterator(); 71 while (it.hasNext()) { 72 it.next(); 73 it.remove(); 74 } 75 } 76 77 /** 78 * Tests whether this {@code Collection} contains the specified object. This 79 * implementation iterates over this {@code Collection} and tests, whether any 80 * element is equal to the given object. If {@code object != null} then 81 * {@code object.equals(e)} is called for each element {@code e} returned by 82 * the iterator until the element is found. If {@code object == null} then 83 * each element {@code e} returned by the iterator is compared with the test 84 * {@code e == null}. 85 * 86 * @param object 87 * the object to search for. 88 * @return {@code true} if object is an element of this {@code Collection}, {@code 89 * false} otherwise. 90 * @throws ClassCastException 91 * if the object to look for isn't of the correct type. 92 * @throws NullPointerException 93 * if the object to look for is {@code null} and this 94 * {@code Collection} doesn't support {@code null} elements. 95 */ 96 public boolean contains(Object object) { 97 Iterator<E> it = iterator(); 98 if (object != null) { 99 while (it.hasNext()) { 100 if (object.equals(it.next())) { 101 return true; 102 } 103 } 104 } else { 105 while (it.hasNext()) { 106 if (it.next() == null) { 107 return true; 108 } 109 } 110 } 111 return false; 112 } 113 114 /** 115 * Tests whether this {@code Collection} contains all objects contained in the 116 * specified {@code Collection}. This implementation iterates over the specified 117 * {@code Collection}. If one element returned by the iterator is not contained in 118 * this {@code Collection}, then {@code false} is returned; {@code true} otherwise. 119 * 120 * @param collection 121 * the collection of objects. 122 * @return {@code true} if all objects in the specified {@code Collection} are 123 * elements of this {@code Collection}, {@code false} otherwise. 124 * @throws ClassCastException 125 * if one or more elements of {@code collection} isn't of the 126 * correct type. 127 * @throws NullPointerException 128 * if {@code collection} contains at least one {@code null} 129 * element and this {@code Collection} doesn't support {@code null} 130 * elements. 131 * @throws NullPointerException 132 * if {@code collection} is {@code null}. 133 */ 134 public boolean containsAll(Collection<?> collection) { 135 Iterator<?> it = collection.iterator(); 136 while (it.hasNext()) { 137 if (!contains(it.next())) { 138 return false; 139 } 140 } 141 return true; 142 } 143 144 /** 145 * Returns if this {@code Collection} contains no elements. This implementation 146 * tests, whether {@code size} returns 0. 147 * 148 * @return {@code true} if this {@code Collection} has no elements, {@code false} 149 * otherwise. 150 * 151 * @see #size 152 */ 153 public boolean isEmpty() { 154 return size() == 0; 155 } 156 157 /** 158 * Returns an instance of {@link Iterator} that may be used to access the 159 * objects contained by this {@code Collection}. The order in which the elements are 160 * returned by the {@link Iterator} is not defined unless the instance of the 161 * {@code Collection} has a defined order. In that case, the elements are returned in that order. 162 * <p> 163 * In this class this method is declared abstract and has to be implemented 164 * by concrete {@code Collection} implementations. 165 * 166 * @return an iterator for accessing the {@code Collection} contents. 167 */ 168 public abstract Iterator<E> iterator(); 169 170 /** 171 * Removes one instance of the specified object from this {@code Collection} if one 172 * is contained (optional). This implementation iterates over this 173 * {@code Collection} and tests for each element {@code e} returned by the iterator, 174 * whether {@code e} is equal to the given object. If {@code object != null} 175 * then this test is performed using {@code object.equals(e)}, otherwise 176 * using {@code object == null}. If an element equal to the given object is 177 * found, then the {@code remove} method is called on the iterator and 178 * {@code true} is returned, {@code false} otherwise. If the iterator does 179 * not support removing elements, an {@code UnsupportedOperationException} 180 * is thrown. 181 * 182 * @param object 183 * the object to remove. 184 * @return {@code true} if this {@code Collection} is modified, {@code false} 185 * otherwise. 186 * @throws UnsupportedOperationException 187 * if removing from this {@code Collection} is not supported. 188 * @throws ClassCastException 189 * if the object passed is not of the correct type. 190 * @throws NullPointerException 191 * if {@code object} is {@code null} and this {@code Collection} 192 * doesn't support {@code null} elements. 193 */ 194 public boolean remove(Object object) { 195 Iterator<?> it = iterator(); 196 if (object != null) { 197 while (it.hasNext()) { 198 if (object.equals(it.next())) { 199 it.remove(); 200 return true; 201 } 202 } 203 } else { 204 while (it.hasNext()) { 205 if (it.next() == null) { 206 it.remove(); 207 return true; 208 } 209 } 210 } 211 return false; 212 } 213 214 /** 215 * Removes all occurrences in this {@code Collection} of each object in the 216 * specified {@code Collection} (optional). After this method returns none of the 217 * elements in the passed {@code Collection} can be found in this {@code Collection} 218 * anymore. 219 * <p> 220 * This implementation iterates over this {@code Collection} and tests for each 221 * element {@code e} returned by the iterator, whether it is contained in 222 * the specified {@code Collection}. If this test is positive, then the {@code 223 * remove} method is called on the iterator. If the iterator does not 224 * support removing elements, an {@code UnsupportedOperationException} is 225 * thrown. 226 * 227 * @param collection 228 * the collection of objects to remove. 229 * @return {@code true} if this {@code Collection} is modified, {@code false} 230 * otherwise. 231 * @throws UnsupportedOperationException 232 * if removing from this {@code Collection} is not supported. 233 * @throws ClassCastException 234 * if one or more elements of {@code collection} isn't of the 235 * correct type. 236 * @throws NullPointerException 237 * if {@code collection} contains at least one {@code null} 238 * element and this {@code Collection} doesn't support {@code null} 239 * elements. 240 * @throws NullPointerException 241 * if {@code collection} is {@code null}. 242 */ 243 public boolean removeAll(Collection<?> collection) { 244 boolean result = false; 245 Iterator<?> it = iterator(); 246 while (it.hasNext()) { 247 if (collection.contains(it.next())) { 248 it.remove(); 249 result = true; 250 } 251 } 252 return result; 253 } 254 255 /** 256 * Removes all objects from this {@code Collection} that are not also found in the 257 * {@code Collection} passed (optional). After this method returns this {@code Collection} 258 * will only contain elements that also can be found in the {@code Collection} 259 * passed to this method. 260 * <p> 261 * This implementation iterates over this {@code Collection} and tests for each 262 * element {@code e} returned by the iterator, whether it is contained in 263 * the specified {@code Collection}. If this test is negative, then the {@code 264 * remove} method is called on the iterator. If the iterator does not 265 * support removing elements, an {@code UnsupportedOperationException} is 266 * thrown. 267 * 268 * @param collection 269 * the collection of objects to retain. 270 * @return {@code true} if this {@code Collection} is modified, {@code false} 271 * otherwise. 272 * @throws UnsupportedOperationException 273 * if removing from this {@code Collection} is not supported. 274 * @throws ClassCastException 275 * if one or more elements of {@code collection} 276 * isn't of the correct type. 277 * @throws NullPointerException 278 * if {@code collection} contains at least one 279 * {@code null} element and this {@code Collection} doesn't support 280 * {@code null} elements. 281 * @throws NullPointerException 282 * if {@code collection} is {@code null}. 283 */ 284 public boolean retainAll(Collection<?> collection) { 285 boolean result = false; 286 Iterator<?> it = iterator(); 287 while (it.hasNext()) { 288 if (!collection.contains(it.next())) { 289 it.remove(); 290 result = true; 291 } 292 } 293 return result; 294 } 295 296 /** 297 * Returns a count of how many objects this {@code Collection} contains. 298 * <p> 299 * In this class this method is declared abstract and has to be implemented 300 * by concrete {@code Collection} implementations. 301 * 302 * @return how many objects this {@code Collection} contains, or {@code Integer.MAX_VALUE} 303 * if there are more than {@code Integer.MAX_VALUE} elements in this 304 * {@code Collection}. 305 */ 306 public abstract int size(); 307 308 public Object[] toArray() { 309 int size = size(), index = 0; 310 Iterator<?> it = iterator(); 311 Object[] array = new Object[size]; 312 while (index < size) { 313 array[index++] = it.next(); 314 } 315 return array; 316 } 317 318 @SuppressWarnings("unchecked") 319 public <T> T[] toArray(T[] contents) { 320 int size = size(), index = 0; 321 if (size > contents.length) { 322 Class<?> ct = contents.getClass().getComponentType(); 323 contents = (T[]) Array.newInstance(ct, size); 324 } 325 for (E entry : this) { 326 contents[index++] = (T) entry; 327 } 328 if (index < contents.length) { 329 contents[index] = null; 330 } 331 return contents; 332 } 333 334 /** 335 * Returns the string representation of this {@code Collection}. The presentation 336 * has a specific format. It is enclosed by square brackets ("[]"). Elements 337 * are separated by ', ' (comma and space). 338 * 339 * @return the string representation of this {@code Collection}. 340 */ 341 @Override 342 public String toString() { 343 if (isEmpty()) { 344 return "[]"; 345 } 346 347 StringBuilder buffer = new StringBuilder(size() * 16); 348 buffer.append('['); 349 Iterator<?> it = iterator(); 350 while (it.hasNext()) { 351 Object next = it.next(); 352 if (next != this) { 353 buffer.append(next); 354 } else { 355 buffer.append("(this Collection)"); 356 } 357 if (it.hasNext()) { 358 buffer.append(", "); 359 } 360 } 361 buffer.append(']'); 362 return buffer.toString(); 363 } 364 }
AbstractSet AbstractClass

1 public abstract class AbstractSet<E> extends AbstractCollection<E> implements 2 Set<E> { 3 4 /** 5 * Constructs a new instance of this AbstractSet. 6 */ 7 protected AbstractSet() { 8 } 9 10 /** 11 * Compares the specified object to this Set and returns true if they are 12 * equal. The object must be an instance of Set and contain the same 13 * objects. 14 * 15 * @param object 16 * the object to compare with this set. 17 * @return {@code true} if the specified object is equal to this set, 18 * {@code false} otherwise 19 * @see #hashCode 20 */ 21 @Override 22 public boolean equals(Object object) { 23 if (this == object) { 24 return true; 25 } 26 if (object instanceof Set) { 27 Set<?> s = (Set<?>) object; 28 29 try { 30 return size() == s.size() && containsAll(s); 31 } catch (NullPointerException ignored) { 32 return false; 33 } catch (ClassCastException ignored) { 34 return false; 35 } 36 } 37 return false; 38 } 39 40 /** 41 * Returns the hash code for this set. Two set which are equal must return 42 * the same value. This implementation calculates the hash code by adding 43 * each element's hash code. 44 * 45 * @return the hash code of this set. 46 * @see #equals 47 */ 48 @Override 49 public int hashCode() { 50 int result = 0; 51 Iterator<?> it = iterator(); 52 while (it.hasNext()) { 53 Object next = it.next(); 54 result += next == null ? 0 : next.hashCode(); 55 } 56 return result; 57 } 58 59 /** 60 * Removes all occurrences in this collection which are contained in the 61 * specified collection. 62 * 63 * @param collection 64 * the collection of objects to remove. 65 * @return {@code true} if this collection was modified, {@code false} 66 * otherwise. 67 * @throws UnsupportedOperationException 68 * if removing from this collection is not supported. 69 */ 70 @Override 71 public boolean removeAll(Collection<?> collection) { 72 boolean result = false; 73 if (size() <= collection.size()) { 74 Iterator<?> it = iterator(); 75 while (it.hasNext()) { 76 if (collection.contains(it.next())) { 77 it.remove(); 78 result = true; 79 } 80 } 81 } else { 82 Iterator<?> it = collection.iterator(); 83 while (it.hasNext()) { 84 result = remove(it.next()) || result; 85 } 86 } 87 return result; 88 } 89 }
HashSet

1 package java.util; 2 3 import java.io.IOException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 import java.io.Serializable; 7 8 9 public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, 10 Serializable { 11 12 private static final long serialVersionUID = -5024744406713321676L; 13 14 transient HashMap<E, HashSet<E>> backingMap; 15 16 /** 17 * Constructs a new empty instance of {@code HashSet}. 18 */ 19 public HashSet() { 20 this(new HashMap<E, HashSet<E>>()); 21 } 22 23 /** 24 * Constructs a new instance of {@code HashSet} with the specified capacity. 25 * 26 * @param capacity 27 * the initial capacity of this {@code HashSet}. 28 */ 29 public HashSet(int capacity) { 30 this(new HashMap<E, HashSet<E>>(capacity)); 31 } 32 33 /** 34 * Constructs a new instance of {@code HashSet} with the specified capacity 35 * and load factor. 36 * 37 * @param capacity 38 * the initial capacity. 39 * @param loadFactor 40 * the initial load factor. 41 */ 42 public HashSet(int capacity, float loadFactor) { 43 this(new HashMap<E, HashSet<E>>(capacity, loadFactor)); 44 } 45 46 /** 47 * Constructs a new instance of {@code HashSet} containing the unique 48 * elements in the specified collection. 49 * 50 * @param collection 51 * the collection of elements to add. 52 */ 53 public HashSet(Collection<? extends E> collection) { 54 this(new HashMap<E, HashSet<E>>(collection.size() < 6 ? 11 : collection 55 .size() * 2)); 56 for (E e : collection) { 57 add(e); 58 } 59 } 60 61 HashSet(HashMap<E, HashSet<E>> backingMap) { 62 this.backingMap = backingMap; 63 } 64 65 /** 66 * Adds the specified object to this {@code HashSet} if not already present. 67 * 68 * @param object 69 * the object to add. 70 * @return {@code true} when this {@code HashSet} did not already contain 71 * the object, {@code false} otherwise 72 */ 73 @Override 74 public boolean add(E object) { 75 return backingMap.put(object, this) == null; 76 } 77 78 /** 79 * Removes all elements from this {@code HashSet}, leaving it empty. 80 * 81 * @see #isEmpty 82 * @see #size 83 */ 84 @Override 85 public void clear() { 86 backingMap.clear(); 87 } 88 89 /** 90 * Returns a new {@code HashSet} with the same elements and size as this 91 * {@code HashSet}. 92 * 93 * @return a shallow copy of this {@code HashSet}. 94 * @see java.lang.Cloneable 95 */ 96 @Override 97 @SuppressWarnings("unchecked") 98 public Object clone() { 99 try { 100 HashSet<E> clone = (HashSet<E>) super.clone(); 101 clone.backingMap = (HashMap<E, HashSet<E>>) backingMap.clone(); 102 return clone; 103 } catch (CloneNotSupportedException e) { 104 throw new AssertionError(e); 105 } 106 } 107 108 /** 109 * Searches this {@code HashSet} for the specified object. 110 * 111 * @param object 112 * the object to search for. 113 * @return {@code true} if {@code object} is an element of this 114 * {@code HashSet}, {@code false} otherwise. 115 */ 116 @Override 117 public boolean contains(Object object) { 118 return backingMap.containsKey(object); 119 } 120 121 /** 122 * Returns true if this {@code HashSet} has no elements, false otherwise. 123 * 124 * @return {@code true} if this {@code HashSet} has no elements, 125 * {@code false} otherwise. 126 * @see #size 127 */ 128 @Override 129 public boolean isEmpty() { 130 return backingMap.isEmpty(); 131 } 132 133 /** 134 * Returns an Iterator on the elements of this {@code HashSet}. 135 * 136 * @return an Iterator on the elements of this {@code HashSet}. 137 * @see Iterator 138 */ 139 @Override 140 public Iterator<E> iterator() { 141 return backingMap.keySet().iterator(); 142 } 143 144 /** 145 * Removes the specified object from this {@code HashSet}. 146 * 147 * @param object 148 * the object to remove. 149 * @return {@code true} if the object was removed, {@code false} otherwise. 150 */ 151 @Override 152 public boolean remove(Object object) { 153 return backingMap.remove(object) != null; 154 } 155 156 /** 157 * Returns the number of elements in this {@code HashSet}. 158 * 159 * @return the number of elements in this {@code HashSet}. 160 */ 161 @Override 162 public int size() { 163 return backingMap.size(); 164 } 165 166 private void writeObject(ObjectOutputStream stream) throws IOException { 167 stream.defaultWriteObject(); 168 stream.writeInt(backingMap.table.length); 169 stream.writeFloat(HashMap.DEFAULT_LOAD_FACTOR); 170 stream.writeInt(size()); 171 for (E e : this) { 172 stream.writeObject(e); 173 } 174 } 175 176 @SuppressWarnings("unchecked") 177 private void readObject(ObjectInputStream stream) throws IOException, 178 ClassNotFoundException { 179 stream.defaultReadObject(); 180 int length = stream.readInt(); 181 float loadFactor = stream.readFloat(); 182 backingMap = createBackingMap(length, loadFactor); 183 int elementCount = stream.readInt(); 184 for (int i = elementCount; --i >= 0;) { 185 E key = (E) stream.readObject(); 186 backingMap.put(key, this); 187 } 188 } 189 190 HashMap<E, HashSet<E>> createBackingMap(int capacity, float loadFactor) { 191 return new HashMap<E, HashSet<E>>(capacity, loadFactor); 192 } 193 }
TreeSet

1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util; 19 20 import java.io.IOException; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectOutputStream; 23 import java.io.Serializable; 24 25 /** 26 * TreeSet is an implementation of SortedSet. All optional operations (adding 27 * and removing) are supported. The elements can be any objects which are 28 * comparable to each other either using their natural order or a specified 29 * Comparator. 30 * 31 * @since 1.2 32 */ 33 public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, 34 Cloneable, Serializable { 35 36 private static final long serialVersionUID = -2479143000061671589L; 37 38 /** Keys are this set's elements. Values are always Boolean.TRUE */ 39 private transient NavigableMap<E, Object> backingMap; 40 41 private transient NavigableSet<E> descendingSet; 42 43 TreeSet(NavigableMap<E, Object> map) { 44 backingMap = map; 45 } 46 47 /** 48 * Constructs a new empty instance of {@code TreeSet} which uses natural 49 * ordering. 50 */ 51 public TreeSet() { 52 backingMap = new TreeMap<E, Object>(); 53 } 54 55 /** 56 * Constructs a new instance of {@code TreeSet} which uses natural ordering 57 * and containing the unique elements in the specified collection. 58 * 59 * @param collection 60 * the collection of elements to add. 61 * @throws ClassCastException 62 * when an element in the collection does not implement the 63 * Comparable interface, or the elements in the collection 64 * cannot be compared. 65 */ 66 public TreeSet(Collection<? extends E> collection) { 67 this(); 68 addAll(collection); 69 } 70 71 /** 72 * Constructs a new empty instance of {@code TreeSet} which uses the 73 * specified comparator. 74 * 75 * @param comparator 76 * the comparator to use. 77 */ 78 public TreeSet(Comparator<? super E> comparator) { 79 backingMap = new TreeMap<E, Object>(comparator); 80 } 81 82 /** 83 * Constructs a new instance of {@code TreeSet} containing the elements of 84 * the specified SortedSet and using the same Comparator. 85 * 86 * @param set 87 * the SortedSet of elements to add. 88 */ 89 public TreeSet(SortedSet<E> set) { 90 this(set.comparator()); 91 Iterator<E> it = set.iterator(); 92 while (it.hasNext()) { 93 add(it.next()); 94 } 95 } 96 97 /** 98 * Adds the specified object to this {@code TreeSet}. 99 * 100 * @param object 101 * the object to add. 102 * @return {@code true} when this {@code TreeSet} did not already contain 103 * the object, {@code false} otherwise. 104 * @throws ClassCastException 105 * when the object cannot be compared with the elements in this 106 * {@code TreeSet}. 107 * @throws NullPointerException 108 * when the object is null and the comparator cannot handle 109 * null. 110 */ 111 @Override 112 public boolean add(E object) { 113 return backingMap.put(object, Boolean.TRUE) == null; 114 } 115 116 /** 117 * Adds the objects in the specified collection to this {@code TreeSet}. 118 * 119 * @param collection 120 * the collection of objects to add. 121 * @return {@code true} if this {@code TreeSet} was modified, {@code false} 122 * otherwise. 123 * @throws ClassCastException 124 * when an object in the collection cannot be compared with the 125 * elements in this {@code TreeSet}. 126 * @throws NullPointerException 127 * when an object in the collection is null and the comparator 128 * cannot handle null. 129 */ 130 @Override 131 public boolean addAll(Collection<? extends E> collection) { 132 return super.addAll(collection); 133 } 134 135 /** 136 * Removes all elements from this {@code TreeSet}, leaving it empty. 137 * 138 * @see #isEmpty 139 * @see #size 140 */ 141 @Override 142 public void clear() { 143 backingMap.clear(); 144 } 145 146 /** 147 * Returns a new {@code TreeSet} with the same elements, size and comparator 148 * as this {@code TreeSet}. 149 * 150 * @return a shallow copy of this {@code TreeSet}. 151 * @see java.lang.Cloneable 152 */ 153 @SuppressWarnings("unchecked") 154 @Override 155 public Object clone() { 156 try { 157 TreeSet<E> clone = (TreeSet<E>) super.clone(); 158 if (backingMap instanceof TreeMap) { 159 clone.backingMap = (NavigableMap<E, Object>) ((TreeMap<E, Object>) backingMap) 160 .clone(); 161 } else { 162 clone.backingMap = new TreeMap<E, Object>(backingMap); 163 } 164 return clone; 165 } catch (CloneNotSupportedException e) { 166 throw new AssertionError(e); 167 } 168 } 169 170 /** 171 * Returns the comparator used to compare elements in this {@code TreeSet}. 172 * 173 * @return a Comparator or null if the natural ordering is used 174 */ 175 public Comparator<? super E> comparator() { 176 return backingMap.comparator(); 177 } 178 179 /** 180 * Searches this {@code TreeSet} for the specified object. 181 * 182 * @param object 183 * the object to search for. 184 * @return {@code true} if {@code object} is an element of this 185 * {@code TreeSet}, {@code false} otherwise. 186 * @throws ClassCastException 187 * when the object cannot be compared with the elements in this 188 * {@code TreeSet}. 189 * @throws NullPointerException 190 * when the object is null and the comparator cannot handle 191 * null. 192 */ 193 @Override 194 public boolean contains(Object object) { 195 return backingMap.containsKey(object); 196 } 197 198 /** 199 * Returns true if this {@code TreeSet} has no element, otherwise false. 200 * 201 * @return true if this {@code TreeSet} has no element. 202 * @see #size 203 */ 204 @Override 205 public boolean isEmpty() { 206 return backingMap.isEmpty(); 207 } 208 209 /** 210 * Returns an Iterator on the elements of this {@code TreeSet}. 211 * 212 * @return an Iterator on the elements of this {@code TreeSet}. 213 * @see Iterator 214 */ 215 @Override 216 public Iterator<E> iterator() { 217 return backingMap.keySet().iterator(); 218 } 219 220 /** 221 * {@inheritDoc} 222 * 223 * @see java.util.NavigableSet#descendingIterator() 224 * @since 1.6 225 */ 226 public Iterator<E> descendingIterator() { 227 return descendingSet().iterator(); 228 } 229 230 /** 231 * Removes an occurrence of the specified object from this {@code TreeSet}. 232 * 233 * @param object 234 * the object to remove. 235 * @return {@code true} if this {@code TreeSet} was modified, {@code false} 236 * otherwise. 237 * @throws ClassCastException 238 * when the object cannot be compared with the elements in this 239 * {@code TreeSet}. 240 * @throws NullPointerException 241 * when the object is null and the comparator cannot handle 242 * null. 243 */ 244 @Override 245 public boolean remove(Object object) { 246 return backingMap.remove(object) != null; 247 } 248 249 /** 250 * Returns the number of elements in this {@code TreeSet}. 251 * 252 * @return the number of elements in this {@code TreeSet}. 253 */ 254 @Override 255 public int size() { 256 return backingMap.size(); 257 } 258 259 /** 260 * Returns the first element in this set. 261 * @exception NoSuchElementException when this TreeSet is empty 262 */ 263 public E first() { 264 return backingMap.firstKey(); 265 } 266 267 /** 268 * Returns the last element in this set. 269 * @exception NoSuchElementException when this TreeSet is empty 270 */ 271 public E last() { 272 return backingMap.lastKey(); 273 } 274 275 /** 276 * {@inheritDoc} 277 * 278 * @see java.util.NavigableSet#pollFirst() 279 * @since 1.6 280 */ 281 public E pollFirst() { 282 Map.Entry<E, Object> entry = backingMap.pollFirstEntry(); 283 return (entry == null) ? null : entry.getKey(); 284 } 285 286 /** 287 * {@inheritDoc} 288 * 289 * @see java.util.NavigableSet#pollLast() 290 * @since 1.6 291 */ 292 public E pollLast() { 293 Map.Entry<E, Object> entry = backingMap.pollLastEntry(); 294 return (entry == null) ? null : entry.getKey(); 295 } 296 297 /** 298 * {@inheritDoc} 299 * 300 * @see java.util.NavigableSet#higher(java.lang.Object) 301 * @since 1.6 302 */ 303 public E higher(E e) { 304 return backingMap.higherKey(e); 305 } 306 307 /** 308 * {@inheritDoc} 309 * 310 * @see java.util.NavigableSet#lower(java.lang.Object) 311 * @since 1.6 312 */ 313 public E lower(E e) { 314 return backingMap.lowerKey(e); 315 } 316 317 /** 318 * {@inheritDoc} 319 * 320 * @see java.util.NavigableSet#ceiling(java.lang.Object) 321 * @since 1.6 322 */ 323 public E ceiling(E e) { 324 return backingMap.ceilingKey(e); 325 } 326 327 /** 328 * {@inheritDoc} 329 * 330 * @see java.util.NavigableSet#floor(java.lang.Object) 331 * @since 1.6 332 */ 333 public E floor(E e) { 334 return backingMap.floorKey(e); 335 } 336 337 /** 338 * {@inheritDoc} 339 * 340 * @see java.util.NavigableSet#descendingSet() 341 * @since 1.6 342 */ 343 public NavigableSet<E> descendingSet() { 344 return (descendingSet != null) ? descendingSet 345 : (descendingSet = new TreeSet<E>(backingMap.descendingMap())); 346 } 347 348 /** 349 * {@inheritDoc} 350 * 351 * @see java.util.NavigableSet#subSet(Object, boolean, Object, boolean) 352 * @since 1.6 353 */ 354 @SuppressWarnings("unchecked") 355 public NavigableSet<E> subSet(E start, boolean startInclusive, E end, 356 boolean endInclusive) { 357 Comparator<? super E> c = backingMap.comparator(); 358 int compare = (c == null) ? ((Comparable<E>) start).compareTo(end) : c 359 .compare(start, end); 360 if (compare <= 0) { 361 return new TreeSet<E>(backingMap.subMap(start, startInclusive, end, 362 endInclusive)); 363 } 364 throw new IllegalArgumentException(); 365 } 366 367 /** 368 * {@inheritDoc} 369 * 370 * @see java.util.NavigableSet#headSet(Object, boolean) 371 * @since 1.6 372 */ 373 @SuppressWarnings("unchecked") 374 public NavigableSet<E> headSet(E end, boolean endInclusive) { 375 // Check for errors 376 Comparator<? super E> c = backingMap.comparator(); 377 if (c == null) { 378 ((Comparable<E>) end).compareTo(end); 379 } else { 380 c.compare(end, end); 381 } 382 return new TreeSet<E>(backingMap.headMap(end, endInclusive)); 383 } 384 385 /** 386 * {@inheritDoc} 387 * 388 * @see java.util.NavigableSet#tailSet(Object, boolean) 389 * @since 1.6 390 */ 391 @SuppressWarnings("unchecked") 392 public NavigableSet<E> tailSet(E start, boolean startInclusive) { 393 // Check for errors 394 Comparator<? super E> c = backingMap.comparator(); 395 if (c == null) { 396 ((Comparable<E>) start).compareTo(start); 397 } else { 398 c.compare(start, start); 399 } 400 return new TreeSet<E>(backingMap.tailMap(start, startInclusive)); 401 } 402 403 /** 404 * Returns a {@code SortedSet} of the specified portion of this {@code TreeSet} which 405 * contains elements greater or equal to the start element but less than the 406 * end element. The returned SortedSet is backed by this TreeSet so changes 407 * to one are reflected by the other. 408 * 409 * @param start 410 * the start element 411 * @param end 412 * the end element 413 * @return a subset where the elements are greater or equal to 414 * <code>start</code> and less than <code>end</code> 415 * 416 * @exception ClassCastException 417 * when the start or end object cannot be compared with the 418 * elements in this TreeSet 419 * @exception NullPointerException 420 * when the start or end object is null and the comparator 421 * cannot handle null 422 */ 423 @SuppressWarnings("unchecked") 424 public SortedSet<E> subSet(E start, E end) { 425 return subSet(start, true, end, false); 426 } 427 428 /** 429 * Returns a {@code SortedSet} of the specified portion of this {@code TreeSet} which 430 * contains elements less than the end element. The returned SortedSet is 431 * backed by this TreeSet so changes to one are reflected by the other. 432 * 433 * @param end 434 * the end element 435 * @return a subset where the elements are less than <code>end</code> 436 * 437 * @exception ClassCastException 438 * when the end object cannot be compared with the elements 439 * in this TreeSet 440 * @exception NullPointerException 441 * when the end object is null and the comparator cannot 442 * handle null 443 */ 444 @SuppressWarnings("unchecked") 445 public SortedSet<E> headSet(E end) { 446 return headSet(end, false); 447 } 448 449 /** 450 * Returns a {@code SortedSet} of the specified portion of this {@code TreeSet} which 451 * contains elements greater or equal to the start element. The returned 452 * SortedSet is backed by this TreeSet so changes to one are reflected by 453 * the other. 454 * 455 * @param start 456 * the start element 457 * @return a subset where the elements are greater or equal to 458 * <code>start</code> 459 * 460 * @exception ClassCastException 461 * when the start object cannot be compared with the elements 462 * in this TreeSet 463 * @exception NullPointerException 464 * when the start object is null and the comparator cannot 465 * handle null 466 */ 467 @SuppressWarnings("unchecked") 468 public SortedSet<E> tailSet(E start) { 469 return tailSet(start, true); 470 } 471 472 private void writeObject(ObjectOutputStream stream) throws IOException { 473 stream.defaultWriteObject(); 474 stream.writeObject(backingMap.comparator()); 475 int size = backingMap.size(); 476 stream.writeInt(size); 477 if (size > 0) { 478 Iterator<E> it = backingMap.keySet().iterator(); 479 while (it.hasNext()) { 480 stream.writeObject(it.next()); 481 } 482 } 483 } 484 485 @SuppressWarnings("unchecked") 486 private void readObject(ObjectInputStream stream) throws IOException, 487 ClassNotFoundException { 488 stream.defaultReadObject(); 489 TreeMap<E, Object> map = new TreeMap<E, Object>( 490 (Comparator<? super E>) stream.readObject()); 491 int size = stream.readInt(); 492 if (size > 0) { 493 for (int i=0; i<size; i++) { 494 E elem = (E)stream.readObject(); 495 map.put(elem, Boolean.TRUE); 496 } 497 } 498 backingMap = map; 499 } 500 }
AbstractList AbstractClass

1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util; 19 20 21 public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { 22 23 /** 24 * A counter for changes to the list. 25 */ 26 protected transient int modCount; 27 28 private class SimpleListIterator implements Iterator<E> { 29 int pos = -1; 30 31 int expectedModCount; 32 33 int lastPosition = -1; 34 35 SimpleListIterator() { 36 expectedModCount = modCount; 37 } 38 39 public boolean hasNext() { 40 return pos + 1 < size(); 41 } 42 43 public E next() { 44 if (expectedModCount == modCount) { 45 try { 46 E result = get(pos + 1); 47 lastPosition = ++pos; 48 return result; 49 } catch (IndexOutOfBoundsException e) { 50 throw new NoSuchElementException(); 51 } 52 } 53 throw new ConcurrentModificationException(); 54 } 55 56 public void remove() { 57 if (this.lastPosition == -1) { 58 throw new IllegalStateException(); 59 } 60 61 if (expectedModCount != modCount) { 62 throw new ConcurrentModificationException(); 63 } 64 65 try { 66 AbstractList.this.remove(lastPosition); 67 } catch (IndexOutOfBoundsException e) { 68 throw new ConcurrentModificationException(); 69 } 70 71 expectedModCount = modCount; 72 if (pos == lastPosition) { 73 pos--; 74 } 75 lastPosition = -1; 76 } 77 } 78 79 private final class FullListIterator extends SimpleListIterator implements ListIterator<E> { 80 FullListIterator(int start) { 81 if (start >= 0 && start <= size()) { 82 pos = start - 1; 83 } else { 84 throw new IndexOutOfBoundsException(); 85 } 86 } 87 88 public void add(E object) { 89 if (expectedModCount == modCount) { 90 try { 91 AbstractList.this.add(pos + 1, object); 92 } catch (IndexOutOfBoundsException e) { 93 throw new NoSuchElementException(); 94 } 95 pos++; 96 lastPosition = -1; 97 if (modCount != expectedModCount) { 98 expectedModCount = modCount; 99 } 100 } else { 101 throw new ConcurrentModificationException(); 102 } 103 } 104 105 public boolean hasPrevious() { 106 return pos >= 0; 107 } 108 109 public int nextIndex() { 110 return pos + 1; 111 } 112 113 public E previous() { 114 if (expectedModCount == modCount) { 115 try { 116 E result = get(pos); 117 lastPosition = pos; 118 pos--; 119 return result; 120 } catch (IndexOutOfBoundsException e) { 121 throw new NoSuchElementException(); 122 } 123 } 124 throw new ConcurrentModificationException(); 125 } 126 127 public int previousIndex() { 128 return pos; 129 } 130 131 public void set(E object) { 132 if (expectedModCount == modCount) { 133 try { 134 AbstractList.this.set(lastPosition, object); 135 } catch (IndexOutOfBoundsException e) { 136 throw new IllegalStateException(); 137 } 138 } else { 139 throw new ConcurrentModificationException(); 140 } 141 } 142 } 143 144 private static final class SubAbstractListRandomAccess<E> extends 145 SubAbstractList<E> implements RandomAccess { 146 SubAbstractListRandomAccess(AbstractList<E> list, int start, int end) { 147 super(list, start, end); 148 } 149 } 150 151 private static class SubAbstractList<E> extends AbstractList<E> { 152 private final AbstractList<E> fullList; 153 154 private int offset; 155 156 private int size; 157 158 private static final class SubAbstractListIterator<E> implements 159 ListIterator<E> { 160 private final SubAbstractList<E> subList; 161 162 private final ListIterator<E> iterator; 163 164 private int start; 165 166 private int end; 167 168 SubAbstractListIterator(ListIterator<E> it, 169 SubAbstractList<E> list, int offset, int length) { 170 iterator = it; 171 subList = list; 172 start = offset; 173 end = start + length; 174 } 175 176 public void add(E object) { 177 iterator.add(object); 178 subList.sizeChanged(true); 179 end++; 180 } 181 182 public boolean hasNext() { 183 return iterator.nextIndex() < end; 184 } 185 186 public boolean hasPrevious() { 187 return iterator.previousIndex() >= start; 188 } 189 190 public E next() { 191 if (iterator.nextIndex() < end) { 192 return iterator.next(); 193 } 194 throw new NoSuchElementException(); 195 } 196 197 public int nextIndex() { 198 return iterator.nextIndex() - start; 199 } 200 201 public E previous() { 202 if (iterator.previousIndex() >= start) { 203 return iterator.previous(); 204 } 205 throw new NoSuchElementException(); 206 } 207 208 public int previousIndex() { 209 int previous = iterator.previousIndex(); 210 if (previous >= start) { 211 return previous - start; 212 } 213 return -1; 214 } 215 216 public void remove() { 217 iterator.remove(); 218 subList.sizeChanged(false); 219 end--; 220 } 221 222 public void set(E object) { 223 iterator.set(object); 224 } 225 } 226 227 SubAbstractList(AbstractList<E> list, int start, int end) { 228 fullList = list; 229 modCount = fullList.modCount; 230 offset = start; 231 size = end - start; 232 } 233 234 @Override 235 public void add(int location, E object) { 236 if (modCount == fullList.modCount) { 237 if (location >= 0 && location <= size) { 238 fullList.add(location + offset, object); 239 size++; 240 modCount = fullList.modCount; 241 } else { 242 throw new IndexOutOfBoundsException(); 243 } 244 } else { 245 throw new ConcurrentModificationException(); 246 } 247 } 248 249 @Override 250 public boolean addAll(int location, Collection<? extends E> collection) { 251 if (modCount == fullList.modCount) { 252 if (location >= 0 && location <= size) { 253 boolean result = fullList.addAll(location + offset, 254 collection); 255 if (result) { 256 size += collection.size(); 257 modCount = fullList.modCount; 258 } 259 return result; 260 } 261 throw new IndexOutOfBoundsException(); 262 } 263 throw new ConcurrentModificationException(); 264 } 265 266 @Override 267 public boolean addAll(Collection<? extends E> collection) { 268 if (modCount == fullList.modCount) { 269 boolean result = fullList.addAll(offset + size, collection); 270 if (result) { 271 size += collection.size(); 272 modCount = fullList.modCount; 273 } 274 return result; 275 } 276 throw new ConcurrentModificationException(); 277 } 278 279 @Override 280 public E get(int location) { 281 if (modCount == fullList.modCount) { 282 if (location >= 0 && location < size) { 283 return fullList.get(location + offset); 284 } 285 throw new IndexOutOfBoundsException(); 286 } 287 throw new ConcurrentModificationException(); 288 } 289 290 @Override 291 public Iterator<E> iterator() { 292 return listIterator(0); 293 } 294 295 @Override 296 public ListIterator<E> listIterator(int location) { 297 if (modCount == fullList.modCount) { 298 if (location >= 0 && location <= size) { 299 return new SubAbstractListIterator<E>(fullList 300 .listIterator(location + offset), this, offset, 301 size); 302 } 303 throw new IndexOutOfBoundsException(); 304 } 305 throw new ConcurrentModificationException(); 306 } 307 308 @Override 309 public E remove(int location) { 310 if (modCount == fullList.modCount) { 311 if (location >= 0 && location < size) { 312 E result = fullList.remove(location + offset); 313 size--; 314 modCount = fullList.modCount; 315 return result; 316 } 317 throw new IndexOutOfBoundsException(); 318 } 319 throw new ConcurrentModificationException(); 320 } 321 322 @Override 323 protected void removeRange(int start, int end) { 324 if (start != end) { 325 if (modCount == fullList.modCount) { 326 fullList.removeRange(start + offset, end + offset); 327 size -= end - start; 328 modCount = fullList.modCount; 329 } else { 330 throw new ConcurrentModificationException(); 331 } 332 } 333 } 334 335 @Override 336 public E set(int location, E object) { 337 if (modCount == fullList.modCount) { 338 if (location >= 0 && location < size) { 339 return fullList.set(location + offset, object); 340 } 341 throw new IndexOutOfBoundsException(); 342 } 343 throw new ConcurrentModificationException(); 344 } 345 346 @Override 347 public int size() { 348 if (modCount == fullList.modCount) { 349 return size; 350 } 351 throw new ConcurrentModificationException(); 352 } 353 354 void sizeChanged(boolean increment) { 355 if (increment) { 356 size++; 357 } else { 358 size--; 359 } 360 modCount = fullList.modCount; 361 } 362 } 363 364 /** 365 * Constructs a new instance of this AbstractList. 366 */ 367 protected AbstractList() { 368 } 369 370 /** 371 * Inserts the specified object into this List at the specified location. 372 * The object is inserted before any previous element at the specified 373 * location. If the location is equal to the size of this List, the object 374 * is added at the end. 375 * <p> 376 * Concrete implementations that would like to support the add functionality 377 * must override this method. 378 * 379 * @param location 380 * the index at which to insert. 381 * @param object 382 * the object to add. 383 * 384 * @throws UnsupportedOperationException 385 * if adding to this List is not supported. 386 * @throws ClassCastException 387 * if the class of the object is inappropriate for this 388 * List 389 * @throws IllegalArgumentException 390 * if the object cannot be added to this List 391 * @throws IndexOutOfBoundsException 392 * if {@code location < 0 || >= size()} 393 */ 394 public void add(int location, E object) { 395 throw new UnsupportedOperationException(); 396 } 397 398 /** 399 * Adds the specified object at the end of this List. 400 * 401 * 402 * @param object 403 * the object to add 404 * @return true 405 * 406 * @throws UnsupportedOperationException 407 * if adding to this List is not supported 408 * @throws ClassCastException 409 * if the class of the object is inappropriate for this 410 * List 411 * @throws IllegalArgumentException 412 * if the object cannot be added to this List 413 */ 414 @Override 415 public boolean add(E object) { 416 add(size(), object); 417 return true; 418 } 419 420 /** 421 * Inserts the objects in the specified Collection at the specified location 422 * in this List. The objects are added in the order they are returned from 423 * the collection's iterator. 424 * 425 * @param location 426 * the index at which to insert. 427 * @param collection 428 * the Collection of objects 429 * @return {@code true} if this List is modified, {@code false} otherwise. 430 * @throws UnsupportedOperationException 431 * if adding to this list is not supported. 432 * @throws ClassCastException 433 * if the class of an object is inappropriate for this list. 434 * @throws IllegalArgumentException 435 * if an object cannot be added to this list. 436 * @throws IndexOutOfBoundsException 437 * if {@code location < 0 || > size()} 438 */ 439 public boolean addAll(int location, Collection<? extends E> collection) { 440 Iterator<? extends E> it = collection.iterator(); 441 while (it.hasNext()) { 442 add(location++, it.next()); 443 } 444 return !collection.isEmpty(); 445 } 446 447 /** 448 * Removes all elements from this list, leaving it empty. 449 * 450 * @throws UnsupportedOperationException 451 * if removing from this list is not supported. 452 * @see List#isEmpty 453 * @see List#size 454 */ 455 @Override 456 public void clear() { 457 removeRange(0, size()); 458 } 459 460 @Override 461 public boolean equals(Object object) { 462 if (this == object) { 463 return true; 464 } 465 if (object instanceof List) { 466 List<?> list = (List<?>) object; 467 if (list.size() != size()) { 468 return false; 469 } 470 471 Iterator<?> it1 = iterator(), it2 = list.iterator(); 472 while (it1.hasNext()) { 473 Object e1 = it1.next(), e2 = it2.next(); 474 if (!(e1 == null ? e2 == null : e1.equals(e2))) { 475 return false; 476 } 477 } 478 return true; 479 } 480 return false; 481 } 482 public abstract E get(int location); 483 484 @Override 485 public int hashCode() { 486 int result = 1; 487 Iterator<?> it = iterator(); 488 while (it.hasNext()) { 489 Object object = it.next(); 490 result = (31 * result) + (object == null ? 0 : object.hashCode()); 491 } 492 return result; 493 } 494 public int indexOf(Object object) { 495 ListIterator<?> it = listIterator(); 496 if (object != null) { 497 while (it.hasNext()) { 498 if (object.equals(it.next())) { 499 return it.previousIndex(); 500 } 501 } 502 } else { 503 while (it.hasNext()) { 504 if (it.next() == null) { 505 return it.previousIndex(); 506 } 507 } 508 } 509 return -1; 510 } 511 512 @Override 513 public Iterator<E> iterator() { 514 return new SimpleListIterator(); 515 } 516 517 public int lastIndexOf(Object object) { 518 ListIterator<?> it = listIterator(size()); 519 if (object != null) { 520 while (it.hasPrevious()) { 521 if (object.equals(it.previous())) { 522 return it.nextIndex(); 523 } 524 } 525 } else { 526 while (it.hasPrevious()) { 527 if (it.previous() == null) { 528 return it.nextIndex(); 529 } 530 } 531 } 532 return -1; 533 } 534 535 public ListIterator<E> listIterator() { 536 return listIterator(0); 537 } 538 539 public ListIterator<E> listIterator(int location) { 540 return new FullListIterator(location); 541 } 542 543 544 public E remove(int location) { 545 throw new UnsupportedOperationException(); 546 } 547 548 protected void removeRange(int start, int end) { 549 Iterator<?> it = listIterator(start); 550 for (int i = start; i < end; i++) { 551 it.next(); 552 it.remove(); 553 } 554 } 555 556 public E set(int location, E object) { 557 throw new UnsupportedOperationException(); 558 } 559 560 public List<E> subList(int start, int end) { 561 if (start >= 0 && end <= size()) { 562 if (start <= end) { 563 if (this instanceof RandomAccess) { 564 return new SubAbstractListRandomAccess<E>(this, start, end); 565 } 566 return new SubAbstractList<E>(this, start, end); 567 } 568 throw new IllegalArgumentException(); 569 } 570 throw new IndexOutOfBoundsException(); 571 } 572 }
Vector

1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util; 19 20 import java.io.IOException; 21 import java.io.ObjectOutputStream; 22 import java.io.Serializable; 23 import java.lang.reflect.Array; 24 25 /** 26 * Vector is an implementation of {@link List}, backed by an array and synchronized. 27 * All optional operations including adding, removing, and replacing elements are supported. 28 * 29 * <p>All elements are permitted, including null. 30 * 31 * <p>This class is equivalent to {@link ArrayList} with synchronized operations. This has a 32 * performance cost, and the synchronization is not necessarily meaningful to your application: 33 * synchronizing each call to {@code get}, for example, is not equivalent to synchronizing on the 34 * list and iterating over it (which is probably what you intended). If you do need very highly 35 * concurrent access, you should also consider {@link java.util.concurrent.CopyOnWriteArrayList}. 36 * 37 * @param <E> The element type of this list. 38 */ 39 public class Vector<E> extends AbstractList<E> implements List<E>, 40 RandomAccess, Cloneable, Serializable { 41 42 private static final long serialVersionUID = -2767605614048989439L; 43 44 /** 45 * The number of elements or the size of the vector. 46 */ 47 protected int elementCount; 48 49 /** 50 * The elements of the vector. 51 */ 52 protected Object[] elementData; 53 54 /** 55 * How many elements should be added to the vector when it is detected that 56 * it needs to grow to accommodate extra entries. If this value is zero or 57 * negative the size will be doubled if an increase is needed. 58 */ 59 protected int capacityIncrement; 60 61 private static final int DEFAULT_SIZE = 10; 62 63 /** 64 * Constructs a new vector using the default capacity. 65 */ 66 public Vector() { 67 this(DEFAULT_SIZE, 0); 68 } 69 70 /** 71 * Constructs a new vector using the specified capacity. 72 * 73 * @param capacity 74 * the initial capacity of the new vector. 75 * @throws IllegalArgumentException 76 * if {@code capacity} is negative. 77 */ 78 public Vector(int capacity) { 79 this(capacity, 0); 80 } 81 82 /** 83 * Constructs a new vector using the specified capacity and capacity 84 * increment. 85 * 86 * @param capacity 87 * the initial capacity of the new vector. 88 * @param capacityIncrement 89 * the amount to increase the capacity when this vector is full. 90 * @throws IllegalArgumentException 91 * if {@code capacity} is negative. 92 */ 93 public Vector(int capacity, int capacityIncrement) { 94 if (capacity < 0) { 95 throw new IllegalArgumentException(); 96 } 97 elementData = newElementArray(capacity); 98 elementCount = 0; 99 this.capacityIncrement = capacityIncrement; 100 } 101 102 /** 103 * Constructs a new instance of {@code Vector} containing the elements in 104 * {@code collection}. The order of the elements in the new {@code Vector} 105 * is dependent on the iteration order of the seed collection. 106 * 107 * @param collection 108 * the collection of elements to add. 109 */ 110 public Vector(Collection<? extends E> collection) { 111 this(collection.size(), 0); 112 Iterator<? extends E> it = collection.iterator(); 113 while (it.hasNext()) { 114 elementData[elementCount++] = it.next(); 115 } 116 } 117 118 @SuppressWarnings("unchecked") 119 private E[] newElementArray(int size) { 120 return (E[]) new Object[size]; 121 } 122 123 /** 124 * Adds the specified object into this vector at the specified location. The 125 * object is inserted before any element with the same or a higher index 126 * increasing their index by 1. If the location is equal to the size of this 127 * vector, the object is added at the end. 128 * 129 * @param location 130 * the index at which to insert the element. 131 * @param object 132 * the object to insert in this vector. 133 * @throws ArrayIndexOutOfBoundsException 134 * if {@code location < 0 || location > size()}. 135 * @see #addElement 136 * @see #size 137 */ 138 @Override 139 public void add(int location, E object) { 140 insertElementAt(object, location); 141 } 142 143 /** 144 * Adds the specified object at the end of this vector. 145 * 146 * @param object 147 * the object to add to the vector. 148 * @return {@code true} 149 */ 150 @Override 151 public synchronized boolean add(E object) { 152 if (elementCount == elementData.length) { 153 growByOne(); 154 } 155 elementData[elementCount++] = object; 156 modCount++; 157 return true; 158 } 159 160 /** 161 * Inserts the objects in the specified collection at the specified location 162 * in this vector. The objects are inserted in the order in which they are 163 * returned from the Collection iterator. The elements with an index equal 164 * or higher than {@code location} have their index increased by the size of 165 * the added collection. 166 * 167 * @param location 168 * the location to insert the objects. 169 * @param collection 170 * the collection of objects. 171 * @return {@code true} if this vector is modified, {@code false} otherwise. 172 * @throws ArrayIndexOutOfBoundsException 173 * if {@code location < 0} or {@code location > size()}. 174 */ 175 @Override 176 public synchronized boolean addAll(int location, Collection<? extends E> collection) { 177 if (location >= 0 && location <= elementCount) { 178 int size = collection.size(); 179 if (size == 0) { 180 return false; 181 } 182 int required = size - (elementData.length - elementCount); 183 if (required > 0) { 184 growBy(required); 185 } 186 int count = elementCount - location; 187 if (count > 0) { 188 System.arraycopy(elementData, location, elementData, location 189 + size, count); 190 } 191 Iterator<? extends E> it = collection.iterator(); 192 while (it.hasNext()) { 193 elementData[location++] = it.next(); 194 } 195 elementCount += size; 196 modCount++; 197 return true; 198 } 199 throw arrayIndexOutOfBoundsException(location, elementCount); 200 } 201 202 /** 203 * Adds the objects in the specified collection to the end of this vector. 204 * 205 * @param collection 206 * the collection of objects. 207 * @return {@code true} if this vector is modified, {@code false} otherwise. 208 */ 209 @Override 210 public synchronized boolean addAll(Collection<? extends E> collection) { 211 return addAll(elementCount, collection); 212 } 213 214 /** 215 * Adds the specified object at the end of this vector. 216 * 217 * @param object 218 * the object to add to the vector. 219 */ 220 public synchronized void addElement(E object) { 221 if (elementCount == elementData.length) { 222 growByOne(); 223 } 224 elementData[elementCount++] = object; 225 modCount++; 226 } 227 228 /** 229 * Returns the number of elements this vector can hold without growing. 230 * 231 * @return the capacity of this vector. 232 * @see #ensureCapacity 233 * @see #size 234 */ 235 public synchronized int capacity() { 236 return elementData.length; 237 } 238 239 /** 240 * Removes all elements from this vector, leaving it empty. 241 * 242 * @see #isEmpty 243 * @see #size 244 */ 245 @Override 246 public void clear() { 247 removeAllElements(); 248 } 249 250 /** 251 * Returns a new vector with the same elements, size, capacity and capacity 252 * increment as this vector. 253 * 254 * @return a shallow copy of this vector. 255 * @see java.lang.Cloneable 256 */ 257 @Override 258 @SuppressWarnings("unchecked") 259 public synchronized Object clone() { 260 try { 261 Vector<E> vector = (Vector<E>) super.clone(); 262 vector.elementData = elementData.clone(); 263 return vector; 264 } catch (CloneNotSupportedException e) { 265 throw new AssertionError(e); 266 } 267 } 268 269 /** 270 * Searches this vector for the specified object. 271 * 272 * @param object 273 * the object to look for in this vector. 274 * @return {@code true} if object is an element of this vector, 275 * {@code false} otherwise. 276 * @see #indexOf(Object) 277 * @see #indexOf(Object, int) 278 * @see java.lang.Object#equals 279 */ 280 @Override 281 public boolean contains(Object object) { 282 return indexOf(object, 0) != -1; 283 } 284 285 /** 286 * Searches this vector for all objects in the specified collection. 287 * 288 * @param collection 289 * the collection of objects. 290 * @return {@code true} if all objects in the specified collection are 291 * elements of this vector, {@code false} otherwise. 292 */ 293 @Override 294 public synchronized boolean containsAll(Collection<?> collection) { 295 return super.containsAll(collection); 296 } 297 298 /** 299 * Attempts to copy elements contained by this {@code Vector} into the 300 * corresponding elements of the supplied {@code Object} array. 301 * 302 * @param elements 303 * the {@code Object} array into which the elements of this 304 * vector are copied. 305 * @throws IndexOutOfBoundsException 306 * if {@code elements} is not big enough. 307 * @see #clone 308 */ 309 public synchronized void copyInto(Object[] elements) { 310 System.arraycopy(elementData, 0, elements, 0, elementCount); 311 } 312 313 /** 314 * Returns the element at the specified location in this vector. 315 * 316 * @param location 317 * the index of the element to return in this vector. 318 * @return the element at the specified location. 319 * @throws ArrayIndexOutOfBoundsException 320 * if {@code location < 0 || location >= size()}. 321 * @see #size 322 */ 323 @SuppressWarnings("unchecked") 324 public synchronized E elementAt(int location) { 325 if (location < elementCount) { 326 return (E) elementData[location]; 327 } 328 throw arrayIndexOutOfBoundsException(location, elementCount); 329 } 330 331 /** 332 * Returns an enumeration on the elements of this vector. The results of the 333 * enumeration may be affected if the contents of this vector is modified. 334 * 335 * @return an enumeration of the elements of this vector. 336 * @see #elementAt 337 * @see Enumeration 338 */ 339 public Enumeration<E> elements() { 340 return new Enumeration<E>() { 341 int pos = 0; 342 343 public boolean hasMoreElements() { 344 return pos < elementCount; 345 } 346 347 @SuppressWarnings("unchecked") 348 public E nextElement() { 349 synchronized (Vector.this) { 350 if (pos < elementCount) { 351 return (E) elementData[pos++]; 352 } 353 } 354 throw new NoSuchElementException(); 355 } 356 }; 357 } 358 359 /** 360 * Ensures that this vector can hold the specified number of elements 361 * without growing. 362 * 363 * @param minimumCapacity 364 * the minimum number of elements that this vector will hold 365 * before growing. 366 * @see #capacity 367 */ 368 public synchronized void ensureCapacity(int minimumCapacity) { 369 if (elementData.length < minimumCapacity) { 370 int next = (capacityIncrement <= 0 ? elementData.length 371 : capacityIncrement) 372 + elementData.length; 373 grow(minimumCapacity > next ? minimumCapacity : next); 374 } 375 } 376 377 /** 378 * Compares the specified object to this vector and returns if they are 379 * equal. The object must be a List which contains the same objects in the 380 * same order. 381 * 382 * @param object 383 * the object to compare with this object 384 * @return {@code true} if the specified object is equal to this vector, 385 * {@code false} otherwise. 386 * @see #hashCode 387 */ 388 @Override 389 public synchronized boolean equals(Object object) { 390 if (this == object) { 391 return true; 392 } 393 if (object instanceof List) { 394 List<?> list = (List<?>) object; 395 if (list.size() != elementCount) { 396 return false; 397 } 398 399 int index = 0; 400 Iterator<?> it = list.iterator(); 401 while (it.hasNext()) { 402 Object e1 = elementData[index++], e2 = it.next(); 403 if (!(e1 == null ? e2 == null : e1.equals(e2))) { 404 return false; 405 } 406 } 407 return true; 408 } 409 return false; 410 } 411 412 /** 413 * Returns the first element in this vector. 414 * 415 * @return the element at the first position. 416 * @throws NoSuchElementException 417 * if this vector is empty. 418 * @see #elementAt 419 * @see #lastElement 420 * @see #size 421 */ 422 @SuppressWarnings("unchecked") 423 public synchronized E firstElement() { 424 if (elementCount > 0) { 425 return (E) elementData[0]; 426 } 427 throw new NoSuchElementException(); 428 } 429 430 /** 431 * Returns the element at the specified location in this vector. 432 * 433 * @param location 434 * the index of the element to return in this vector. 435 * @return the element at the specified location. 436 * @throws ArrayIndexOutOfBoundsException 437 * if {@code location < 0 || location >= size()}. 438 * @see #size 439 */ 440 @Override 441 public E get(int location) { 442 return elementAt(location); 443 } 444 445 private void grow(int newCapacity) { 446 E[] newData = newElementArray(newCapacity); 447 // Assumes elementCount is <= newCapacity 448 assert elementCount <= newCapacity; 449 System.arraycopy(elementData, 0, newData, 0, elementCount); 450 elementData = newData; 451 } 452 453 /** 454 * JIT optimization 455 */ 456 private void growByOne() { 457 int adding = 0; 458 if (capacityIncrement <= 0) { 459 if ((adding = elementData.length) == 0) { 460 adding = 1; 461 } 462 } else { 463 adding = capacityIncrement; 464 } 465 466 E[] newData = newElementArray(elementData.length + adding); 467 System.arraycopy(elementData, 0, newData, 0, elementCount); 468 elementData = newData; 469 } 470 471 private void growBy(int required) { 472 int adding = 0; 473 if (capacityIncrement <= 0) { 474 if ((adding = elementData.length) == 0) { 475 adding = required; 476 } 477 while (adding < required) { 478 adding += adding; 479 } 480 } else { 481 adding = (required / capacityIncrement) * capacityIncrement; 482 if (adding < required) { 483 adding += capacityIncrement; 484 } 485 } 486 E[] newData = newElementArray(elementData.length + adding); 487 System.arraycopy(elementData, 0, newData, 0, elementCount); 488 elementData = newData; 489 } 490 491 /** 492 * Returns an integer hash code for the receiver. Objects which are equal 493 * return the same value for this method. 494 * 495 * @return the receiver's hash. 496 * @see #equals 497 */ 498 @Override 499 public synchronized int hashCode() { 500 int result = 1; 501 for (int i = 0; i < elementCount; i++) { 502 result = (31 * result) 503 + (elementData[i] == null ? 0 : elementData[i].hashCode()); 504 } 505 return result; 506 } 507 508 /** 509 * Searches in this vector for the index of the specified object. The search 510 * for the object starts at the beginning and moves towards the end of this 511 * vector. 512 * 513 * @param object 514 * the object to find in this vector. 515 * @return the index in this vector of the specified element, -1 if the 516 * element isn't found. 517 * @see #contains 518 * @see #lastIndexOf(Object) 519 * @see #lastIndexOf(Object, int) 520 */ 521 @Override 522 public int indexOf(Object object) { 523 return indexOf(object, 0); 524 } 525 526 /** 527 * Searches in this vector for the index of the specified object. The search 528 * for the object starts at the specified location and moves towards the end 529 * of this vector. 530 * 531 * @param object 532 * the object to find in this vector. 533 * @param location 534 * the index at which to start searching. 535 * @return the index in this vector of the specified element, -1 if the 536 * element isn't found. 537 * @throws ArrayIndexOutOfBoundsException 538 * if {@code location < 0}. 539 * @see #contains 540 * @see #lastIndexOf(Object) 541 * @see #lastIndexOf(Object, int) 542 */ 543 public synchronized int indexOf(Object object, int location) { 544 if (object != null) { 545 for (int i = location; i < elementCount; i++) { 546 if (object.equals(elementData[i])) { 547 return i; 548 } 549 } 550 } else { 551 for (int i = location; i < elementCount; i++) { 552 if (elementData[i] == null) { 553 return i; 554 } 555 } 556 } 557 return -1; 558 } 559 560 /** 561 * Inserts the specified object into this vector at the specified location. 562 * This object is inserted before any previous element at the specified 563 * location. All elements with an index equal or greater than 564 * {@code location} have their index increased by 1. If the location is 565 * equal to the size of this vector, the object is added at the end. 566 * 567 * @param object 568 * the object to insert in this vector. 569 * @param location 570 * the index at which to insert the element. 571 * @throws ArrayIndexOutOfBoundsException 572 * if {@code location < 0 || location > size()}. 573 * @see #addElement 574 * @see #size 575 */ 576 public synchronized void insertElementAt(E object, int location) { 577 if (location >= 0 && location <= elementCount) { 578 if (elementCount == elementData.length) { 579 growByOne(); 580 } 581 int count = elementCount - location; 582 if (count > 0) { 583 System.arraycopy(elementData, location, elementData, 584 location + 1, count); 585 } 586 elementData[location] = object; 587 elementCount++; 588 modCount++; 589 } else { 590 throw arrayIndexOutOfBoundsException(location, elementCount); 591 } 592 } 593 594 /** 595 * Returns if this vector has no elements, a size of zero. 596 * 597 * @return {@code true} if this vector has no elements, {@code false} 598 * otherwise. 599 * @see #size 600 */ 601 @Override 602 public synchronized boolean isEmpty() { 603 return elementCount == 0; 604 } 605 606 /** 607 * Returns the last element in this vector. 608 * 609 * @return the element at the last position. 610 * @throws NoSuchElementException 611 * if this vector is empty. 612 * @see #elementAt 613 * @see #firstElement 614 * @see #size 615 */ 616 @SuppressWarnings("unchecked") 617 public synchronized E lastElement() { 618 try { 619 return (E) elementData[elementCount - 1]; 620 } catch (IndexOutOfBoundsException e) { 621 throw new NoSuchElementException(); 622 } 623 } 624 625 /** 626 * Searches in this vector for the index of the specified object. The search 627 * for the object starts at the end and moves towards the start of this 628 * vector. 629 * 630 * @param object 631 * the object to find in this vector. 632 * @return the index in this vector of the specified element, -1 if the 633 * element isn't found. 634 * @see #contains 635 * @see #indexOf(Object) 636 * @see #indexOf(Object, int) 637 */ 638 @Override 639 public synchronized int lastIndexOf(Object object) { 640 return lastIndexOf(object, elementCount - 1); 641 } 642 643 /** 644 * Searches in this vector for the index of the specified object. The search 645 * for the object starts at the specified location and moves towards the 646 * start of this vector. 647 * 648 * @param object 649 * the object to find in this vector. 650 * @param location 651 * the index at which to start searching. 652 * @return the index in this vector of the specified element, -1 if the 653 * element isn't found. 654 * @throws ArrayIndexOutOfBoundsException 655 * if {@code location >= size()}. 656 * @see #contains 657 * @see #indexOf(Object) 658 * @see #indexOf(Object, int) 659 */ 660 public synchronized int lastIndexOf(Object object, int location) { 661 if (location < elementCount) { 662 if (object != null) { 663 for (int i = location; i >= 0; i--) { 664 if (object.equals(elementData[i])) { 665 return i; 666 } 667 } 668 } else { 669 for (int i = location; i >= 0; i--) { 670 if (elementData[i] == null) { 671 return i; 672 } 673 } 674 } 675 return -1; 676 } 677 throw arrayIndexOutOfBoundsException(location, elementCount); 678 } 679 680 /** 681 * Removes the object at the specified location from this vector. All 682 * elements with an index bigger than {@code location} have their index 683 * decreased by 1. 684 * 685 * @param location 686 * the index of the object to remove. 687 * @return the removed object. 688 * @throws IndexOutOfBoundsException 689 * if {@code location < 0 || location >= size()}. 690 */ 691 @SuppressWarnings("unchecked") 692 @Override 693 public synchronized E remove(int location) { 694 if (location < elementCount) { 695 E result = (E) elementData[location]; 696 elementCount--; 697 int size = elementCount - location; 698 if (size > 0) { 699 System.arraycopy(elementData, location + 1, elementData, 700 location, size); 701 } 702 elementData[elementCount] = null; 703 modCount++; 704 return result; 705 } 706 throw arrayIndexOutOfBoundsException(location, elementCount); 707 } 708 709 /** 710 * Removes the first occurrence, starting at the beginning and moving 711 * towards the end, of the specified object from this vector. All elements 712 * with an index bigger than the element that gets removed have their index 713 * decreased by 1. 714 * 715 * @param object 716 * the object to remove from this vector. 717 * @return {@code true} if the specified object was found, {@code false} 718 * otherwise. 719 * @see #removeAllElements 720 * @see #removeElementAt 721 * @see #size 722 */ 723 @Override 724 public boolean remove(Object object) { 725 return removeElement(object); 726 } 727 728 /** 729 * Removes all occurrences in this vector of each object in the specified 730 * Collection. 731 * 732 * @param collection 733 * the collection of objects to remove. 734 * @return {@code true} if this vector is modified, {@code false} otherwise. 735 * @see #remove(Object) 736 * @see #contains(Object) 737 */ 738 @Override 739 public synchronized boolean removeAll(Collection<?> collection) { 740 return super.removeAll(collection); 741 } 742 743 /** 744 * Removes all elements from this vector, leaving the size zero and the 745 * capacity unchanged. 746 * 747 * @see #isEmpty 748 * @see #size 749 */ 750 public synchronized void removeAllElements() { 751 for (int i = 0; i < elementCount; i++) { 752 elementData[i] = null; 753 } 754 modCount++; 755 elementCount = 0; 756 } 757 758 /** 759 * Removes the first occurrence, starting at the beginning and moving 760 * towards the end, of the specified object from this vector. All elements 761 * with an index bigger than the element that gets removed have their index 762 * decreased by 1. 763 * 764 * @param object 765 * the object to remove from this vector. 766 * @return {@code true} if the specified object was found, {@code false} 767 * otherwise. 768 * @see #removeAllElements 769 * @see #removeElementAt 770 * @see #size 771 */ 772 public synchronized boolean removeElement(Object object) { 773 int index; 774 if ((index = indexOf(object, 0)) == -1) { 775 return false; 776 } 777 removeElementAt(index); 778 return true; 779 } 780 781 /** 782 * Removes the element found at index position {@code location} from 783 * this {@code Vector}. All elements with an index bigger than 784 * {@code location} have their index decreased by 1. 785 * 786 * @param location 787 * the index of the element to remove. 788 * @throws ArrayIndexOutOfBoundsException 789 * if {@code location < 0 || location >= size()}. 790 * @see #removeElement 791 * @see #removeAllElements 792 * @see #size 793 */ 794 public synchronized void removeElementAt(int location) { 795 if (location >= 0 && location < elementCount) { 796 elementCount--; 797 int size = elementCount - location; 798 if (size > 0) { 799 System.arraycopy(elementData, location + 1, elementData, 800 location, size); 801 } 802 elementData[elementCount] = null; 803 modCount++; 804 } else { 805 throw arrayIndexOutOfBoundsException(location, elementCount); 806 } 807 } 808 809 /** 810 * Removes the objects in the specified range from the start to the, but not 811 * including, end index. All elements with an index bigger than or equal to 812 * {@code end} have their index decreased by {@code end - start}. 813 * 814 * @param start 815 * the index at which to start removing. 816 * @param end 817 * the index one past the end of the range to remove. 818 * @throws IndexOutOfBoundsException 819 * if {@code start < 0, start > end} or 820 * {@code end > size()}. 821 */ 822 @Override 823 protected void removeRange(int start, int end) { 824 if (start >= 0 && start <= end && end <= elementCount) { 825 if (start == end) { 826 return; 827 } 828 if (end != elementCount) { 829 System.arraycopy(elementData, end, elementData, start, 830 elementCount - end); 831 int newCount = elementCount - (end - start); 832 Arrays.fill(elementData, newCount, elementCount, null); 833 elementCount = newCount; 834 } else { 835 Arrays.fill(elementData, start, elementCount, null); 836 elementCount = start; 837 } 838 modCount++; 839 } else { 840 throw new IndexOutOfBoundsException(); 841 } 842 } 843 844 /** 845 * Removes all objects from this vector that are not contained in the 846 * specified collection. 847 * 848 * @param collection 849 * the collection of objects to retain. 850 * @return {@code true} if this vector is modified, {@code false} otherwise. 851 * @see #remove(Object) 852 */ 853 @Override 854 public synchronized boolean retainAll(Collection<?> collection) { 855 return super.retainAll(collection); 856 } 857 858 /** 859 * Replaces the element at the specified location in this vector with the 860 * specified object. 861 * 862 * @param location 863 * the index at which to put the specified object. 864 * @param object 865 * the object to add to this vector. 866 * @return the previous element at the location. 867 * @throws ArrayIndexOutOfBoundsException 868 * if {@code location < 0 || location >= size()}. 869 * @see #size 870 */ 871 @SuppressWarnings("unchecked") 872 @Override 873 public synchronized E set(int location, E object) { 874 if (location < elementCount) { 875 E result = (E) elementData[location]; 876 elementData[location] = object; 877 return result; 878 } 879 throw arrayIndexOutOfBoundsException(location, elementCount); 880 } 881 882 /** 883 * Replaces the element at the specified location in this vector with the 884 * specified object. 885 * 886 * @param object 887 * the object to add to this vector. 888 * @param location 889 * the index at which to put the specified object. 890 * @throws ArrayIndexOutOfBoundsException 891 * if {@code location < 0 || location >= size()}. 892 * @see #size 893 */ 894 public synchronized void setElementAt(E object, int location) { 895 if (location < elementCount) { 896 elementData[location] = object; 897 } else { 898 throw arrayIndexOutOfBoundsException(location, elementCount); 899 } 900 } 901 902 /** 903 * This method was extracted to encourage VM to inline callers. 904 * TODO: when we have a VM that can actually inline, move the test in here too! 905 */ 906 private static ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException(int index, int size) { 907 throw new ArrayIndexOutOfBoundsException(size, index); 908 } 909 910 /** 911 * Sets the size of this vector to the specified size. If there are more 912 * than length elements in this vector, the elements at end are lost. If 913 * there are less than length elements in the vector, the additional 914 * elements contain null. 915 * 916 * @param length 917 * the new size of this vector. 918 * @see #size 919 */ 920 public synchronized void setSize(int length) { 921 if (length == elementCount) { 922 return; 923 } 924 ensureCapacity(length); 925 if (elementCount > length) { 926 Arrays.fill(elementData, length, elementCount, null); 927 } 928 elementCount = length; 929 modCount++; 930 } 931 932 /** 933 * Returns the number of elements in this vector. 934 * 935 * @return the number of elements in this vector. 936 * @see #elementCount 937 * @see #lastElement 938 */ 939 @Override 940 public synchronized int size() { 941 return elementCount; 942 } 943 944 /** 945 * Returns a List of the specified portion of this vector from the start 946 * index to one less than the end index. The returned List is backed by this 947 * vector so changes to one are reflected by the other. 948 * 949 * @param start 950 * the index at which to start the sublist. 951 * @param end 952 * the index one past the end of the sublist. 953 * @return a List of a portion of this vector. 954 * @throws IndexOutOfBoundsException 955 * if {@code start < 0} or {@code end > size()}. 956 * @throws IllegalArgumentException 957 * if {@code start > end}. 958 */ 959 @Override 960 public synchronized List<E> subList(int start, int end) { 961 return new Collections.SynchronizedRandomAccessList<E>(super.subList( 962 start, end), this); 963 } 964 965 /** 966 * Returns a new array containing all elements contained in this vector. 967 * 968 * @return an array of the elements from this vector. 969 */ 970 @Override 971 public synchronized Object[] toArray() { 972 Object[] result = new Object[elementCount]; 973 System.arraycopy(elementData, 0, result, 0, elementCount); 974 return result; 975 } 976 977 /** 978 * Returns an array containing all elements contained in this vector. If the 979 * specified array is large enough to hold the elements, the specified array 980 * is used, otherwise an array of the same type is created. If the specified 981 * array is used and is larger than this vector, the array element following 982 * the collection elements is set to null. 983 * 984 * @param contents 985 * the array to fill. 986 * @return an array of the elements from this vector. 987 * @throws ArrayStoreException 988 * if the type of an element in this vector cannot be 989 * stored in the type of the specified array. 990 */ 991 @Override 992 @SuppressWarnings("unchecked") 993 public synchronized <T> T[] toArray(T[] contents) { 994 if (elementCount > contents.length) { 995 Class<?> ct = contents.getClass().getComponentType(); 996 contents = (T[]) Array.newInstance(ct, elementCount); 997 } 998 System.arraycopy(elementData, 0, contents, 0, elementCount); 999 if (elementCount < contents.length) { 1000 contents[elementCount] = null; 1001 } 1002 return contents; 1003 } 1004 1005 /** 1006 * Returns the string representation of this vector. 1007 * 1008 * @return the string representation of this vector. 1009 * @see #elements 1010 */ 1011 @Override 1012 public synchronized String toString() { 1013 if (elementCount == 0) { 1014 return "[]"; 1015 } 1016 int length = elementCount - 1; 1017 StringBuilder buffer = new StringBuilder(elementCount * 16); 1018 buffer.append('['); 1019 for (int i = 0; i < length; i++) { 1020 if (elementData[i] == this) { 1021 buffer.append("(this Collection)"); 1022 } else { 1023 buffer.append(elementData[i]); 1024 } 1025 buffer.append(", "); 1026 } 1027 if (elementData[length] == this) { 1028 buffer.append("(this Collection)"); 1029 } else { 1030 buffer.append(elementData[length]); 1031 } 1032 buffer.append(']'); 1033 return buffer.toString(); 1034 } 1035 1036 /** 1037 * Sets the capacity of this vector to be the same as the size. 1038 * 1039 * @see #capacity 1040 * @see #ensureCapacity 1041 * @see #size 1042 */ 1043 public synchronized void trimToSize() { 1044 if (elementData.length != elementCount) { 1045 grow(elementCount); 1046 } 1047 } 1048 1049 private synchronized void writeObject(ObjectOutputStream stream) 1050 throws IOException { 1051 stream.defaultWriteObject(); 1052 } 1053 }
ArrayList

1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util; 19 20 import java.io.IOException; 21 import java.io.InvalidObjectException; 22 import java.io.ObjectInputStream; 23 import java.io.ObjectOutputStream; 24 import java.io.Serializable; 25 import java.lang.reflect.Array; 26 import libcore.util.EmptyArray; 27 28 /** 29 * ArrayList is an implementation of {@link List}, backed by an array. 30 * All optional operations including adding, removing, and replacing elements are supported. 31 * 32 * <p>All elements are permitted, including null. 33 * 34 * <p>This class is a good choice as your default {@code List} implementation. 35 * {@link Vector} synchronizes all operations, but not necessarily in a way that's 36 * meaningful to your application: synchronizing each call to {@code get}, for example, is not 37 * equivalent to synchronizing the list and iterating over it (which is probably what you intended). 38 * {@link java.util.concurrent.CopyOnWriteArrayList} is intended for the special case of very high 39 * concurrency, frequent traversals, and very rare mutations. 40 * 41 * @param <E> The element type of this list. 42 * @since 1.2 43 */ 44 public class ArrayList<E> extends AbstractList<E> implements Cloneable, Serializable, RandomAccess { 45 /** 46 * The minimum amount by which the capacity of an ArrayList will increase. 47 * This tuning parameter controls a time-space tradeoff. This value (12) 48 * gives empirically good results and is arguably consistent with the 49 * RI's specified default initial capacity of 10: instead of 10, we start 50 * with 0 (sans allocation) and jump to 12. 51 */ 52 private static final int MIN_CAPACITY_INCREMENT = 12; 53 54 /** 55 * The number of elements in this list. 56 */ 57 int size; 58 59 /** 60 * The elements in this list, followed by nulls. 61 */ 62 transient Object[] array; 63 64 /** 65 * Constructs a new instance of {@code ArrayList} with the specified 66 * initial capacity. 67 * 68 * @param capacity 69 * the initial capacity of this {@code ArrayList}. 70 */ 71 public ArrayList(int capacity) { 72 if (capacity < 0) { 73 throw new IllegalArgumentException(); 74 } 75 array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]); 76 } 77 78 /** 79 * Constructs a new {@code ArrayList} instance with zero initial capacity. 80 */ 81 public ArrayList() { 82 array = EmptyArray.OBJECT; 83 } 84 85 /** 86 * Constructs a new instance of {@code ArrayList} containing the elements of 87 * the specified collection. 88 * 89 * @param collection 90 * the collection of elements to add. 91 */ 92 public ArrayList(Collection<? extends E> collection) { 93 Object[] a = collection.toArray(); 94 if (a.getClass() != Object[].class) { 95 Object[] newArray = new Object[a.length]; 96 System.arraycopy(a, 0, newArray, 0, a.length); 97 a = newArray; 98 } 99 array = a; 100 size = a.length; 101 } 102 103 /** 104 * Adds the specified object at the end of this {@code ArrayList}. 105 * 106 * @param object 107 * the object to add. 108 * @return always true 109 */ 110 @Override public boolean add(E object) { 111 Object[] a = array; 112 int s = size; 113 if (s == a.length) { 114 Object[] newArray = new Object[s + 115 (s < (MIN_CAPACITY_INCREMENT / 2) ? 116 MIN_CAPACITY_INCREMENT : s >> 1)]; 117 System.arraycopy(a, 0, newArray, 0, s); 118 array = a = newArray; 119 } 120 a[s] = object; 121 size = s + 1; 122 modCount++; 123 return true; 124 } 125 126 /** 127 * Inserts the specified object into this {@code ArrayList} at the specified 128 * location. The object is inserted before any previous element at the 129 * specified location. If the location is equal to the size of this 130 * {@code ArrayList}, the object is added at the end. 131 * 132 * @param index 133 * the index at which to insert the object. 134 * @param object 135 * the object to add. 136 * @throws IndexOutOfBoundsException 137 * when {@code location < 0 || > size()} 138 */ 139 @Override public void add(int index, E object) { 140 Object[] a = array; 141 int s = size; 142 if (index > s || index < 0) { 143 throwIndexOutOfBoundsException(index, s); 144 } 145 146 if (s < a.length) { 147 System.arraycopy(a, index, a, index + 1, s - index); 148 } else { 149 // assert s == a.length; 150 Object[] newArray = new Object[newCapacity(s)]; 151 System.arraycopy(a, 0, newArray, 0, index); 152 System.arraycopy(a, index, newArray, index + 1, s - index); 153 array = a = newArray; 154 } 155 a[index] = object; 156 size = s + 1; 157 modCount++; 158 } 159 160 /** 161 * This method controls the growth of ArrayList capacities. It represents 162 * a time-space tradeoff: we don't want to grow lists too frequently 163 * (which wastes time and fragments storage), but we don't want to waste 164 * too much space in unused excess capacity. 165 * 166 * NOTE: This method is inlined into {@link #add(Object)} for performance. 167 * If you change the method, change it there too! 168 */ 169 private static int newCapacity(int currentCapacity) { 170 int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ? 171 MIN_CAPACITY_INCREMENT : currentCapacity >> 1); 172 return currentCapacity + increment; 173 } 174 175 /** 176 * Adds the objects in the specified collection to this {@code ArrayList}. 177 * 178 * @param collection 179 * the collection of objects. 180 * @return {@code true} if this {@code ArrayList} is modified, {@code false} 181 * otherwise. 182 */ 183 @Override public boolean addAll(Collection<? extends E> collection) { 184 Object[] newPart = collection.toArray(); 185 int newPartSize = newPart.length; 186 if (newPartSize == 0) { 187 return false; 188 } 189 Object[] a = array; 190 int s = size; 191 int newSize = s + newPartSize; // If add overflows, arraycopy will fail 192 if (newSize > a.length) { 193 int newCapacity = newCapacity(newSize - 1); // ~33% growth room 194 Object[] newArray = new Object[newCapacity]; 195 System.arraycopy(a, 0, newArray, 0, s); 196 array = a = newArray; 197 } 198 System.arraycopy(newPart, 0, a, s, newPartSize); 199 size = newSize; 200 modCount++; 201 return true; 202 } 203 204 /** 205 * Inserts the objects in the specified collection at the specified location 206 * in this List. The objects are added in the order they are returned from 207 * the collection's iterator. 208 * 209 * @param index 210 * the index at which to insert. 211 * @param collection 212 * the collection of objects. 213 * @return {@code true} if this {@code ArrayList} is modified, {@code false} 214 * otherwise. 215 * @throws IndexOutOfBoundsException 216 * when {@code location < 0 || > size()} 217 */ 218 @Override 219 public boolean addAll(int index, Collection<? extends E> collection) { 220 int s = size; 221 if (index > s || index < 0) { 222 throwIndexOutOfBoundsException(index, s); 223 } 224 Object[] newPart = collection.toArray(); 225 int newPartSize = newPart.length; 226 if (newPartSize == 0) { 227 return false; 228 } 229 Object[] a = array; 230 int newSize = s + newPartSize; // If add overflows, arraycopy will fail 231 if (newSize <= a.length) { 232 System.arraycopy(a, index, a, index + newPartSize, s - index); 233 } else { 234 int newCapacity = newCapacity(newSize - 1); // ~33% growth room 235 Object[] newArray = new Object[newCapacity]; 236 System.arraycopy(a, 0, newArray, 0, index); 237 System.arraycopy(a, index, newArray, index + newPartSize, s-index); 238 array = a = newArray; 239 } 240 System.arraycopy(newPart, 0, a, index, newPartSize); 241 size = newSize; 242 modCount++; 243 return true; 244 } 245 246 /** 247 * This method was extracted to encourage VM to inline callers. 248 * TODO: when we have a VM that can actually inline, move the test in here too! 249 */ 250 static IndexOutOfBoundsException throwIndexOutOfBoundsException(int index, int size) { 251 throw new IndexOutOfBoundsException("Invalid index " + index + ", size is " + size); 252 } 253 254 /** 255 * Removes all elements from this {@code ArrayList}, leaving it empty. 256 * 257 * @see #isEmpty 258 * @see #size 259 */ 260 @Override public void clear() { 261 if (size != 0) { 262 Arrays.fill(array, 0, size, null); 263 size = 0; 264 modCount++; 265 } 266 } 267 268 /** 269 * Returns a new {@code ArrayList} with the same elements, the same size and 270 * the same capacity as this {@code ArrayList}. 271 * 272 * @return a shallow copy of this {@code ArrayList} 273 * @see java.lang.Cloneable 274 */ 275 @Override public Object clone() { 276 try { 277 ArrayList<?> result = (ArrayList<?>) super.clone(); 278 result.array = array.clone(); 279 return result; 280 } catch (CloneNotSupportedException e) { 281 throw new AssertionError(); 282 } 283 } 284 285 /** 286 * Ensures that after this operation the {@code ArrayList} can hold the 287 * specified number of elements without further growing. 288 * 289 * @param minimumCapacity 290 * the minimum capacity asked for. 291 */ 292 public void ensureCapacity(int minimumCapacity) { 293 Object[] a = array; 294 if (a.length < minimumCapacity) { 295 Object[] newArray = new Object[minimumCapacity]; 296 System.arraycopy(a, 0, newArray, 0, size); 297 array = newArray; 298 modCount++; 299 } 300 } 301 302 @SuppressWarnings("unchecked") @Override public E get(int index) { 303 if (index >= size) { 304 throwIndexOutOfBoundsException(index, size); 305 } 306 return (E) array[index]; 307 } 308 309 /** 310 * Returns the number of elements in this {@code ArrayList}. 311 * 312 * @return the number of elements in this {@code ArrayList}. 313 */ 314 @Override public int size() { 315 return size; 316 } 317 318 @Override public boolean isEmpty() { 319 return size == 0; 320 } 321 322 /** 323 * Searches this {@code ArrayList} for the specified object. 324 * 325 * @param object 326 * the object to search for. 327 * @return {@code true} if {@code object} is an element of this 328 * {@code ArrayList}, {@code false} otherwise 329 */ 330 @Override public boolean contains(Object object) { 331 Object[] a = array; 332 int s = size; 333 if (object != null) { 334 for (int i = 0; i < s; i++) { 335 if (object.equals(a[i])) { 336 return true; 337 } 338 } 339 } else { 340 for (int i = 0; i < s; i++) { 341 if (a[i] == null) { 342 return true; 343 } 344 } 345 } 346 return false; 347 } 348 349 @Override public int indexOf(Object object) { 350 Object[] a = array; 351 int s = size; 352 if (object != null) { 353 for (int i = 0; i < s; i++) { 354 if (object.equals(a[i])) { 355 return i; 356 } 357 } 358 } else { 359 for (int i = 0; i < s; i++) { 360 if (a[i] == null) { 361 return i; 362 } 363 } 364 } 365 return -1; 366 } 367 368 @Override public int lastIndexOf(Object object) { 369 Object[] a = array; 370 if (object != null) { 371 for (int i = size - 1; i >= 0; i--) { 372 if (object.equals(a[i])) { 373 return i; 374 } 375 } 376 } else { 377 for (int i = size - 1; i >= 0; i--) { 378 if (a[i] == null) { 379 return i; 380 } 381 } 382 } 383 return -1; 384 } 385 386 /** 387 * Removes the object at the specified location from this list. 388 * 389 * @param index 390 * the index of the object to remove. 391 * @return the removed object. 392 * @throws IndexOutOfBoundsException 393 * when {@code location < 0 || >= size()} 394 */ 395 @Override public E remove(int index) { 396 Object[] a = array; 397 int s = size; 398 if (index >= s) { 399 throwIndexOutOfBoundsException(index, s); 400 } 401 @SuppressWarnings("unchecked") E result = (E) a[index]; 402 System.arraycopy(a, index + 1, a, index, --s - index); 403 a[s] = null; // Prevent memory leak 404 size = s; 405 modCount++; 406 return result; 407 } 408 409 @Override public boolean remove(Object object) { 410 Object[] a = array; 411 int s = size; 412 if (object != null) { 413 for (int i = 0; i < s; i++) { 414 if (object.equals(a[i])) { 415 System.arraycopy(a, i + 1, a, i, --s - i); 416 a[s] = null; // Prevent memory leak 417 size = s; 418 modCount++; 419 return true; 420 } 421 } 422 } else { 423 for (int i = 0; i < s; i++) { 424 if (a[i] == null) { 425 System.arraycopy(a, i + 1, a, i, --s - i); 426 a[s] = null; // Prevent memory leak 427 size = s; 428 modCount++; 429 return true; 430 } 431 } 432 } 433 return false; 434 } 435 436 @Override protected void removeRange(int fromIndex, int toIndex) { 437 if (fromIndex == toIndex) { 438 return; 439 } 440 Object[] a = array; 441 int s = size; 442 if (fromIndex >= s) { 443 throw new IndexOutOfBoundsException("fromIndex " + fromIndex 444 + " >= size " + size); 445 } 446 if (toIndex > s) { 447 throw new IndexOutOfBoundsException("toIndex " + toIndex 448 + " > size " + size); 449 } 450 if (fromIndex > toIndex) { 451 throw new IndexOutOfBoundsException("fromIndex " + fromIndex 452 + " > toIndex " + toIndex); 453 } 454 455 System.arraycopy(a, toIndex, a, fromIndex, s - toIndex); 456 int rangeSize = toIndex - fromIndex; 457 Arrays.fill(a, s - rangeSize, s, null); 458 size = s - rangeSize; 459 modCount++; 460 } 461 462 /** 463 * Replaces the element at the specified location in this {@code ArrayList} 464 * with the specified object. 465 * 466 * @param index 467 * the index at which to put the specified object. 468 * @param object 469 * the object to add. 470 * @return the previous element at the index. 471 * @throws IndexOutOfBoundsException 472 * when {@code location < 0 || >= size()} 473 */ 474 @Override public E set(int index, E object) { 475 Object[] a = array; 476 if (index >= size) { 477 throwIndexOutOfBoundsException(index, size); 478 } 479 @SuppressWarnings("unchecked") E result = (E) a[index]; 480 a[index] = object; 481 return result; 482 } 483 484 /** 485 * Returns a new array containing all elements contained in this 486 * {@code ArrayList}. 487 * 488 * @return an array of the elements from this {@code ArrayList} 489 */ 490 @Override public Object[] toArray() { 491 int s = size; 492 Object[] result = new Object[s]; 493 System.arraycopy(array, 0, result, 0, s); 494 return result; 495 } 496 497 /** 498 * Returns an array containing all elements contained in this 499 * {@code ArrayList}. If the specified array is large enough to hold the 500 * elements, the specified array is used, otherwise an array of the same 501 * type is created. If the specified array is used and is larger than this 502 * {@code ArrayList}, the array element following the collection elements 503 * is set to null. 504 * 505 * @param contents 506 * the array. 507 * @return an array of the elements from this {@code ArrayList}. 508 * @throws ArrayStoreException 509 * when the type of an element in this {@code ArrayList} cannot 510 * be stored in the type of the specified array. 511 */ 512 @Override public <T> T[] toArray(T[] contents) { 513 int s = size; 514 if (contents.length < s) { 515 @SuppressWarnings("unchecked") T[] newArray 516 = (T[]) Array.newInstance(contents.getClass().getComponentType(), s); 517 contents = newArray; 518 } 519 System.arraycopy(this.array, 0, contents, 0, s); 520 if (contents.length > s) { 521 contents[s] = null; 522 } 523 return contents; 524 } 525 526 /** 527 * Sets the capacity of this {@code ArrayList} to be the same as the current 528 * size. 529 * 530 * @see #size 531 */ 532 public void trimToSize() { 533 int s = size; 534 if (s == array.length) { 535 return; 536 } 537 if (s == 0) { 538 array = EmptyArray.OBJECT; 539 } else { 540 Object[] newArray = new Object[s]; 541 System.arraycopy(array, 0, newArray, 0, s); 542 array = newArray; 543 } 544 modCount++; 545 } 546 547 @Override public Iterator<E> iterator() { 548 return new ArrayListIterator(); 549 } 550 551 private class ArrayListIterator implements Iterator<E> { 552 /** Number of elements remaining in this iteration */ 553 private int remaining = size; 554 555 /** Index of element that remove() would remove, or -1 if no such elt */ 556 private int removalIndex = -1; 557 558 /** The expected modCount value */ 559 private int expectedModCount = modCount; 560 561 public boolean hasNext() { 562 return remaining != 0; 563 } 564 565 @SuppressWarnings("unchecked") public E next() { 566 ArrayList<E> ourList = ArrayList.this; 567 int rem = remaining; 568 if (ourList.modCount != expectedModCount) { 569 throw new ConcurrentModificationException(); 570 } 571 if (rem == 0) { 572 throw new NoSuchElementException(); 573 } 574 remaining = rem - 1; 575 return (E) ourList.array[removalIndex = ourList.size - rem]; 576 } 577 578 public void remove() { 579 Object[] a = array; 580 int removalIdx = removalIndex; 581 if (modCount != expectedModCount) { 582 throw new ConcurrentModificationException(); 583 } 584 if (removalIdx < 0) { 585 throw new IllegalStateException(); 586 } 587 System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining); 588 a[--size] = null; // Prevent memory leak 589 removalIndex = -1; 590 expectedModCount = ++modCount; 591 } 592 } 593 594 @Override public int hashCode() { 595 Object[] a = array; 596 int hashCode = 1; 597 for (int i = 0, s = size; i < s; i++) { 598 Object e = a[i]; 599 hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); 600 } 601 return hashCode; 602 } 603 604 @Override public boolean equals(Object o) { 605 if (o == this) { 606 return true; 607 } 608 if (!(o instanceof List)) { 609 return false; 610 } 611 List<?> that = (List<?>) o; 612 int s = size; 613 if (that.size() != s) { 614 return false; 615 } 616 Object[] a = array; 617 if (that instanceof RandomAccess) { 618 for (int i = 0; i < s; i++) { 619 Object eThis = a[i]; 620 Object ethat = that.get(i); 621 if (eThis == null ? ethat != null : !eThis.equals(ethat)) { 622 return false; 623 } 624 } 625 } else { // Argument list is not random access; use its iterator 626 Iterator<?> it = that.iterator(); 627 for (int i = 0; i < s; i++) { 628 Object eThis = a[i]; 629 Object eThat = it.next(); 630 if (eThis == null ? eThat != null : !eThis.equals(eThat)) { 631 return false; 632 } 633 } 634 } 635 return true; 636 } 637 638 private static final long serialVersionUID = 8683452581122892189L; 639 640 private void writeObject(ObjectOutputStream stream) throws IOException { 641 stream.defaultWriteObject(); 642 stream.writeInt(array.length); 643 for (int i = 0; i < size; i++) { 644 stream.writeObject(array[i]); 645 } 646 } 647 648 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 649 stream.defaultReadObject(); 650 int cap = stream.readInt(); 651 if (cap < size) { 652 throw new InvalidObjectException( 653 "Capacity: " + cap + " < size: " + size); 654 } 655 array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]); 656 for (int i = 0; i < size; i++) { 657 array[i] = stream.readObject(); 658 } 659 } 660 }

1 package java.util; 2 public abstract class Dictionary<K, V> { 3 public Dictionary() { 4 } 5 public abstract Enumeration<V> elements(); 6 public abstract V get(Object key); 7 public abstract boolean isEmpty(); 8 public abstract Enumeration<K> keys(); 9 public abstract V put(K key, V value); 10 public abstract V remove(Object key); 11 public abstract int size(); 12 }
Map Interface

1 package java.util; 2 3 public interface Map<K,V> { 4 5 /** 6 * {@code Map.Entry} is a key/value mapping contained in a {@code Map}. 7 */ 8 public static interface Entry<K,V> { 9 public boolean equals(Object object); 10 public K getKey(); 11 public V getValue(); 12 public int hashCode(); 13 public V setValue(V object); 14 }; 15 public void clear(); 16 public boolean containsKey(Object key); 17 public boolean containsValue(Object value); 18 public Set<Map.Entry<K,V>> entrySet(); 19 public boolean equals(Object object); 20 public V get(Object key); 21 public int hashCode(); 22 public boolean isEmpty(); 23 public Set<K> keySet(); 24 public V put(K key, V value); 25 public void putAll(Map<? extends K,? extends V> map); 26 public V remove(Object key); 27 public int size(); 28 public Collection<V> values(); 29 }
SortedMap Interface

1 package java.util; 2 3 public interface SortedMap<K,V> extends Map<K,V> { 4 5 public Comparator<? super K> comparator(); 6 public K firstKey(); 7 public SortedMap<K,V> headMap(K endKey); 8 public K lastKey(); 9 public SortedMap<K,V> subMap(K startKey, K endKey); 10 public SortedMap<K,V> tailMap(K startKey); 11 }
AbstractMap

1 package java.util; 2 import java.io.Serializable; 3 public abstract class AbstractMap<K, V> implements Map<K, V> { 4 5 // Lazily initialized key set. 6 Set<K> keySet; 7 Collection<V> valuesCollection; 8 public static class SimpleImmutableEntry<K, V> 9 implements Map.Entry<K, V>, Serializable { 10 private static final long serialVersionUID = 7138329143949025153L; 11 12 private final K key; 13 private final V value; 14 15 public SimpleImmutableEntry(K theKey, V theValue) { 16 key = theKey; 17 value = theValue; 18 } 19 public SimpleImmutableEntry(Map.Entry<? extends K, ? extends V> copyFrom) { 20 key = copyFrom.getKey(); 21 value = copyFrom.getValue(); 22 } 23 public K getKey() { 24 return key; 25 } 26 public V getValue() { 27 return value; 28 } 29 public V setValue(V object) { 30 throw new UnsupportedOperationException(); 31 } 32 @Override 33 public boolean equals(Object object) { 34 if (this == object) { 35 return true; 36 } 37 if (object instanceof Map.Entry) { 38 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object; 39 return (key == null ? entry.getKey() == null : key.equals(entry 40 .getKey())) 41 && (value == null ? entry.getValue() == null : value 42 .equals(entry.getValue())); 43 } 44 return false; 45 } 46 @Override public int hashCode() { 47 return (key == null ? 0 : key.hashCode()) 48 ^ (value == null ? 0 : value.hashCode()); 49 } 50 @Override public String toString() { 51 return key + "=" + value; 52 } 53 } 54 public static class SimpleEntry<K, V> implements Map.Entry<K, V>, Serializable { 55 private static final long serialVersionUID = -8499721149061103585L; 56 57 private final K key; 58 private V value; 59 60 public SimpleEntry(K theKey, V theValue) { 61 key = theKey; 62 value = theValue; 63 } 64 public SimpleEntry(Map.Entry<? extends K, ? extends V> copyFrom) { 65 key = copyFrom.getKey(); 66 value = copyFrom.getValue(); 67 } 68 public K getKey() { 69 return key; 70 } 71 public V getValue() { 72 return value; 73 } 74 public V setValue(V object) { 75 V result = value; 76 value = object; 77 return result; 78 } 79 @Override 80 public boolean equals(Object object) { 81 if (this == object) { 82 return true; 83 } 84 if (object instanceof Map.Entry) { 85 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object; 86 return (key == null ? entry.getKey() == null : key.equals(entry 87 .getKey())) 88 && (value == null ? entry.getValue() == null : value 89 .equals(entry.getValue())); 90 } 91 return false; 92 } 93 @Override 94 public int hashCode() { 95 return (key == null ? 0 : key.hashCode()) 96 ^ (value == null ? 0 : value.hashCode()); 97 } 98 @Override 99 public String toString() { 100 return key + "=" + value; 101 } 102 } 103 protected AbstractMap() { 104 } 105 106 public void clear() { 107 entrySet().clear(); 108 } 109 110 public boolean containsKey(Object key) { 111 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 112 if (key != null) { 113 while (it.hasNext()) { 114 if (key.equals(it.next().getKey())) { 115 return true; 116 } 117 } 118 } else { 119 while (it.hasNext()) { 120 if (it.next().getKey() == null) { 121 return true; 122 } 123 } 124 } 125 return false; 126 } 127 public boolean containsValue(Object value) { 128 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 129 if (value != null) { 130 while (it.hasNext()) { 131 if (value.equals(it.next().getValue())) { 132 return true; 133 } 134 } 135 } else { 136 while (it.hasNext()) { 137 if (it.next().getValue() == null) { 138 return true; 139 } 140 } 141 } 142 return false; 143 } 144 145 public abstract Set<Map.Entry<K, V>> entrySet(); 146 @Override 147 public boolean equals(Object object) { 148 if (this == object) { 149 return true; 150 } 151 if (object instanceof Map) { 152 Map<?, ?> map = (Map<?, ?>) object; 153 if (size() != map.size()) { 154 return false; 155 } 156 157 try { 158 for (Entry<K, V> entry : entrySet()) { 159 K key = entry.getKey(); 160 V mine = entry.getValue(); 161 Object theirs = map.get(key); 162 if (mine == null) { 163 if (theirs != null || !map.containsKey(key)) { 164 return false; 165 } 166 } else if (!mine.equals(theirs)) { 167 return false; 168 } 169 } 170 } catch (NullPointerException ignored) { 171 return false; 172 } catch (ClassCastException ignored) { 173 return false; 174 } 175 return true; 176 } 177 return false; 178 } 179 public V get(Object key) { 180 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 181 if (key != null) { 182 while (it.hasNext()) { 183 Map.Entry<K, V> entry = it.next(); 184 if (key.equals(entry.getKey())) { 185 return entry.getValue(); 186 } 187 } 188 } else { 189 while (it.hasNext()) { 190 Map.Entry<K, V> entry = it.next(); 191 if (entry.getKey() == null) { 192 return entry.getValue(); 193 } 194 } 195 } 196 return null; 197 } 198 @Override public int hashCode() { 199 int result = 0; 200 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 201 while (it.hasNext()) { 202 result += it.next().hashCode(); 203 } 204 return result; 205 } 206 public boolean isEmpty() { 207 return size() == 0; 208 } 209 public Set<K> keySet() { 210 if (keySet == null) { 211 keySet = new AbstractSet<K>() { 212 @Override public boolean contains(Object object) { 213 return containsKey(object); 214 } 215 216 @Override public int size() { 217 return AbstractMap.this.size(); 218 } 219 220 @Override public Iterator<K> iterator() { 221 return new Iterator<K>() { 222 Iterator<Map.Entry<K, V>> setIterator = entrySet().iterator(); 223 224 public boolean hasNext() { 225 return setIterator.hasNext(); 226 } 227 228 public K next() { 229 return setIterator.next().getKey(); 230 } 231 232 public void remove() { 233 setIterator.remove(); 234 } 235 }; 236 } 237 }; 238 } 239 return keySet; 240 } 241 public V put(K key, V value) { 242 throw new UnsupportedOperationException(); 243 } 244 public void putAll(Map<? extends K, ? extends V> map) { 245 for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { 246 put(entry.getKey(), entry.getValue()); 247 } 248 } 249 public V remove(Object key) { 250 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 251 if (key != null) { 252 while (it.hasNext()) { 253 Map.Entry<K, V> entry = it.next(); 254 if (key.equals(entry.getKey())) { 255 it.remove(); 256 return entry.getValue(); 257 } 258 } 259 } else { 260 while (it.hasNext()) { 261 Map.Entry<K, V> entry = it.next(); 262 if (entry.getKey() == null) { 263 it.remove(); 264 return entry.getValue(); 265 } 266 } 267 } 268 return null; 269 } 270 public int size() { 271 return entrySet().size(); 272 } 273 @Override public String toString() { 274 if (isEmpty()) { 275 return "{}"; 276 } 277 278 StringBuilder buffer = new StringBuilder(size() * 28); 279 buffer.append('{'); 280 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 281 while (it.hasNext()) { 282 Map.Entry<K, V> entry = it.next(); 283 Object key = entry.getKey(); 284 if (key != this) { 285 buffer.append(key); 286 } else { 287 buffer.append("(this Map)"); 288 } 289 buffer.append('='); 290 Object value = entry.getValue(); 291 if (value != this) { 292 buffer.append(value); 293 } else { 294 buffer.append("(this Map)"); 295 } 296 if (it.hasNext()) { 297 buffer.append(", "); 298 } 299 } 300 buffer.append('}'); 301 return buffer.toString(); 302 } 303 public Collection<V> values() { 304 if (valuesCollection == null) { 305 valuesCollection = new AbstractCollection<V>() { 306 @Override public int size() { 307 return AbstractMap.this.size(); 308 } 309 310 @Override public boolean contains(Object object) { 311 return containsValue(object); 312 } 313 314 @Override public Iterator<V> iterator() { 315 return new Iterator<V>() { 316 Iterator<Map.Entry<K, V>> setIterator = entrySet().iterator(); 317 318 public boolean hasNext() { 319 return setIterator.hasNext(); 320 } 321 322 public V next() { 323 return setIterator.next().getValue(); 324 } 325 326 public void remove() { 327 setIterator.remove(); 328 } 329 }; 330 } 331 }; 332 } 333 return valuesCollection; 334 } 335 @SuppressWarnings("unchecked") 336 @Override 337 protected Object clone() throws CloneNotSupportedException { 338 AbstractMap<K, V> result = (AbstractMap<K, V>) super.clone(); 339 result.keySet = null; 340 result.valuesCollection = null; 341 return result; 342 } 343 }
HashMap

1 package java.util; 2 import java.io.IOException; 3 import java.io.InvalidObjectException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 import java.io.ObjectStreamField; 7 import java.io.Serializable; 8 import java.util.Map.Entry; 9 10 import libcore.util.Objects; 11 12 /** 13 * HashMap is an implementation of {@link Map}. All optional operations are supported. 14 * 15 * <p>All elements are permitted as keys or values, including null. 16 * 17 * <p>Note that the iteration order for HashMap is non-deterministic. If you want 18 * deterministic iteration, use {@link LinkedHashMap}. 19 * 20 * <p>Note: the implementation of {@code HashMap} is not synchronized. 21 * If one thread of several threads accessing an instance modifies the map 22 * structurally, access to the map needs to be synchronized. A structural 23 * modification is an operation that adds or removes an entry. Changes in 24 * the value of an entry are not structural changes. 25 * 26 * <p>The {@code Iterator} created by calling the {@code iterator} method 27 * may throw a {@code ConcurrentModificationException} if the map is structurally 28 * changed while an iterator is used to iterate over the elements. Only the 29 * {@code remove} method that is provided by the iterator allows for removal of 30 * elements during iteration. It is not possible to guarantee that this 31 * mechanism works in all cases of unsynchronized concurrent modification. It 32 * should only be used for debugging purposes. 33 * 34 * @param <K> the type of keys maintained by this map 35 * @param <V> the type of mapped values 36 */ 37 public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable { 38 /** 39 * Min capacity (other than zero) for a HashMap. Must be a power of two 40 * greater than 1 (and less than 1 << 30). 41 */ 42 private static final int MINIMUM_CAPACITY = 4; 43 44 /** 45 * Max capacity for a HashMap. Must be a power of two >= MINIMUM_CAPACITY. 46 */ 47 private static final int MAXIMUM_CAPACITY = 1 << 30; 48 49 /** 50 * An empty table shared by all zero-capacity maps (typically from default 51 * constructor). It is never written to, and replaced on first put. Its size 52 * is set to half the minimum, so that the first resize will create a 53 * minimum-sized table. 54 */ 55 private static final Entry[] EMPTY_TABLE 56 = new HashMapEntry[MINIMUM_CAPACITY >>> 1]; 57 58 /** 59 * The default load factor. Note that this implementation ignores the 60 * load factor, but cannot do away with it entirely because it's 61 * mentioned in the API. 62 * 63 * <p>Note that this constant has no impact on the behavior of the program, 64 * but it is emitted as part of the serialized form. The load factor of 65 * .75 is hardwired into the program, which uses cheap shifts in place of 66 * expensive division. 67 */ 68 static final float DEFAULT_LOAD_FACTOR = .75F; 69 70 /** 71 * The hash table. If this hash map contains a mapping for null, it is 72 * not represented this hash table. 73 */ 74 transient HashMapEntry<K, V>[] table; 75 76 /** 77 * The entry representing the null key, or null if there's no such mapping. 78 */ 79 transient HashMapEntry<K, V> entryForNullKey; 80 81 /** 82 * The number of mappings in this hash map. 83 */ 84 transient int size; 85 86 /** 87 * Incremented by "structural modifications" to allow (best effort) 88 * detection of concurrent modification. 89 */ 90 transient int modCount; 91 92 /** 93 * The table is rehashed when its size exceeds this threshold. 94 * The value of this field is generally .75 * capacity, except when 95 * the capacity is zero, as described in the EMPTY_TABLE declaration 96 * above. 97 */ 98 private transient int threshold; 99 100 // Views - lazily initialized 101 private transient Set<K> keySet; 102 private transient Set<Entry<K, V>> entrySet; 103 private transient Collection<V> values; 104 105 /** 106 * Constructs a new empty {@code HashMap} instance. 107 */ 108 @SuppressWarnings("unchecked") 109 public HashMap() { 110 table = (HashMapEntry<K, V>[]) EMPTY_TABLE; 111 threshold = -1; // Forces first put invocation to replace EMPTY_TABLE 112 } 113 114 /** 115 * Constructs a new {@code HashMap} instance with the specified capacity. 116 * 117 * @param capacity 118 * the initial capacity of this hash map. 119 * @throws IllegalArgumentException 120 * when the capacity is less than zero. 121 */ 122 public HashMap(int capacity) { 123 if (capacity < 0) { 124 throw new IllegalArgumentException("Capacity: " + capacity); 125 } 126 127 if (capacity == 0) { 128 @SuppressWarnings("unchecked") 129 HashMapEntry<K, V>[] tab = (HashMapEntry<K, V>[]) EMPTY_TABLE; 130 table = tab; 131 threshold = -1; // Forces first put() to replace EMPTY_TABLE 132 return; 133 } 134 135 if (capacity < MINIMUM_CAPACITY) { 136 capacity = MINIMUM_CAPACITY; 137 } else if (capacity > MAXIMUM_CAPACITY) { 138 capacity = MAXIMUM_CAPACITY; 139 } else { 140 capacity = roundUpToPowerOfTwo(capacity); 141 } 142 makeTable(capacity); 143 } 144 145 /** 146 * Constructs a new {@code HashMap} instance with the specified capacity and 147 * load factor. 148 * 149 * @param capacity 150 * the initial capacity of this hash map. 151 * @param loadFactor 152 * the initial load factor. 153 * @throws IllegalArgumentException 154 * when the capacity is less than zero or the load factor is 155 * less or equal to zero or NaN. 156 */ 157 public HashMap(int capacity, float loadFactor) { 158 this(capacity); 159 160 if (loadFactor <= 0 || Float.isNaN(loadFactor)) { 161 throw new IllegalArgumentException("Load factor: " + loadFactor); 162 } 163 164 /* 165 * Note that this implementation ignores loadFactor; it always uses 166 * a load factor of 3/4. This simplifies the code and generally 167 * improves performance. 168 */ 169 } 170 171 /** 172 * Constructs a new {@code HashMap} instance containing the mappings from 173 * the specified map. 174 * 175 * @param map 176 * the mappings to add. 177 */ 178 public HashMap(Map<? extends K, ? extends V> map) { 179 this(capacityForInitSize(map.size())); 180 constructorPutAll(map); 181 } 182 183 /** 184 * Inserts all of the elements of map into this HashMap in a manner 185 * suitable for use by constructors and pseudo-constructors (i.e., clone, 186 * readObject). Also used by LinkedHashMap. 187 */ 188 final void constructorPutAll(Map<? extends K, ? extends V> map) { 189 for (Entry<? extends K, ? extends V> e : map.entrySet()) { 190 constructorPut(e.getKey(), e.getValue()); 191 } 192 } 193 194 /** 195 * Returns an appropriate capacity for the specified initial size. Does 196 * not round the result up to a power of two; the caller must do this! 197 * The returned value will be between 0 and MAXIMUM_CAPACITY (inclusive). 198 */ 199 static int capacityForInitSize(int size) { 200 int result = (size >> 1) + size; // Multiply by 3/2 to allow for growth 201 202 // boolean expr is equivalent to result >= 0 && result<MAXIMUM_CAPACITY 203 return (result & ~(MAXIMUM_CAPACITY-1))==0 ? result : MAXIMUM_CAPACITY; 204 } 205 206 /** 207 * Returns a shallow copy of this map. 208 * 209 * @return a shallow copy of this map. 210 */ 211 @SuppressWarnings("unchecked") 212 @Override public Object clone() { 213 /* 214 * This could be made more efficient. It unnecessarily hashes all of 215 * the elements in the map. 216 */ 217 HashMap<K, V> result; 218 try { 219 result = (HashMap<K, V>) super.clone(); 220 } catch (CloneNotSupportedException e) { 221 throw new AssertionError(e); 222 } 223 224 // Restore clone to empty state, retaining our capacity and threshold 225 result.makeTable(table.length); 226 result.entryForNullKey = null; 227 result.size = 0; 228 result.keySet = null; 229 result.entrySet = null; 230 result.values = null; 231 232 result.init(); // Give subclass a chance to initialize itself 233 result.constructorPutAll(this); // Calls method overridden in subclass!! 234 return result; 235 } 236 237 /** 238 * This method is called from the pseudo-constructors (clone and readObject) 239 * prior to invoking constructorPut/constructorPutAll, which invoke the 240 * overridden constructorNewEntry method. Normally it is a VERY bad idea to 241 * invoke an overridden method from a pseudo-constructor (Effective Java 242 * Item 17). In this case it is unavoidable, and the init method provides a 243 * workaround. 244 */ 245 void init() { } 246 247 /** 248 * Returns whether this map is empty. 249 * 250 * @return {@code true} if this map has no elements, {@code false} 251 * otherwise. 252 * @see #size() 253 */ 254 @Override public boolean isEmpty() { 255 return size == 0; 256 } 257 258 /** 259 * Returns the number of elements in this map. 260 * 261 * @return the number of elements in this map. 262 */ 263 @Override public int size() { 264 return size; 265 } 266 267 /** 268 * Returns the value of the mapping with the specified key. 269 * 270 * @param key 271 * the key. 272 * @return the value of the mapping with the specified key, or {@code null} 273 * if no mapping for the specified key is found. 274 */ 275 public V get(Object key) { 276 if (key == null) { 277 HashMapEntry<K, V> e = entryForNullKey; 278 return e == null ? null : e.value; 279 } 280 281 // Doug Lea's supplemental secondaryHash function (inlined) 282 int hash = key.hashCode(); 283 hash ^= (hash >>> 20) ^ (hash >>> 12); 284 hash ^= (hash >>> 7) ^ (hash >>> 4); 285 286 HashMapEntry<K, V>[] tab = table; 287 for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; e != null; e = e.next) 288 { 289 K eKey = e.key; 290 if (eKey == key || (e.hash == hash && key.equals(eKey))) { 291 return e.value; 292 } 293 } 294 return null; 295 } 296 297 /** 298 * Returns whether this map contains the specified key. 299 * 300 * @param key 301 * the key to search for. 302 * @return {@code true} if this map contains the specified key, 303 * {@code false} otherwise. 304 */ 305 @Override public boolean containsKey(Object key) { 306 if (key == null) { 307 return entryForNullKey != null; 308 } 309 310 // Doug Lea's supplemental secondaryHash function (inlined) 311 int hash = key.hashCode(); 312 hash ^= (hash >>> 20) ^ (hash >>> 12); 313 hash ^= (hash >>> 7) ^ (hash >>> 4); 314 315 HashMapEntry<K, V>[] tab = table; 316 for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; 317 e != null; e = e.next) { 318 K eKey = e.key; 319 if (eKey == key || (e.hash == hash && key.equals(eKey))) { 320 return true; 321 } 322 } 323 return false; 324 } 325 326 /** 327 * Returns whether this map contains the specified value. 328 * 329 * @param value 330 * the value to search for. 331 * @return {@code true} if this map contains the specified value, 332 * {@code false} otherwise. 333 */ 334 @Override public boolean containsValue(Object value) { 335 HashMapEntry[] tab = table; 336 int len = tab.length; 337 if (value == null) { 338 for (int i = 0; i < len; i++) { 339 for (HashMapEntry e = tab[i]; e != null; e = e.next) { 340 if (e.value == null) { 341 return true; 342 } 343 } 344 } 345 return entryForNullKey != null && entryForNullKey.value == null; 346 } 347 348 // value is non-null 349 for (int i = 0; i < len; i++) { 350 for (HashMapEntry e = tab[i]; e != null; e = e.next) { 351 if (value.equals(e.value)) { 352 return true; 353 } 354 } 355 } 356 return entryForNullKey != null && value.equals(entryForNullKey.value); 357 } 358 359 /** 360 * Maps the specified key to the specified value. 361 * 362 * @param key 363 * the key. 364 * @param value 365 * the value. 366 * @return the value of any previous mapping with the specified key or 367 * {@code null} if there was no such mapping. 368 */ 369 @Override public V put(K key, V value) { 370 if (key == null) { 371 return putValueForNullKey(value); 372 } 373 374 int hash = secondaryHash(key.hashCode()); 375 HashMapEntry<K, V>[] tab = table; 376 int index = hash & (tab.length - 1); 377 for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) { 378 if (e.hash == hash && key.equals(e.key)) { 379 preModify(e); 380 V oldValue = e.value; 381 e.value = value; 382 return oldValue; 383 } 384 } 385 386 // No entry for (non-null) key is present; create one 387 modCount++; 388 if (size++ > threshold) { 389 tab = doubleCapacity(); 390 index = hash & (tab.length - 1); 391 } 392 addNewEntry(key, value, hash, index); 393 return null; 394 } 395 396 private V putValueForNullKey(V value) { 397 HashMapEntry<K, V> entry = entryForNullKey; 398 if (entry == null) { 399 addNewEntryForNullKey(value); 400 size++; 401 modCount++; 402 return null; 403 } else { 404 preModify(entry); 405 V oldValue = entry.value; 406 entry.value = value; 407 return oldValue; 408 } 409 } 410 411 /** 412 * Give LinkedHashMap a chance to take action when we modify an existing 413 * entry. 414 * 415 * @param e the entry we're about to modify. 416 */ 417 void preModify(HashMapEntry<K, V> e) { } 418 419 /** 420 * This method is just like put, except that it doesn't do things that 421 * are inappropriate or unnecessary for constructors and pseudo-constructors 422 * (i.e., clone, readObject). In particular, this method does not check to 423 * ensure that capacity is sufficient, and does not increment modCount. 424 */ 425 private void constructorPut(K key, V value) { 426 if (key == null) { 427 HashMapEntry<K, V> entry = entryForNullKey; 428 if (entry == null) { 429 entryForNullKey = constructorNewEntry(null, value, 0, null); 430 size++; 431 } else { 432 entry.value = value; 433 } 434 return; 435 } 436 437 int hash = secondaryHash(key.hashCode()); 438 HashMapEntry<K, V>[] tab = table; 439 int index = hash & (tab.length - 1); 440 HashMapEntry<K, V> first = tab[index]; 441 for (HashMapEntry<K, V> e = first; e != null; e = e.next) { 442 if (e.hash == hash && key.equals(e.key)) { 443 e.value = value; 444 return; 445 } 446 } 447 448 // No entry for (non-null) key is present; create one 449 tab[index] = constructorNewEntry(key, value, hash, first); 450 size++; 451 } 452 453 /** 454 * Creates a new entry for the given key, value, hash, and index and 455 * inserts it into the hash table. This method is called by put 456 * (and indirectly, putAll), and overridden by LinkedHashMap. The hash 457 * must incorporate the secondary hash function. 458 */ 459 void addNewEntry(K key, V value, int hash, int index) { 460 table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]); 461 } 462 463 /** 464 * Creates a new entry for the null key, and the given value and 465 * inserts it into the hash table. This method is called by put 466 * (and indirectly, putAll), and overridden by LinkedHashMap. 467 */ 468 void addNewEntryForNullKey(V value) { 469 entryForNullKey = new HashMapEntry<K, V>(null, value, 0, null); 470 } 471 472 /** 473 * Like newEntry, but does not perform any activity that would be 474 * unnecessary or inappropriate for constructors. In this class, the 475 * two methods behave identically; in LinkedHashMap, they differ. 476 */ 477 HashMapEntry<K, V> constructorNewEntry( 478 K key, V value, int hash, HashMapEntry<K, V> first) { 479 return new HashMapEntry<K, V>(key, value, hash, first); 480 } 481 482 /** 483 * Copies all the mappings in the specified map to this map. These mappings 484 * will replace all mappings that this map had for any of the keys currently 485 * in the given map. 486 * 487 * @param map 488 * the map to copy mappings from. 489 */ 490 @Override public void putAll(Map<? extends K, ? extends V> map) { 491 ensureCapacity(map.size()); 492 super.putAll(map); 493 } 494 495 /** 496 * Ensures that the hash table has sufficient capacity to store the 497 * specified number of mappings, with room to grow. If not, it increases the 498 * capacity as appropriate. Like doubleCapacity, this method moves existing 499 * entries to new buckets as appropriate. Unlike doubleCapacity, this method 500 * can grow the table by factors of 2^n for n > 1. Hopefully, a single call 501 * to this method will be faster than multiple calls to doubleCapacity. 502 * 503 * <p>This method is called only by putAll. 504 */ 505 private void ensureCapacity(int numMappings) { 506 int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings)); 507 HashMapEntry<K, V>[] oldTable = table; 508 int oldCapacity = oldTable.length; 509 if (newCapacity <= oldCapacity) { 510 return; 511 } 512 if (newCapacity == oldCapacity * 2) { 513 doubleCapacity(); 514 return; 515 } 516 517 // We're growing by at least 4x, rehash in the obvious way 518 HashMapEntry<K, V>[] newTable = makeTable(newCapacity); 519 if (size != 0) { 520 int newMask = newCapacity - 1; 521 for (int i = 0; i < oldCapacity; i++) { 522 for (HashMapEntry<K, V> e = oldTable[i]; e != null;) { 523 HashMapEntry<K, V> oldNext = e.next; 524 int newIndex = e.hash & newMask; 525 HashMapEntry<K, V> newNext = newTable[newIndex]; 526 newTable[newIndex] = e; 527 e.next = newNext; 528 e = oldNext; 529 } 530 } 531 } 532 } 533 534 /** 535 * Allocate a table of the given capacity and set the threshold accordingly. 536 * @param newCapacity must be a power of two 537 */ 538 private HashMapEntry<K, V>[] makeTable(int newCapacity) { 539 @SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable 540 = (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity]; 541 table = newTable; 542 threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity 543 return newTable; 544 } 545 546 /** 547 * Doubles the capacity of the hash table. Existing entries are placed in 548 * the correct bucket on the enlarged table. If the current capacity is, 549 * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which 550 * will be new unless we were already at MAXIMUM_CAPACITY. 551 */ 552 private HashMapEntry<K, V>[] doubleCapacity() { 553 HashMapEntry<K, V>[] oldTable = table; 554 int oldCapacity = oldTable.length; 555 if (oldCapacity == MAXIMUM_CAPACITY) { 556 return oldTable; 557 } 558 int newCapacity = oldCapacity * 2; 559 HashMapEntry<K, V>[] newTable = makeTable(newCapacity); 560 if (size == 0) { 561 return newTable; 562 } 563 564 for (int j = 0; j < oldCapacity; j++) { 565 /* 566 * Rehash the bucket using the minimum number of field writes. 567 * This is the most subtle and delicate code in the class. 568 */ 569 HashMapEntry<K, V> e = oldTable[j]; 570 if (e == null) { 571 continue; 572 } 573 int highBit = e.hash & oldCapacity; 574 HashMapEntry<K, V> broken = null; 575 newTable[j | highBit] = e; 576 for (HashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) { 577 int nextHighBit = n.hash & oldCapacity; 578 if (nextHighBit != highBit) { 579 if (broken == null) 580 newTable[j | nextHighBit] = n; 581 else 582 broken.next = n; 583 broken = e; 584 highBit = nextHighBit; 585 } 586 } 587 if (broken != null) 588 broken.next = null; 589 } 590 return newTable; 591 } 592 593 /** 594 * Removes the mapping with the specified key from this map. 595 * 596 * @param key 597 * the key of the mapping to remove. 598 * @return the value of the removed mapping or {@code null} if no mapping 599 * for the specified key was found. 600 */ 601 @Override public V remove(Object key) { 602 if (key == null) { 603 return removeNullKey(); 604 } 605 int hash = secondaryHash(key.hashCode()); 606 HashMapEntry<K, V>[] tab = table; 607 int index = hash & (tab.length - 1); 608 for (HashMapEntry<K, V> e = tab[index], prev = null; 609 e != null; prev = e, e = e.next) { 610 if (e.hash == hash && key.equals(e.key)) { 611 if (prev == null) { 612 tab[index] = e.next; 613 } else { 614 prev.next = e.next; 615 } 616 modCount++; 617 size--; 618 postRemove(e); 619 return e.value; 620 } 621 } 622 return null; 623 } 624 625 private V removeNullKey() { 626 HashMapEntry<K, V> e = entryForNullKey; 627 if (e == null) { 628 return null; 629 } 630 entryForNullKey = null; 631 modCount++; 632 size--; 633 postRemove(e); 634 return e.value; 635 } 636 637 /** 638 * Subclass overrides this method to unlink entry. 639 */ 640 void postRemove(HashMapEntry<K, V> e) { } 641 642 /** 643 * Removes all mappings from this hash map, leaving it empty. 644 * 645 * @see #isEmpty 646 * @see #size 647 */ 648 @Override public void clear() { 649 if (size != 0) { 650 Arrays.fill(table, null); 651 entryForNullKey = null; 652 modCount++; 653 size = 0; 654 } 655 } 656 657 /** 658 * Returns a set of the keys contained in this map. The set is backed by 659 * this map so changes to one are reflected by the other. The set does not 660 * support adding. 661 * 662 * @return a set of the keys. 663 */ 664 @Override public Set<K> keySet() { 665 Set<K> ks = keySet; 666 return (ks != null) ? ks : (keySet = new KeySet()); 667 } 668 669 /** 670 * Returns a collection of the values contained in this map. The collection 671 * is backed by this map so changes to one are reflected by the other. The 672 * collection supports remove, removeAll, retainAll and clear operations, 673 * and it does not support add or addAll operations. 674 * <p> 675 * This method returns a collection which is the subclass of 676 * AbstractCollection. The iterator method of this subclass returns a 677 * "wrapper object" over the iterator of map's entrySet(). The {@code size} 678 * method wraps the map's size method and the {@code contains} method wraps 679 * the map's containsValue method. 680 * </p> 681 * <p> 682 * The collection is created when this method is called for the first time 683 * and returned in response to all subsequent calls. This method may return 684 * different collections when multiple concurrent calls occur, since no 685 * synchronization is performed. 686 * </p> 687 * 688 * @return a collection of the values contained in this map. 689 */ 690 @Override public Collection<V> values() { 691 Collection<V> vs = values; 692 return (vs != null) ? vs : (values = new Values()); 693 } 694 695 /** 696 * Returns a set containing all of the mappings in this map. Each mapping is 697 * an instance of {@link Map.Entry}. As the set is backed by this map, 698 * changes in one will be reflected in the other. 699 * 700 * @return a set of the mappings. 701 */ 702 public Set<Entry<K, V>> entrySet() { 703 Set<Entry<K, V>> es = entrySet; 704 return (es != null) ? es : (entrySet = new EntrySet()); 705 } 706 707 static class HashMapEntry<K, V> implements Entry<K, V> { 708 final K key; 709 V value; 710 final int hash; 711 HashMapEntry<K, V> next; 712 713 HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) { 714 this.key = key; 715 this.value = value; 716 this.hash = hash; 717 this.next = next; 718 } 719 720 public final K getKey() { 721 return key; 722 } 723 724 public final V getValue() { 725 return value; 726 } 727 728 public final V setValue(V value) { 729 V oldValue = this.value; 730 this.value = value; 731 return oldValue; 732 } 733 734 @Override public final boolean equals(Object o) { 735 if (!(o instanceof Entry)) { 736 return false; 737 } 738 Entry<?, ?> e = (Entry<?, ?>) o; 739 return Objects.equal(e.getKey(), key) 740 && Objects.equal(e.getValue(), value); 741 } 742 743 @Override public final int hashCode() { 744 return (key == null ? 0 : key.hashCode()) ^ 745 (value == null ? 0 : value.hashCode()); 746 } 747 748 @Override public final String toString() { 749 return key + "=" + value; 750 } 751 } 752 753 private abstract class HashIterator { 754 int nextIndex; 755 HashMapEntry<K, V> nextEntry = entryForNullKey; 756 HashMapEntry<K, V> lastEntryReturned; 757 int expectedModCount = modCount; 758 759 HashIterator() { 760 if (nextEntry == null) { 761 HashMapEntry<K, V>[] tab = table; 762 HashMapEntry<K, V> next = null; 763 while (next == null && nextIndex < tab.length) { 764 next = tab[nextIndex++]; 765 } 766 nextEntry = next; 767 } 768 } 769 770 public boolean hasNext() { 771 return nextEntry != null; 772 } 773 774 HashMapEntry<K, V> nextEntry() { 775 if (modCount != expectedModCount) 776 throw new ConcurrentModificationException(); 777 if (nextEntry == null) 778 throw new NoSuchElementException(); 779 780 HashMapEntry<K, V> entryToReturn = nextEntry; 781 HashMapEntry<K, V>[] tab = table; 782 HashMapEntry<K, V> next = entryToReturn.next; 783 while (next == null && nextIndex < tab.length) { 784 next = tab[nextIndex++]; 785 } 786 nextEntry = next; 787 return lastEntryReturned = entryToReturn; 788 } 789 790 public void remove() { 791 if (lastEntryReturned == null) 792 throw new IllegalStateException(); 793 if (modCount != expectedModCount) 794 throw new ConcurrentModificationException(); 795 HashMap.this.remove(lastEntryReturned.key); 796 lastEntryReturned = null; 797 expectedModCount = modCount; 798 } 799 } 800 801 private final class KeyIterator extends HashIterator 802 implements Iterator<K> { 803 public K next() { return nextEntry().key; } 804 } 805 806 private final class ValueIterator extends HashIterator 807 implements Iterator<V> { 808 public V next() { return nextEntry().value; } 809 } 810 811 private final class EntryIterator extends HashIterator 812 implements Iterator<Entry<K, V>> { 813 public Entry<K, V> next() { return nextEntry(); } 814 } 815 816 /** 817 * Returns true if this map contains the specified mapping. 818 */ 819 private boolean containsMapping(Object key, Object value) { 820 if (key == null) { 821 HashMapEntry<K, V> e = entryForNullKey; 822 return e != null && Objects.equal(value, e.value); 823 } 824 825 int hash = secondaryHash(key.hashCode()); 826 HashMapEntry<K, V>[] tab = table; 827 int index = hash & (tab.length - 1); 828 for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) { 829 if (e.hash == hash && key.equals(e.key)) { 830 return Objects.equal(value, e.value); 831 } 832 } 833 return false; // No entry for key 834 } 835 836 /** 837 * Removes the mapping from key to value and returns true if this mapping 838 * exists; otherwise, returns does nothing and returns false. 839 */ 840 private boolean removeMapping(Object key, Object value) { 841 if (key == null) { 842 HashMapEntry<K, V> e = entryForNullKey; 843 if (e == null || !Objects.equal(value, e.value)) { 844 return false; 845 } 846 entryForNullKey = null; 847 modCount++; 848 size--; 849 postRemove(e); 850 return true; 851 } 852 853 int hash = secondaryHash(key.hashCode()); 854 HashMapEntry<K, V>[] tab = table; 855 int index = hash & (tab.length - 1); 856 for (HashMapEntry<K, V> e = tab[index], prev = null; 857 e != null; prev = e, e = e.next) { 858 if (e.hash == hash && key.equals(e.key)) { 859 if (!Objects.equal(value, e.value)) { 860 return false; // Map has wrong value for key 861 } 862 if (prev == null) { 863 tab[index] = e.next; 864 } else { 865 prev.next = e.next; 866 } 867 modCount++; 868 size--; 869 postRemove(e); 870 return true; 871 } 872 } 873 return false; // No entry for key 874 } 875 876 // Subclass (LinkedHashMap) overrides these for correct iteration order 877 Iterator<K> newKeyIterator() { return new KeyIterator(); } 878 Iterator<V> newValueIterator() { return new ValueIterator(); } 879 Iterator<Entry<K, V>> newEntryIterator() { return new EntryIterator(); } 880 881 private final class KeySet extends AbstractSet<K> { 882 public Iterator<K> iterator() { 883 return newKeyIterator(); 884 } 885 public int size() { 886 return size; 887 } 888 public boolean isEmpty() { 889 return size == 0; 890 } 891 public boolean contains(Object o) { 892 return containsKey(o); 893 } 894 public boolean remove(Object o) { 895 int oldSize = size; 896 HashMap.this.remove(o); 897 return size != oldSize; 898 } 899 public void clear() { 900 HashMap.this.clear(); 901 } 902 } 903 904 private final class Values extends AbstractCollection<V> { 905 public Iterator<V> iterator() { 906 return newValueIterator(); 907 } 908 public int size() { 909 return size; 910 } 911 public boolean isEmpty() { 912 return size == 0; 913 } 914 public boolean contains(Object o) { 915 return containsValue(o); 916 } 917 public void clear() { 918 HashMap.this.clear(); 919 } 920 } 921 922 private final class EntrySet extends AbstractSet<Entry<K, V>> { 923 public Iterator<Entry<K, V>> iterator() { 924 return newEntryIterator(); 925 } 926 public boolean contains(Object o) { 927 if (!(o instanceof Entry)) 928 return false; 929 Entry<?, ?> e = (Entry<?, ?>) o; 930 return containsMapping(e.getKey(), e.getValue()); 931 } 932 public boolean remove(Object o) { 933 if (!(o instanceof Entry)) 934 return false; 935 Entry<?, ?> e = (Entry<?, ?>)o; 936 return removeMapping(e.getKey(), e.getValue()); 937 } 938 public int size() { 939 return size; 940 } 941 public boolean isEmpty() { 942 return size == 0; 943 } 944 public void clear() { 945 HashMap.this.clear(); 946 } 947 } 948 949 /** 950 * Applies a supplemental hash function to a given hashCode, which defends 951 * against poor quality hash functions. This is critical because HashMap 952 * uses power-of-two length hash tables, that otherwise encounter collisions 953 * for hashCodes that do not differ in lower or upper bits. 954 */ 955 private static int secondaryHash(int h) { 956 // Doug Lea's supplemental hash function 957 h ^= (h >>> 20) ^ (h >>> 12); 958 return h ^ (h >>> 7) ^ (h >>> 4); 959 } 960 961 /** 962 * Returns the smallest power of two >= its argument, with several caveats: 963 * If the argument is negative but not Integer.MIN_VALUE, the method returns 964 * zero. If the argument is > 2^30 or equal to Integer.MIN_VALUE, the method 965 * returns Integer.MIN_VALUE. If the argument is zero, the method returns 966 * zero. 967 */ 968 private static int roundUpToPowerOfTwo(int i) { 969 i--; // If input is a power of two, shift its high-order bit right 970 971 // "Smear" the high-order bit all the way to the right 972 i |= i >>> 1; 973 i |= i >>> 2; 974 i |= i >>> 4; 975 i |= i >>> 8; 976 i |= i >>> 16; 977 978 return i + 1; 979 } 980 981 private static final long serialVersionUID = 362498820763181265L; 982 983 private static final ObjectStreamField[] serialPersistentFields = { 984 new ObjectStreamField("loadFactor", float.class) 985 }; 986 987 private void writeObject(ObjectOutputStream stream) throws IOException { 988 // Emulate loadFactor field for other implementations to read 989 ObjectOutputStream.PutField fields = stream.putFields(); 990 fields.put("loadFactor", DEFAULT_LOAD_FACTOR); 991 stream.writeFields(); 992 993 stream.writeInt(table.length); // Capacity 994 stream.writeInt(size); 995 for (Entry<K, V> e : entrySet()) { 996 stream.writeObject(e.getKey()); 997 stream.writeObject(e.getValue()); 998 } 999 } 1000 1001 private void readObject(ObjectInputStream stream) throws IOException, 1002 ClassNotFoundException { 1003 stream.defaultReadObject(); 1004 int capacity = stream.readInt(); 1005 if (capacity < 0) { 1006 throw new InvalidObjectException("Capacity: " + capacity); 1007 } 1008 if (capacity < MINIMUM_CAPACITY) { 1009 capacity = MINIMUM_CAPACITY; 1010 } else if (capacity > MAXIMUM_CAPACITY) { 1011 capacity = MAXIMUM_CAPACITY; 1012 } else { 1013 capacity = roundUpToPowerOfTwo(capacity); 1014 } 1015 makeTable(capacity); 1016 1017 int size = stream.readInt(); 1018 if (size < 0) { 1019 throw new InvalidObjectException("Size: " + size); 1020 } 1021 1022 init(); // Give subclass (LinkedHashMap) a chance to initialize itself 1023 for (int i = 0; i < size; i++) { 1024 @SuppressWarnings("unchecked") K key = (K) stream.readObject(); 1025 @SuppressWarnings("unchecked") V val = (V) stream.readObject(); 1026 constructorPut(key, val); 1027 } 1028 } 1029 }
TreeMap

1 package java.util; 2 import java.io.IOException; 3 import java.io.ObjectInputStream; 4 import java.io.ObjectInputStream.GetField; 5 import java.io.ObjectOutputStream; 6 import java.io.ObjectStreamException; 7 import java.io.Serializable; 8 import static java.util.TreeMap.Bound.*; 9 import static java.util.TreeMap.Relation.*; 10 import libcore.util.Objects; 11 /** 12 * A map whose entries are sorted by their keys. All optional operations such as 13 * {@link #put} and {@link #remove} are supported. 14 * 15 * <p>This map sorts keys using either a user-supplied comparator or the key's 16 * natural order: 17 * <ul> 18 * <li>User supplied comparators must be able to compare any pair of keys in 19 * this map. If a user-supplied comparator is in use, it will be returned 20 * by {@link #comparator}. 21 * <li>If no user-supplied comparator is supplied, keys will be sorted by 22 * their natural order. Keys must be <i>mutually comparable</i>: they must 23 * implement {@link Comparable} and {@link Comparable#compareTo 24 * compareTo()} must be able to compare each key with any other key in 25 * this map. In this case {@link #comparator} will return null. 26 * </ul> 27 * With either a comparator or a natural ordering, comparisons should be 28 * <i>consistent with equals</i>. An ordering is consistent with equals if for 29 * every pair of keys {@code a} and {@code b}, {@code a.equals(b)} if and only 30 * if {@code compare(a, b) == 0}. 31 * 32 * <p>When the ordering is not consistent with equals the behavior of this 33 * class is well defined but does not honor the contract specified by {@link 34 * Map}. Consider a tree map of case-insensitive strings, an ordering that is 35 * not consistent with equals: <pre> {@code 36 * TreeMap<String, String> map = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); 37 * map.put("a", "android"); 38 * 39 * // The Map API specifies that the next line should print "null" because 40 * // "a".equals("A") is false and there is no mapping for upper case "A". 41 * // But the case insensitive ordering says compare("a", "A") == 0. TreeMap 42 * // uses only comparators/comparable on keys and so this prints "android". 43 * System.out.println(map.get("A")); 44 * }</pre> 45 * 46 * @since 1.2 47 */ 48 public class TreeMap<K, V> extends AbstractMap<K, V> 49 implements SortedMap<K, V>, NavigableMap<K, V>, Cloneable, Serializable { 50 51 @SuppressWarnings("unchecked") // to avoid Comparable<Comparable<Comparable<...>>> 52 private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() { 53 public int compare(Comparable a, Comparable b) { 54 return a.compareTo(b); 55 } 56 }; 57 58 Comparator<? super K> comparator; 59 Node<K, V> root; 60 int size = 0; 61 int modCount = 0; 62 63 /** 64 * Create a natural order, empty tree map whose keys must be mutually 65 * comparable and non-null. 66 */ 67 @SuppressWarnings("unchecked") // unsafe! this assumes K is comparable 68 public TreeMap() { 69 this.comparator = (Comparator<? super K>) NATURAL_ORDER; 70 } 71 72 /** 73 * Create a natural order tree map populated with the key/value pairs of 74 * {@code copyFrom}. This map's keys must be mutually comparable and 75 * non-null. 76 * 77 * <p>Even if {@code copyFrom} is a {@code SortedMap}, the constructed map 78 * <strong>will not</strong> use {@code copyFrom}'s ordering. This 79 * constructor always creates a naturally-ordered map. Because the {@code 80 * TreeMap} constructor overloads are ambiguous, prefer to construct a map 81 * and populate it in two steps: <pre> {@code 82 * TreeMap<String, Integer> customOrderedMap 83 * = new TreeMap<String, Integer>(copyFrom.comparator()); 84 * customOrderedMap.putAll(copyFrom); 85 * }</pre> 86 */ 87 public TreeMap(Map<? extends K, ? extends V> copyFrom) { 88 this(); 89 for (Map.Entry<? extends K, ? extends V> entry : copyFrom.entrySet()) { 90 putInternal(entry.getKey(), entry.getValue()); 91 } 92 } 93 94 /** 95 * Create a tree map ordered by {@code comparator}. This map's keys may only 96 * be null if {@code comparator} permits. 97 * 98 * @param comparator the comparator to order elements with, or {@code null} to use the natural 99 * ordering. 100 */ 101 @SuppressWarnings("unchecked") // unsafe! if comparator is null, this assumes K is comparable 102 public TreeMap(Comparator<? super K> comparator) { 103 if (comparator != null) { 104 this.comparator = comparator; 105 } else { 106 this.comparator = (Comparator<? super K>) NATURAL_ORDER; 107 } 108 } 109 110 /** 111 * Create a tree map with the ordering and key/value pairs of {@code 112 * copyFrom}. This map's keys may only be null if the {@code copyFrom}'s 113 * ordering permits. 114 * 115 * <p>The constructed map <strong>will always use</strong> {@code 116 * copyFrom}'s ordering. Because the {@code TreeMap} constructor overloads 117 * are ambigous, prefer to construct a map and populate it in two steps: 118 * <pre> {@code 119 * TreeMap<String, Integer> customOrderedMap 120 * = new TreeMap<String, Integer>(copyFrom.comparator()); 121 * customOrderedMap.putAll(copyFrom); 122 * }</pre> 123 */ 124 @SuppressWarnings("unchecked") // if copyFrom's keys are comparable this map's keys must be also 125 public TreeMap(SortedMap<K, ? extends V> copyFrom) { 126 Comparator<? super K> sourceComparator = copyFrom.comparator(); 127 if (sourceComparator != null) { 128 this.comparator = sourceComparator; 129 } else { 130 this.comparator = (Comparator<? super K>) NATURAL_ORDER; 131 } 132 for (Map.Entry<K, ? extends V> entry : copyFrom.entrySet()) { 133 putInternal(entry.getKey(), entry.getValue()); 134 } 135 } 136 137 @Override public Object clone() { 138 try { 139 @SuppressWarnings("unchecked") // super.clone() must return the same type 140 TreeMap<K, V> map = (TreeMap<K, V>) super.clone(); 141 map.root = root != null ? root.copy(null) : null; 142 map.entrySet = null; 143 map.keySet = null; 144 return map; 145 } catch (CloneNotSupportedException e) { 146 throw new AssertionError(); 147 } 148 } 149 150 @Override public int size() { 151 return size; 152 } 153 154 @Override public boolean isEmpty() { 155 return size == 0; 156 } 157 158 @Override public V get(Object key) { 159 Entry<K, V> entry = findByObject(key); 160 return entry != null ? entry.getValue() : null; 161 } 162 163 @Override public boolean containsKey(Object key) { 164 return findByObject(key) != null; 165 } 166 167 @Override public V put(K key, V value) { 168 return putInternal(key, value); 169 } 170 171 @Override public void clear() { 172 root = null; 173 size = 0; 174 modCount++; 175 } 176 177 @Override public V remove(Object key) { 178 Node<K, V> node = removeInternalByKey(key); 179 return node != null ? node.value : null; 180 } 181 182 /* 183 * AVL methods 184 */ 185 186 enum Relation { 187 LOWER, 188 FLOOR, 189 EQUAL, 190 CREATE, 191 CEILING, 192 HIGHER; 193 194 /** 195 * Returns a possibly-flipped relation for use in descending views. 196 * 197 * @param ascending false to flip; true to return this. 198 */ 199 Relation forOrder(boolean ascending) { 200 if (ascending) { 201 return this; 202 } 203 204 switch (this) { 205 case LOWER: 206 return HIGHER; 207 case FLOOR: 208 return CEILING; 209 case EQUAL: 210 return EQUAL; 211 case CEILING: 212 return FLOOR; 213 case HIGHER: 214 return LOWER; 215 default: 216 throw new IllegalStateException(); 217 } 218 } 219 } 220 221 V putInternal(K key, V value) { 222 Node<K, V> created = find(key, Relation.CREATE); 223 V result = created.value; 224 created.value = value; 225 return result; 226 } 227 228 /** 229 * Returns the node at or adjacent to the given key, creating it if requested. 230 * 231 * @throws ClassCastException if {@code key} and the tree's keys aren't mutually comparable. 232 */ 233 Node<K, V> find(K key, Relation relation) { 234 if (root == null) { 235 if (comparator == NATURAL_ORDER && !(key instanceof Comparable)) { 236 throw new ClassCastException(key.getClass().getName() + " is not Comparable"); // NullPointerException ok 237 } 238 if (relation == Relation.CREATE) { 239 root = new Node<K, V>(null, key); 240 size = 1; 241 modCount++; 242 return root; 243 } else { 244 return null; 245 } 246 } 247 248 /* 249 * Micro-optimization: avoid polymorphic calls to Comparator.compare(). 250 * This is 10% faster for naturally ordered trees. 251 */ 252 @SuppressWarnings("unchecked") // will throw a ClassCastException below if there's trouble 253 Comparable<Object> comparableKey = (comparator == NATURAL_ORDER) 254 ? (Comparable<Object>) key 255 : null; 256 257 Node<K, V> nearest = root; 258 while (true) { 259 int comparison = (comparableKey != null) 260 ? comparableKey.compareTo(nearest.key) 261 : comparator.compare(key, nearest.key); 262 263 /* 264 * We found the requested key. 265 */ 266 if (comparison == 0) { 267 switch (relation) { 268 case LOWER: 269 return nearest.prev(); 270 case FLOOR: 271 case EQUAL: 272 case CREATE: 273 case CEILING: 274 return nearest; 275 case HIGHER: 276 return nearest.next(); 277 } 278 } 279 280 Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right; 281 if (child != null) { 282 nearest = child; 283 continue; 284 } 285 286 /* 287 * We found a nearest node. Every key not in the tree has up to two 288 * nearest nodes, one lower and one higher. 289 */ 290 291 if (comparison < 0) { // nearest.key is higher 292 switch (relation) { 293 case LOWER: 294 case FLOOR: 295 return nearest.prev(); 296 case CEILING: 297 case HIGHER: 298 return nearest; 299 case EQUAL: 300 return null; 301 case CREATE: 302 Node<K, V> created = new Node<K, V>(nearest, key); 303 nearest.left = created; 304 size++; 305 modCount++; 306 rebalance(nearest, true); 307 return created; 308 } 309 } else { // comparison > 0, nearest.key is lower 310 switch (relation) { 311 case LOWER: 312 case FLOOR: 313 return nearest; 314 case CEILING: 315 case HIGHER: 316 return nearest.next(); 317 case EQUAL: 318 return null; 319 case CREATE: 320 Node<K, V> created = new Node<K, V>(nearest, key); 321 nearest.right = created; 322 size++; 323 modCount++; 324 rebalance(nearest, true); 325 return created; 326 } 327 } 328 } 329 } 330 331 @SuppressWarnings("unchecked") // this method throws ClassCastExceptions! 332 Node<K, V> findByObject(Object key) { 333 return find((K) key, EQUAL); 334 } 335 336 /** 337 * Returns this map's entry that has the same key and value as {@code 338 * entry}, or null if this map has no such entry. 339 * 340 * <p>This method uses the comparator for key equality rather than {@code 341 * equals}. If this map's comparator isn't consistent with equals (such as 342 * {@code String.CASE_INSENSITIVE_ORDER}), then {@code remove()} and {@code 343 * contains()} will violate the collections API. 344 */ 345 Node<K, V> findByEntry(Entry<?, ?> entry) { 346 Node<K, V> mine = findByObject(entry.getKey()); 347 boolean valuesEqual = mine != null && Objects.equal(mine.value, entry.getValue()); 348 return valuesEqual ? mine : null; 349 } 350 351 /** 352 * Removes {@code node} from this tree, rearranging the tree's structure as 353 * necessary. 354 */ 355 void removeInternal(Node<K, V> node) { 356 Node<K, V> left = node.left; 357 Node<K, V> right = node.right; 358 Node<K, V> originalParent = node.parent; 359 if (left != null && right != null) { 360 361 /* 362 * To remove a node with both left and right subtrees, move an 363 * adjacent node from one of those subtrees into this node's place. 364 * 365 * Removing the adjacent node may change this node's subtrees. This 366 * node may no longer have two subtrees once the adjacent node is 367 * gone! 368 */ 369 370 Node<K, V> adjacent = (left.height > right.height) ? left.last() : right.first(); 371 removeInternal(adjacent); // takes care of rebalance and size-- 372 373 int leftHeight = 0; 374 left = node.left; 375 if (left != null) { 376 leftHeight = left.height; 377 adjacent.left = left; 378 left.parent = adjacent; 379 node.left = null; 380 } 381 int rightHeight = 0; 382 right = node.right; 383 if (right != null) { 384 rightHeight = right.height; 385 adjacent.right = right; 386 right.parent = adjacent; 387 node.right = null; 388 } 389 adjacent.height = Math.max(leftHeight, rightHeight) + 1; 390 replaceInParent(node, adjacent); 391 return; 392 } else if (left != null) { 393 replaceInParent(node, left); 394 node.left = null; 395 } else if (right != null) { 396 replaceInParent(node, right); 397 node.right = null; 398 } else { 399 replaceInParent(node, null); 400 } 401 402 rebalance(originalParent, false); 403 size--; 404 modCount++; 405 } 406 407 Node<K, V> removeInternalByKey(Object key) { 408 Node<K, V> node = findByObject(key); 409 if (node != null) { 410 removeInternal(node); 411 } 412 return node; 413 } 414 415 private void replaceInParent(Node<K, V> node, Node<K, V> replacement) { 416 Node<K, V> parent = node.parent; 417 node.parent = null; 418 if (replacement != null) { 419 replacement.parent = parent; 420 } 421 422 if (parent != null) { 423 if (parent.left == node) { 424 parent.left = replacement; 425 } else { 426 assert (parent.right == node); 427 parent.right = replacement; 428 } 429 } else { 430 root = replacement; 431 } 432 } 433 434 /** 435 * Rebalances the tree by making any AVL rotations necessary between the 436 * newly-unbalanced node and the tree's root. 437 * 438 * @param insert true if the node was unbalanced by an insert; false if it 439 * was by a removal. 440 */ 441 private void rebalance(Node<K, V> unbalanced, boolean insert) { 442 for (Node<K, V> node = unbalanced; node != null; node = node.parent) { 443 Node<K, V> left = node.left; 444 Node<K, V> right = node.right; 445 int leftHeight = left != null ? left.height : 0; 446 int rightHeight = right != null ? right.height : 0; 447 448 int delta = leftHeight - rightHeight; 449 if (delta == -2) { 450 Node<K, V> rightLeft = right.left; 451 Node<K, V> rightRight = right.right; 452 int rightRightHeight = rightRight != null ? rightRight.height : 0; 453 int rightLeftHeight = rightLeft != null ? rightLeft.height : 0; 454 455 int rightDelta = rightLeftHeight - rightRightHeight; 456 if (rightDelta == -1 || (rightDelta == 0 && !insert)) { 457 rotateLeft(node); // AVL right right 458 } else { 459 assert (rightDelta == 1); 460 rotateRight(right); // AVL right left 461 rotateLeft(node); 462 } 463 if (insert) { 464 break; // no further rotations will be necessary 465 } 466 467 } else if (delta == 2) { 468 Node<K, V> leftLeft = left.left; 469 Node<K, V> leftRight = left.right; 470 int leftRightHeight = leftRight != null ? leftRight.height : 0; 471 int leftLeftHeight = leftLeft != null ? leftLeft.height : 0; 472 473 int leftDelta = leftLeftHeight - leftRightHeight; 474 if (leftDelta == 1 || (leftDelta == 0 && !insert)) { 475 rotateRight(node); // AVL left left 476 } else { 477 assert (leftDelta == -1); 478 rotateLeft(left); // AVL left right 479 rotateRight(node); 480 } 481 if (insert) { 482 break; // no further rotations will be necessary 483 } 484 485 } else if (delta == 0) { 486 node.height = leftHeight + 1; // leftHeight == rightHeight 487 if (insert) { 488 break; // the insert caused balance, so rebalancing is done! 489 } 490 491 } else { 492 assert (delta == -1 || delta == 1); 493 node.height = Math.max(leftHeight, rightHeight) + 1; 494 if (!insert) { 495 break; // the height hasn't changed, so rebalancing is done! 496 } 497 } 498 } 499 } 500 501 /** 502 * Rotates the subtree so that its root's right child is the new root. 503 */ 504 private void rotateLeft(Node<K, V> root) { 505 Node<K, V> left = root.left; 506 Node<K, V> pivot = root.right; 507 Node<K, V> pivotLeft = pivot.left; 508 Node<K, V> pivotRight = pivot.right; 509 510 // move the pivot's left child to the root's right 511 root.right = pivotLeft; 512 if (pivotLeft != null) { 513 pivotLeft.parent = root; 514 } 515 516 replaceInParent(root, pivot); 517 518 // move the root to the pivot's left 519 pivot.left = root; 520 root.parent = pivot; 521 522 // fix heights 523 root.height = Math.max(left != null ? left.height : 0, 524 pivotLeft != null ? pivotLeft.height : 0) + 1; 525 pivot.height = Math.max(root.height, 526 pivotRight != null ? pivotRight.height : 0) + 1; 527 } 528 529 /** 530 * Rotates the subtree so that its root's left child is the new root. 531 */ 532 private void rotateRight(Node<K, V> root) { 533 Node<K, V> pivot = root.left; 534 Node<K, V> right = root.right; 535 Node<K, V> pivotLeft = pivot.left; 536 Node<K, V> pivotRight = pivot.right; 537 538 // move the pivot's right child to the root's left 539 root.left = pivotRight; 540 if (pivotRight != null) { 541 pivotRight.parent = root; 542 } 543 544 replaceInParent(root, pivot); 545 546 // move the root to the pivot's right 547 pivot.right = root; 548 root.parent = pivot; 549 550 // fixup heights 551 root.height = Math.max(right != null ? right.height : 0, 552 pivotRight != null ? pivotRight.height : 0) + 1; 553 pivot.height = Math.max(root.height, 554 pivotLeft != null ? pivotLeft.height : 0) + 1; 555 } 556 557 /* 558 * Navigable methods. 559 */ 560 561 /** 562 * Returns an immutable version of {@param entry}. Need this because we allow entry to be null, 563 * in which case we return a null SimpleImmutableEntry. 564 */ 565 private SimpleImmutableEntry<K, V> immutableCopy(Entry<K, V> entry) { 566 return entry == null ? null : new SimpleImmutableEntry<K, V>(entry); 567 } 568 569 public Entry<K, V> firstEntry() { 570 return immutableCopy(root == null ? null : root.first()); 571 } 572 573 private Entry<K, V> internalPollFirstEntry() { 574 if (root == null) { 575 return null; 576 } 577 Node<K, V> result = root.first(); 578 removeInternal(result); 579 return result; 580 } 581 582 public Entry<K, V> pollFirstEntry() { 583 return immutableCopy(internalPollFirstEntry()); 584 } 585 586 public K firstKey() { 587 if (root == null) { 588 throw new NoSuchElementException(); 589 } 590 return root.first().getKey(); 591 } 592 593 public Entry<K, V> lastEntry() { 594 return immutableCopy(root == null ? null : root.last()); 595 } 596 597 private Entry<K, V> internalPollLastEntry() { 598 if (root == null) { 599 return null; 600 } 601 Node<K, V> result = root.last(); 602 removeInternal(result); 603 return result; 604 } 605 606 public Entry<K, V> pollLastEntry() { 607 return immutableCopy(internalPollLastEntry()); 608 } 609 610 public K lastKey() { 611 if (root == null) { 612 throw new NoSuchElementException(); 613 } 614 return root.last().getKey(); 615 } 616 617 public Entry<K, V> lowerEntry(K key) { 618 return immutableCopy(find(key, LOWER)); 619 } 620 621 public K lowerKey(K key) { 622 Entry<K, V> entry = find(key, LOWER); 623 return entry != null ? entry.getKey() : null; 624 } 625 626 public Entry<K, V> floorEntry(K key) { 627 return immutableCopy(find(key, FLOOR)); 628 } 629 630 public K floorKey(K key) { 631 Entry<K, V> entry = find(key, FLOOR); 632 return entry != null ? entry.getKey() : null; 633 } 634 635 public Entry<K, V> ceilingEntry(K key) { 636 return immutableCopy(find(key, CEILING)); 637 } 638 639 public K ceilingKey(K key) { 640 Entry<K, V> entry = find(key, CEILING); 641 return entry != null ? entry.getKey() : null; 642 } 643 644 public Entry<K, V> higherEntry(K key) { 645 return immutableCopy(find(key, HIGHER)); 646 } 647 648 public K higherKey(K key) { 649 Entry<K, V> entry = find(key, HIGHER); 650 return entry != null ? entry.getKey() : null; 651 } 652 653 public Comparator<? super K> comparator() { 654 return comparator != NATURAL_ORDER ? comparator : null; 655 } 656 657 /* 658 * View factory methods. 659 */ 660 661 private EntrySet entrySet; 662 private KeySet keySet; 663 664 @Override public Set<Entry<K, V>> entrySet() { 665 EntrySet result = entrySet; 666 return result != null ? result : (entrySet = new EntrySet()); 667 } 668 669 @Override public Set<K> keySet() { 670 KeySet result = keySet; 671 return result != null ? result : (keySet = new KeySet()); 672 } 673 674 public NavigableSet<K> navigableKeySet() { 675 KeySet result = keySet; 676 return result != null ? result : (keySet = new KeySet()); 677 } 678 679 public NavigableMap<K, V> subMap(K from, boolean fromInclusive, K to, boolean toInclusive) { 680 Bound fromBound = fromInclusive ? INCLUSIVE : EXCLUSIVE; 681 Bound toBound = toInclusive ? INCLUSIVE : EXCLUSIVE; 682 return new BoundedMap(true, from, fromBound, to, toBound); 683 } 684 685 public SortedMap<K, V> subMap(K fromInclusive, K toExclusive) { 686 return new BoundedMap(true, fromInclusive, INCLUSIVE, toExclusive, EXCLUSIVE); 687 } 688 689 public NavigableMap<K, V> headMap(K to, boolean inclusive) { 690 Bound toBound = inclusive ? INCLUSIVE : EXCLUSIVE; 691 return new BoundedMap(true, null, NO_BOUND, to, toBound); 692 } 693 694 public SortedMap<K, V> headMap(K toExclusive) { 695 return new BoundedMap(true, null, NO_BOUND, toExclusive, EXCLUSIVE); 696 } 697 698 public NavigableMap<K, V> tailMap(K from, boolean inclusive) { 699 Bound fromBound = inclusive ? INCLUSIVE : EXCLUSIVE; 700 return new BoundedMap(true, from, fromBound, null, NO_BOUND); 701 } 702 703 public SortedMap<K, V> tailMap(K fromInclusive) { 704 return new BoundedMap(true, fromInclusive, INCLUSIVE, null, NO_BOUND); 705 } 706 707 public NavigableMap<K, V> descendingMap() { 708 return new BoundedMap(false, null, NO_BOUND, null, NO_BOUND); 709 } 710 711 public NavigableSet<K> descendingKeySet() { 712 return new BoundedMap(false, null, NO_BOUND, null, NO_BOUND).navigableKeySet(); 713 } 714 715 static class Node<K, V> implements Map.Entry<K, V> { 716 Node<K, V> parent; 717 Node<K, V> left; 718 Node<K, V> right; 719 final K key; 720 V value; 721 int height; 722 723 Node(Node<K, V> parent, K key) { 724 this.parent = parent; 725 this.key = key; 726 this.height = 1; 727 } 728 729 Node<K, V> copy(Node<K, V> parent) { 730 Node<K, V> result = new Node<K, V>(parent, key); 731 if (left != null) { 732 result.left = left.copy(result); 733 } 734 if (right != null) { 735 result.right = right.copy(result); 736 } 737 result.value = value; 738 result.height = height; 739 return result; 740 } 741 742 public K getKey() { 743 return key; 744 } 745 746 public V getValue() { 747 return value; 748 } 749 750 public V setValue(V value) { 751 V oldValue = this.value; 752 this.value = value; 753 return oldValue; 754 } 755 756 @Override public boolean equals(Object o) { 757 if (o instanceof Map.Entry) { 758 Map.Entry other = (Map.Entry) o; 759 return (key == null ? other.getKey() == null : key.equals(other.getKey())) 760 && (value == null ? other.getValue() == null : value.equals(other.getValue())); 761 } 762 return false; 763 } 764 765 @Override public int hashCode() { 766 return (key == null ? 0 : key.hashCode()) 767 ^ (value == null ? 0 : value.hashCode()); 768 } 769 770 @Override public String toString() { 771 return key + "=" + value; 772 } 773 774 /** 775 * Returns the next node in an inorder traversal, or null if this is the 776 * last node in the tree. 777 */ 778 Node<K, V> next() { 779 if (right != null) { 780 return right.first(); 781 } 782 783 Node<K, V> node = this; 784 Node<K, V> parent = node.parent; 785 while (parent != null) { 786 if (parent.left == node) { 787 return parent; 788 } 789 node = parent; 790 parent = node.parent; 791 } 792 return null; 793 } 794 795 /** 796 * Returns the previous node in an inorder traversal, or null if this is 797 * the first node in the tree. 798 */ 799 public Node<K, V> prev() { 800 if (left != null) { 801 return left.last(); 802 } 803 804 Node<K, V> node = this; 805 Node<K, V> parent = node.parent; 806 while (parent != null) { 807 if (parent.right == node) { 808 return parent; 809 } 810 node = parent; 811 parent = node.parent; 812 } 813 return null; 814 } 815 816 /** 817 * Returns the first node in this subtree. 818 */ 819 public Node<K, V> first() { 820 Node<K, V> node = this; 821 Node<K, V> child = node.left; 822 while (child != null) { 823 node = child; 824 child = node.left; 825 } 826 return node; 827 } 828 829 /** 830 * Returns the last node in this subtree. 831 */ 832 public Node<K, V> last() { 833 Node<K, V> node = this; 834 Node<K, V> child = node.right; 835 while (child != null) { 836 node = child; 837 child = node.right; 838 } 839 return node; 840 } 841 } 842 843 /** 844 * Walk the nodes of the tree left-to-right or right-to-left. Note that in 845 * descending iterations, {@code next} will return the previous node. 846 */ 847 abstract class MapIterator<T> implements Iterator<T> { 848 protected Node<K, V> next; 849 protected Node<K, V> last; 850 protected int expectedModCount = modCount; 851 852 MapIterator(Node<K, V> next) { 853 this.next = next; 854 } 855 856 public boolean hasNext() { 857 return next != null; 858 } 859 860 protected Node<K, V> stepForward() { 861 if (next == null) { 862 throw new NoSuchElementException(); 863 } 864 if (modCount != expectedModCount) { 865 throw new ConcurrentModificationException(); 866 } 867 last = next; 868 next = next.next(); 869 return last; 870 } 871 872 protected Node<K, V> stepBackward() { 873 if (next == null) { 874 throw new NoSuchElementException(); 875 } 876 if (modCount != expectedModCount) { 877 throw new ConcurrentModificationException(); 878 } 879 last = next; 880 next = next.prev(); 881 return last; 882 } 883 884 public void remove() { 885 if (last == null) { 886 throw new IllegalStateException(); 887 } 888 removeInternal(last); 889 expectedModCount = modCount; 890 last = null; 891 } 892 } 893 894 /* 895 * View implementations. 896 */ 897 898 class EntrySet extends AbstractSet<Map.Entry<K, V>> { 899 @Override public int size() { 900 return size; 901 } 902 903 @Override public Iterator<Entry<K, V>> iterator() { 904 return new MapIterator<Entry<K, V>>(root == null ? null : root.first()) { 905 public Entry<K, V> next() { 906 return stepForward(); 907 } 908 }; 909 } 910 911 @Override public boolean contains(Object o) { 912 return o instanceof Entry && findByEntry((Entry<?, ?>) o) != null; 913 } 914 915 @Override public boolean remove(Object o) { 916 if (!(o instanceof Entry)) { 917 return false; 918 } 919 920 Node<K, V> node = findByEntry((Entry<?, ?>) o); 921 if (node == null) { 922 return false; 923 } 924 removeInternal(node); 925 return true; 926 } 927 928 @Override public void clear() { 929 TreeMap.this.clear(); 930 } 931 } 932 933 class KeySet extends AbstractSet<K> implements NavigableSet<K> { 934 @Override public int size() { 935 return size; 936 } 937 938 @Override public Iterator<K> iterator() { 939 return new MapIterator<K>(root == null ? null : root.first()) { 940 public K next() { 941 return stepForward().key; 942 } 943 }; 944 } 945 946 public Iterator<K> descendingIterator() { 947 return new MapIterator<K>(root == null ? null : root.last()) { 948 public K next() { 949 return stepBackward().key; 950 } 951 }; 952 } 953 954 @Override public boolean contains(Object o) { 955 return containsKey(o); 956 } 957 958 @Override public boolean remove(Object key) { 959 return removeInternalByKey(key) != null; 960 } 961 962 @Override public void clear() { 963 TreeMap.this.clear(); 964 } 965 966 public Comparator<? super K> comparator() { 967 return TreeMap.this.comparator(); 968 } 969 970 /* 971 * Navigable methods. 972 */ 973 974 public K first() { 975 return firstKey(); 976 } 977 978 public K last() { 979 return lastKey(); 980 } 981 982 public K lower(K key) { 983 return lowerKey(key); 984 } 985 986 public K floor(K key) { 987 return floorKey(key); 988 } 989 990 public K ceiling(K key) { 991 return ceilingKey(key); 992 } 993 994 public K higher(K key) { 995 return higherKey(key); 996 } 997 998 public K pollFirst() { 999 Entry<K, V> entry = internalPollFirstEntry(); 1000 return entry != null ? entry.getKey() : null; 1001 } 1002 1003 public K pollLast() { 1004 Entry<K, V> entry = internalPollLastEntry(); 1005 return entry != null ? entry.getKey() : null; 1006 } 1007 1008 /* 1009 * View factory methods. 1010 */ 1011 1012 public NavigableSet<K> subSet(K from, boolean fromInclusive, K to, boolean toInclusive) { 1013 return TreeMap.this.subMap(from, fromInclusive, to, toInclusive).navigableKeySet(); 1014 } 1015 1016 public SortedSet<K> subSet(K fromInclusive, K toExclusive) { 1017 return TreeMap.this.subMap(fromInclusive, true, toExclusive, false).navigableKeySet(); 1018 } 1019 1020 public NavigableSet<K> headSet(K to, boolean inclusive) { 1021 return TreeMap.this.headMap(to, inclusive).navigableKeySet(); 1022 } 1023 1024 public SortedSet<K> headSet(K toExclusive) { 1025 return TreeMap.this.headMap(toExclusive, false).navigableKeySet(); 1026 } 1027 1028 public NavigableSet<K> tailSet(K from, boolean inclusive) { 1029 return TreeMap.this.tailMap(from, inclusive).navigableKeySet(); 1030 } 1031 1032 public SortedSet<K> tailSet(K fromInclusive) { 1033 return TreeMap.this.tailMap(fromInclusive, true).navigableKeySet(); 1034 } 1035 1036 public NavigableSet<K> descendingSet() { 1037 return new BoundedMap(false, null, NO_BOUND, null, NO_BOUND).navigableKeySet(); 1038 } 1039 } 1040 1041 /* 1042 * Bounded views implementations. 1043 */ 1044 1045 enum Bound { 1046 INCLUSIVE { 1047 @Override public String leftCap(Object from) { 1048 return "[" + from; 1049 } 1050 @Override public String rightCap(Object to) { 1051 return to + "]"; 1052 } 1053 }, 1054 EXCLUSIVE { 1055 @Override public String leftCap(Object from) { 1056 return "(" + from; 1057 } 1058 @Override public String rightCap(Object to) { 1059 return to + ")"; 1060 } 1061 }, 1062 NO_BOUND { 1063 @Override public String leftCap(Object from) { 1064 return "."; 1065 } 1066 @Override public String rightCap(Object to) { 1067 return "."; 1068 } 1069 }; 1070 1071 public abstract String leftCap(Object from); 1072 public abstract String rightCap(Object to); 1073 } 1074 1075 /** 1076 * A map with optional limits on its range. 1077 */ 1078 final class BoundedMap extends AbstractMap<K, V> implements NavigableMap<K, V>, Serializable { 1079 private final transient boolean ascending; 1080 private final transient K from; 1081 private final transient Bound fromBound; 1082 private final transient K to; 1083 private final transient Bound toBound; 1084 1085 BoundedMap(boolean ascending, K from, Bound fromBound, K to, Bound toBound) { 1086 /* 1087 * Validate the bounds. In addition to checking that from <= to, we 1088 * verify that the comparator supports our bound objects. 1089 */ 1090 if (fromBound != NO_BOUND && toBound != NO_BOUND) { 1091 if (comparator.compare(from, to) > 0) { 1092 throw new IllegalArgumentException(from + " > " + to); 1093 } 1094 } else if (fromBound != NO_BOUND) { 1095 comparator.compare(from, from); 1096 } else if (toBound != NO_BOUND) { 1097 comparator.compare(to, to); 1098 } 1099 1100 this.ascending = ascending; 1101 this.from = from; 1102 this.fromBound = fromBound; 1103 this.to = to; 1104 this.toBound = toBound; 1105 } 1106 1107 @Override public int size() { 1108 return count(entrySet().iterator()); 1109 } 1110 1111 @Override public boolean isEmpty() { 1112 return endpoint(true) == null; 1113 } 1114 1115 @Override public V get(Object key) { 1116 return isInBounds(key) ? TreeMap.this.get(key) : null; 1117 } 1118 1119 @Override public boolean containsKey(Object key) { 1120 return isInBounds(key) && TreeMap.this.containsKey(key); 1121 } 1122 1123 @Override public V put(K key, V value) { 1124 if (!isInBounds(key)) { 1125 throw outOfBounds(key, fromBound, toBound); 1126 } 1127 return putInternal(key, value); 1128 } 1129 1130 @Override public V remove(Object key) { 1131 return isInBounds(key) ? TreeMap.this.remove(key) : null; 1132 } 1133 1134 /** 1135 * Returns true if the key is in bounds. 1136 */ 1137 @SuppressWarnings("unchecked") // this method throws ClassCastExceptions! 1138 private boolean isInBounds(Object key) { 1139 return isInBounds((K) key, fromBound, toBound); 1140 } 1141 1142 /** 1143 * Returns true if the key is in bounds. Use this overload with 1144 * NO_BOUND to skip bounds checking on either end. 1145 */ 1146 private boolean isInBounds(K key, Bound fromBound, Bound toBound) { 1147 if (fromBound == INCLUSIVE) { 1148 if (comparator.compare(key, from) < 0) { 1149 return false; // less than from 1150 } 1151 } else if (fromBound == EXCLUSIVE) { 1152 if (comparator.compare(key, from) <= 0) { 1153 return false; // less than or equal to from 1154 } 1155 } 1156 1157 if (toBound == INCLUSIVE) { 1158 if (comparator.compare(key, to) > 0) { 1159 return false; // greater than 'to' 1160 } 1161 } else if (toBound == EXCLUSIVE) { 1162 if (comparator.compare(key, to) >= 0) { 1163 return false; // greater than or equal to 'to' 1164 } 1165 } 1166 1167 return true; 1168 } 1169 1170 /** 1171 * Returns the entry if it is in bounds, or null if it is out of bounds. 1172 */ 1173 private Node<K, V> bound(Node<K, V> node, Bound fromBound, Bound toBound) { 1174 return node != null && isInBounds(node.getKey(), fromBound, toBound) ? node : null; 1175 } 1176 1177 /* 1178 * Navigable methods. 1179 */ 1180 1181 public Entry<K, V> firstEntry() { 1182 return immutableCopy(endpoint(true)); 1183 } 1184 1185 public Entry<K, V> pollFirstEntry() { 1186 Node<K, V> result = endpoint(true); 1187 if (result != null) { 1188 removeInternal(result); 1189 } 1190 return immutableCopy(result); 1191 } 1192 1193 public K firstKey() { 1194 Entry<K, V> entry = endpoint(true); 1195 if (entry == null) { 1196 throw new NoSuchElementException(); 1197 } 1198 return entry.getKey(); 1199 } 1200 1201 public Entry<K, V> lastEntry() { 1202 return immutableCopy(endpoint(false)); 1203 } 1204 1205 public Entry<K, V> pollLastEntry() { 1206 Node<K, V> result = endpoint(false); 1207 if (result != null) { 1208 removeInternal(result); 1209 } 1210 return immutableCopy(result); 1211 } 1212 1213 public K lastKey() { 1214 Entry<K, V> entry = endpoint(false); 1215 if (entry == null) { 1216 throw new NoSuchElementException(); 1217 } 1218 return entry.getKey(); 1219 } 1220 1221 /** 1222 * @param first true for the first element, false for the last. 1223 */ 1224 private Node<K, V> endpoint(boolean first) { 1225 Node<K, V> node; 1226 if (ascending == first) { 1227 switch (fromBound) { 1228 case NO_BOUND: 1229 node = root == null ? null : root.first(); 1230 break; 1231 case INCLUSIVE: 1232 node = find(from, CEILING); 1233 break; 1234 case EXCLUSIVE: 1235 node = find(from, HIGHER); 1236 break; 1237 default: 1238 throw new AssertionError(); 1239 } 1240 return bound(node, NO_BOUND, toBound); 1241 } else { 1242 switch (toBound) { 1243 case NO_BOUND: 1244 node = root == null ? null : root.last(); 1245 break; 1246 case INCLUSIVE: 1247 node = find(to, FLOOR); 1248 break; 1249 case EXCLUSIVE: 1250 node = find(to, LOWER); 1251 break; 1252 default: 1253 throw new AssertionError(); 1254 } 1255 return bound(node, fromBound, NO_BOUND); 1256 } 1257 } 1258 1259 /** 1260 * Performs a find on the underlying tree after constraining it to the 1261 * bounds of this view. Examples: 1262 * 1263 * bound is (A..C) 1264 * findBounded(B, FLOOR) stays source.find(B, FLOOR) 1265 * 1266 * bound is (A..C) 1267 * findBounded(C, FLOOR) becomes source.find(C, LOWER) 1268 * 1269 * bound is (A..C) 1270 * findBounded(D, LOWER) becomes source.find(C, LOWER) 1271 * 1272 * bound is (A..C] 1273 * findBounded(D, FLOOR) becomes source.find(C, FLOOR) 1274 * 1275 * bound is (A..C] 1276 * findBounded(D, LOWER) becomes source.find(C, FLOOR) 1277 */ 1278 private Entry<K, V> findBounded(K key, Relation relation) { 1279 relation = relation.forOrder(ascending); 1280 Bound fromBoundForCheck = fromBound; 1281 Bound toBoundForCheck = toBound; 1282 1283 if (toBound != NO_BOUND && (relation == LOWER || relation == FLOOR)) { 1284 int comparison = comparator.compare(to, key); 1285 if (comparison <= 0) { 1286 key = to; 1287 if (toBound == EXCLUSIVE) { 1288 relation = LOWER; // 'to' is too high 1289 } else if (comparison < 0) { 1290 relation = FLOOR; // we already went lower 1291 } 1292 } 1293 toBoundForCheck = NO_BOUND; // we've already checked the upper bound 1294 } 1295 1296 if (fromBound != NO_BOUND && (relation == CEILING || relation == HIGHER)) { 1297 int comparison = comparator.compare(from, key); 1298 if (comparison >= 0) { 1299 key = from; 1300 if (fromBound == EXCLUSIVE) { 1301 relation = HIGHER; // 'from' is too low 1302 } else if (comparison > 0) { 1303 relation = CEILING; // we already went higher 1304 } 1305 } 1306 fromBoundForCheck = NO_BOUND; // we've already checked the lower bound 1307 } 1308 1309 return bound(find(key, relation), fromBoundForCheck, toBoundForCheck); 1310 } 1311 1312 public Entry<K, V> lowerEntry(K key) { 1313 return immutableCopy(findBounded(key, LOWER)); 1314 } 1315 1316 public K lowerKey(K key) { 1317 Entry<K, V> entry = findBounded(key, LOWER); 1318 return entry != null ? entry.getKey() : null; 1319 } 1320 1321 public Entry<K, V> floorEntry(K key) { 1322 return immutableCopy(findBounded(key, FLOOR)); 1323 } 1324 1325 public K floorKey(K key) { 1326 Entry<K, V> entry = findBounded(key, FLOOR); 1327 return entry != null ? entry.getKey() : null; 1328 } 1329 1330 public Entry<K, V> ceilingEntry(K key) { 1331 return immutableCopy(findBounded(key, CEILING)); 1332 } 1333 1334 public K ceilingKey(K key) { 1335 Entry<K, V> entry = findBounded(key, CEILING); 1336 return entry != null ? entry.getKey() : null; 1337 } 1338 1339 public Entry<K, V> higherEntry(K key) { 1340 return immutableCopy(findBounded(key, HIGHER)); 1341 } 1342 1343 public K higherKey(K key) { 1344 Entry<K, V> entry = findBounded(key, HIGHER); 1345 return entry != null ? entry.getKey() : null; 1346 } 1347 1348 public Comparator<? super K> comparator() { 1349 if (ascending) { 1350 return TreeMap.this.comparator(); 1351 } else { 1352 return Collections.reverseOrder(comparator); 1353 } 1354 } 1355 1356 /* 1357 * View factory methods. 1358 */ 1359 1360 private transient BoundedEntrySet entrySet; 1361 private transient BoundedKeySet keySet; 1362 1363 @Override public Set<Entry<K, V>> entrySet() { 1364 BoundedEntrySet result = entrySet; 1365 return result != null ? result : (entrySet = new BoundedEntrySet()); 1366 } 1367 1368 @Override public Set<K> keySet() { 1369 return navigableKeySet(); 1370 } 1371 1372 public NavigableSet<K> navigableKeySet() { 1373 BoundedKeySet result = keySet; 1374 return result != null ? result : (keySet = new BoundedKeySet()); 1375 } 1376 1377 public NavigableMap<K, V> descendingMap() { 1378 return new BoundedMap(!ascending, from, fromBound, to, toBound); 1379 } 1380 1381 public NavigableSet<K> descendingKeySet() { 1382 return new BoundedMap(!ascending, from, fromBound, to, toBound).navigableKeySet(); 1383 } 1384 1385 public NavigableMap<K, V> subMap(K from, boolean fromInclusive, K to, boolean toInclusive) { 1386 Bound fromBound = fromInclusive ? INCLUSIVE : EXCLUSIVE; 1387 Bound toBound = toInclusive ? INCLUSIVE : EXCLUSIVE; 1388 return subMap(from, fromBound, to, toBound); 1389 } 1390 1391 public NavigableMap<K, V> subMap(K fromInclusive, K toExclusive) { 1392 return subMap(fromInclusive, INCLUSIVE, toExclusive, EXCLUSIVE); 1393 } 1394 1395 public NavigableMap<K, V> headMap(K to, boolean inclusive) { 1396 Bound toBound = inclusive ? INCLUSIVE : EXCLUSIVE; 1397 return subMap(null, NO_BOUND, to, toBound); 1398 } 1399 1400 public NavigableMap<K, V> headMap(K toExclusive) { 1401 return subMap(null, NO_BOUND, toExclusive, EXCLUSIVE); 1402 } 1403 1404 public NavigableMap<K, V> tailMap(K from, boolean inclusive) { 1405 Bound fromBound = inclusive ? INCLUSIVE : EXCLUSIVE; 1406 return subMap(from, fromBound, null, NO_BOUND); 1407 } 1408 1409 public NavigableMap<K, V> tailMap(K fromInclusive) { 1410 return subMap(fromInclusive, INCLUSIVE, null, NO_BOUND); 1411 } 1412 1413 private NavigableMap<K, V> subMap(K from, Bound fromBound, K to, Bound toBound) { 1414 if (!ascending) { 1415 K fromTmp = from; 1416 Bound fromBoundTmp = fromBound; 1417 from = to; 1418 fromBound = toBound; 1419 to = fromTmp; 1420 toBound = fromBoundTmp; 1421 } 1422 1423 /* 1424 * If both the current and requested bounds are exclusive, the isInBounds check must be 1425 * inclusive. For example, to create (C..F) from (A..F), the bound 'F' is in bounds. 1426 */ 1427 1428 if (fromBound == NO_BOUND) { 1429 from = this.from; 1430 fromBound = this.fromBound; 1431 } else { 1432 Bound fromBoundToCheck = fromBound == this.fromBound ? INCLUSIVE : this.fromBound; 1433 if (!isInBounds(from, fromBoundToCheck, this.toBound)) { 1434 throw outOfBounds(to, fromBoundToCheck, this.toBound); 1435 } 1436 } 1437 1438 if (toBound == NO_BOUND) { 1439 to = this.to; 1440 toBound = this.toBound; 1441 } else { 1442 Bound toBoundToCheck = toBound == this.toBound ? INCLUSIVE : this.toBound; 1443 if (!isInBounds(to, this.fromBound, toBoundToCheck)) { 1444 throw outOfBounds(to, this.fromBound, toBoundToCheck); 1445 } 1446 } 1447 1448 return new BoundedMap(ascending, from, fromBound, to, toBound); 1449 } 1450 1451 private IllegalArgumentException outOfBounds(Object value, Bound fromBound, Bound toBound) { 1452 return new IllegalArgumentException(value + " not in range " 1453 + fromBound.leftCap(from) + ".." + toBound.rightCap(to)); 1454 } 1455 1456 /* 1457 * Bounded view implementations. 1458 */ 1459 1460 abstract class BoundedIterator<T> extends MapIterator<T> { 1461 protected BoundedIterator(Node<K, V> next) { 1462 super(next); 1463 } 1464 1465 @Override protected Node<K, V> stepForward() { 1466 Node<K, V> result = super.stepForward(); 1467 if (next != null && !isInBounds(next.key, NO_BOUND, toBound)) { 1468 next = null; 1469 } 1470 return result; 1471 } 1472 1473 @Override protected Node<K, V> stepBackward() { 1474 Node<K, V> result = super.stepBackward(); 1475 if (next != null && !isInBounds(next.key, fromBound, NO_BOUND)) { 1476 next = null; 1477 } 1478 return result; 1479 } 1480 } 1481 1482 final class BoundedEntrySet extends AbstractSet<Entry<K, V>> { 1483 @Override public int size() { 1484 return BoundedMap.this.size(); 1485 } 1486 1487 @Override public boolean isEmpty() { 1488 return BoundedMap.this.isEmpty(); 1489 } 1490 1491 @Override public Iterator<Entry<K, V>> iterator() { 1492 return new BoundedIterator<Entry<K, V>>(endpoint(true)) { 1493 public Entry<K, V> next() { 1494 return ascending ? stepForward() : stepBackward(); 1495 } 1496 }; 1497 } 1498 1499 @Override public boolean contains(Object o) { 1500 if (!(o instanceof Entry)) { 1501 return false; 1502 } 1503 Entry<?, ?> entry = (Entry<?, ?>) o; 1504 return isInBounds(entry.getKey()) && findByEntry(entry) != null; 1505 } 1506 1507 @Override public boolean remove(Object o) { 1508 if (!(o instanceof Entry)) { 1509 return false; 1510 } 1511 Entry<?, ?> entry = (Entry<?, ?>) o; 1512 return isInBounds(entry.getKey()) && TreeMap.this.entrySet().remove(entry); 1513 } 1514 } 1515 1516 final class BoundedKeySet extends AbstractSet<K> implements NavigableSet<K> { 1517 @Override public int size() { 1518 return BoundedMap.this.size(); 1519 } 1520 1521 @Override public boolean isEmpty() { 1522 return BoundedMap.this.isEmpty(); 1523 } 1524 1525 @Override public Iterator<K> iterator() { 1526 return new BoundedIterator<K>(endpoint(true)) { 1527 public K next() { 1528 return (ascending ? stepForward() : stepBackward()).key; 1529 } 1530 }; 1531 } 1532 1533 public Iterator<K> descendingIterator() { 1534 return new BoundedIterator<K>(endpoint(false)) { 1535 public K next() { 1536 return (ascending ? stepBackward() : stepForward()).key; 1537 } 1538 }; 1539 } 1540 1541 @Override public boolean contains(Object key) { 1542 return isInBounds(key) && findByObject(key) != null; 1543 } 1544 1545 @Override public boolean remove(Object key) { 1546 return isInBounds(key) && removeInternalByKey(key) != null; 1547 } 1548 1549 /* 1550 * Navigable methods. 1551 */ 1552 1553 public K first() { 1554 return firstKey(); 1555 } 1556 1557 public K pollFirst() { 1558 Entry<K, ?> entry = pollFirstEntry(); 1559 return entry != null ? entry.getKey() : null; 1560 } 1561 1562 public K last() { 1563 return lastKey(); 1564 } 1565 1566 public K pollLast() { 1567 Entry<K, ?> entry = pollLastEntry(); 1568 return entry != null ? entry.getKey() : null; 1569 } 1570 1571 public K lower(K key) { 1572 return lowerKey(key); 1573 } 1574 1575 public K floor(K key) { 1576 return floorKey(key); 1577 } 1578 1579 public K ceiling(K key) { 1580 return ceilingKey(key); 1581 } 1582 1583 public K higher(K key) { 1584 return higherKey(key); 1585 } 1586 1587 public Comparator<? super K> comparator() { 1588 return BoundedMap.this.comparator(); 1589 } 1590 1591 /* 1592 * View factory methods. 1593 */ 1594 1595 public NavigableSet<K> subSet(K from, boolean fromInclusive, K to, boolean toInclusive) { 1596 return subMap(from, fromInclusive, to, toInclusive).navigableKeySet(); 1597 } 1598 1599 public SortedSet<K> subSet(K fromInclusive, K toExclusive) { 1600 return subMap(fromInclusive, toExclusive).navigableKeySet(); 1601 } 1602 1603 public NavigableSet<K> headSet(K to, boolean inclusive) { 1604 return headMap(to, inclusive).navigableKeySet(); 1605 } 1606 1607 public SortedSet<K> headSet(K toExclusive) { 1608 return headMap(toExclusive).navigableKeySet(); 1609 } 1610 1611 public NavigableSet<K> tailSet(K from, boolean inclusive) { 1612 return tailMap(from, inclusive).navigableKeySet(); 1613 } 1614 1615 public SortedSet<K> tailSet(K fromInclusive) { 1616 return tailMap(fromInclusive).navigableKeySet(); 1617 } 1618 1619 public NavigableSet<K> descendingSet() { 1620 return new BoundedMap(!ascending, from, fromBound, to, toBound).navigableKeySet(); 1621 } 1622 } 1623 1624 Object writeReplace() throws ObjectStreamException { 1625 return ascending 1626 ? new AscendingSubMap<K, V>(TreeMap.this, from, fromBound, to, toBound) 1627 : new DescendingSubMap<K, V>(TreeMap.this, from, fromBound, to, toBound); 1628 } 1629 } 1630 1631 /** 1632 * Returns the number of elements in the iteration. 1633 */ 1634 static int count(Iterator<?> iterator) { 1635 int count = 0; 1636 while (iterator.hasNext()) { 1637 iterator.next(); 1638 count++; 1639 } 1640 return count; 1641 } 1642 1643 /* 1644 * Serialization 1645 */ 1646 1647 private static final long serialVersionUID = 919286545866124006L; 1648 1649 private void writeObject(ObjectOutputStream stream) throws IOException { 1650 stream.putFields().put("comparator", comparator != NATURAL_ORDER ? comparator : null); 1651 stream.writeFields(); 1652 stream.writeInt(size); 1653 for (Map.Entry<K, V> entry : entrySet()) { 1654 stream.writeObject(entry.getKey()); 1655 stream.writeObject(entry.getValue()); 1656 } 1657 } 1658 1659 @SuppressWarnings("unchecked") // we have to trust that keys are Ks and values are Vs 1660 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 1661 GetField fields = stream.readFields(); 1662 comparator = (Comparator<? super K>) fields.get("comparator", null); 1663 if (comparator == null) { 1664 comparator = (Comparator<? super K>) NATURAL_ORDER; 1665 } 1666 int size = stream.readInt(); 1667 for (int i = 0; i < size; i++) { 1668 putInternal((K) stream.readObject(), (V) stream.readObject()); 1669 } 1670 } 1671 1672 static abstract class NavigableSubMap<K, V> extends AbstractMap<K, V> implements Serializable { 1673 private static final long serialVersionUID = -2102997345730753016L; 1674 TreeMap<K, V> m; 1675 Object lo; 1676 Object hi; 1677 boolean fromStart; 1678 boolean toEnd; 1679 boolean loInclusive; 1680 boolean hiInclusive; 1681 1682 NavigableSubMap(TreeMap<K, V> delegate, K from, Bound fromBound, K to, Bound toBound) { 1683 this.m = delegate; 1684 this.lo = from; 1685 this.hi = to; 1686 this.fromStart = fromBound == NO_BOUND; 1687 this.toEnd = toBound == NO_BOUND; 1688 this.loInclusive = fromBound == INCLUSIVE; 1689 this.hiInclusive = toBound == INCLUSIVE; 1690 } 1691 1692 @Override public Set<Entry<K, V>> entrySet() { 1693 throw new UnsupportedOperationException(); 1694 } 1695 1696 @SuppressWarnings("unchecked") // we have to trust that the bounds are Ks 1697 protected Object readResolve() throws ObjectStreamException { 1698 Bound fromBound = fromStart ? NO_BOUND : (loInclusive ? INCLUSIVE : EXCLUSIVE); 1699 Bound toBound = toEnd ? NO_BOUND : (hiInclusive ? INCLUSIVE : EXCLUSIVE); 1700 boolean ascending = !(this instanceof DescendingSubMap); 1701 return m.new BoundedMap(ascending, (K) lo, fromBound, (K) hi, toBound); 1702 } 1703 } 1704 1705 static class DescendingSubMap<K, V> extends NavigableSubMap<K, V> { 1706 private static final long serialVersionUID = 912986545866120460L; 1707 Comparator<K> reverseComparator; 1708 DescendingSubMap(TreeMap<K, V> delegate, K from, Bound fromBound, K to, Bound toBound) { 1709 super(delegate, from, fromBound, to, toBound); 1710 } 1711 } 1712 1713 static class AscendingSubMap<K, V> extends NavigableSubMap<K, V> { 1714 private static final long serialVersionUID = 912986545866124060L; 1715 AscendingSubMap(TreeMap<K, V> delegate, K from, Bound fromBound, K to, Bound toBound) { 1716 super(delegate, from, fromBound, to, toBound); 1717 } 1718 } 1719 1720 class SubMap extends AbstractMap<K, V> implements Serializable { 1721 private static final long serialVersionUID = -6520786458950516097L; 1722 Object fromKey; 1723 Object toKey; 1724 boolean fromStart; 1725 boolean toEnd; 1726 1727 @Override public Set<Entry<K, V>> entrySet() { 1728 throw new UnsupportedOperationException(); 1729 } 1730 1731 @SuppressWarnings("unchecked") // we have to trust that the bounds are Ks 1732 protected Object readResolve() throws ObjectStreamException { 1733 Bound fromBound = fromStart ? NO_BOUND : INCLUSIVE; 1734 Bound toBound = toEnd ? NO_BOUND : EXCLUSIVE; 1735 return new BoundedMap(true, (K) fromKey, fromBound, (K) toKey, toBound); 1736 } 1737 } 1738 }
|
Implementations |
|||||
Hash Table |
Resizable Array |
Balanced Tree |
Linked List |
Hash Table + Linked List |
||
Interfaces |
Set |
|
|
|||
List |
|
|
|
|||
Deque |
|
|
|
|||
Map |
|
|
是否有序 |
是否允许重复 |
是否线程同步 |
||
Collection |
否 |
是 |
|
|
List |
ArrayList |
是 |
是 |
否 |
Vector |
是 |
|||
LinkedList |
否 |
|||
Set |
HashSet |
否 |
否 |
否 |
TreeSet |
是 |
否 |
||
Map |
HashMap |
否 |
<key, value>, key不允许重复 |
否 |
TreeMap |
是 |
否 |
||
Hashtable |
否 |
是 |
How to use:http://www.cnblogs.com/kiant71/archive/2008/09/04/1752079.html