Collections类提供了一些列静态的方法,用以更方便地操作集合类
排序机制
一个List可以通过下面的方法进行排序:
Collections.sort(list);
如果List包含的是字符串,将会按照字母表排序;如果List包含的是Date类型数据,会按照日期先后排序……这是怎么实现的呢?String和Date都实现了comparable接口,此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo 方法被称为它的自然比较方法。
实现此接口的对象列表(和数组)可以通过Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
对于类 C 的每一个 e1 和 e2 来说,当且仅当e1.compareTo(e2) == 0 与e1.equals(e2) 具有相同的 boolean值时,类 C 的自然排序才叫做与 equals 一致。注意,null 不是任何类的实例,即使e.equals(null) 返回 false,e.compareTo(null) 也将抛出 NullPointerException。
建议(虽然不是必需的)最好使自然排序与equals 一致。这是因为在使用自然排序与 equals 不一致的元素(或键)时,没有显式比较器的有序集合(和有序映射表)行为表现“怪异”。尤其是,这样的有序集合(或有序映射表)违背了根据 equals 方法定义的集合(或映射表)的常规协定。
例如,如果将两个键 a 和 b 添加到没有使用显式比较器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那么第二个 add 操作将返回 false(有序集合的大小没有增加),因为从有序集合的角度来看,a 和 b 是相等的。
实际上,所有实现 Comparable 的 Java 核心类都具有与equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(比如 4.0 和 4.00)视为相等。
如果试图对一个没有实现comparable接口的类进行排序,会抛出ClassCastException
Comparable接口包含下面的方法:
public interface Comparable<T> {
public int compareTo(T o);
}
compareTo方法比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。实现类必须确保对于所有的 x 和 y 都存在sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) 的关系。(这意味着如果 y.compareTo(x)抛出一个异常,则 x.compareTo(y) 也要抛出一个异常。)
实现类还必须确保关系是可传递的:(x.compareTo(y)>0&& y.compareTo(z)>0) 意味着 x.compareTo(z)>0。
最后,实现者必须确保x.compareTo(y)==0 意味着对于所有的 z,都存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))。 强烈推荐(x.compareTo(y)==0) == (x.equals(y)) 这种做法,但并不是严格要求这样做。
在前面的描述中,符号sgn(expression) 指定 signum 数学函数,该函数根据 expression 的值是负数、零还是正数,分别返回 -1、0 或 1 中的一个值。
下面来看一个实例:
public class Name implements Comparable<Name> {
private final String firstName, lastName;
public Name(String firstName, StringlastName) {
if (firstName == null || lastName ==null)
throw new NullPointerException();
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() { return firstName;}
public String lastName() { return lastName; }
//覆写equals方法
public boolean equals(Object o) {
if (!(o instanceof Name))
return false;
Name n = (Name) o;
return n.firstName.equals(firstName)&& n.lastName.equals(lastName);
}
//覆写了equals方法则必须覆写hashCode方法,相同的类必须有相同的哈希码
public int hashCode(){
return 31*firstName.hashCode() +lastName.hashCode();
}
public String toString() {
return firstName + " " + lastName;
}
//当姓氏和名字都一样时,才认为该类相同
public int compareTo(Name n) {
int lastCmp =lastName.compareTo(n.lastName);
//先比较姓氏,如果姓氏相同,再比较名字
return (lastCmp != 0 ? lastCmp :firstName.compareTo(n.firstName));
}
}
测试类
Name nameArray []= {
new Name("John","Smith"),
new Name("Karl","Ng"),
new Name("Jeff","Smith"),
new Name("Tom","Rich")
};
List<Name> names =Arrays.asList(nameArray);
Collections.sort(names);
System.out.println(names);
输出:
[Karl Ng, TomRich, Jeff Smith, John Smith]
如果我们不想按照自然排序,而是希望以一种特殊的方式排序呢?这是就需要提供一个Comparator。跟Comparable接口一样,该接口也只包含一个方法:
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparator提供了强行对某个对象collection 进行整体排序的比较函数。可以将 Comparator传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。
当使用具有与 equals 不一致的强行排序能力的Comparator 对有序 set(或有序映射)进行排序时,应该小心谨慎。假定一个带显式 Comparator c 的有序 set(或有序映射)与从 set S 中抽取出来的元素(或键)一起使用。如果 c 强行对 S 进行的排序是与 equals 不一致的,那么有序 set(或有序映射)将是行为“怪异的”。尤其是有序 set(或有序映射)将违背根据 equals 所定义的 set(或映射)的常规协定。
例如,假定使用 Comparator c 将满足(a.equals(b) && c.compare(a, b) != 0) 的两个元素 a 和 b 添加到一个空TreeSet 中,则第二个 add 操作将返回 true(树 set 的大小将会增加),因为从树 set 的角度来看,a 和 b 是不相等的,即使这与 Set.add 方法的规范相反。
来看一个实例:
public class Employee implements Comparable<Employee> {
public Name name() { ... }
public int number() { ... }
public Date hireDate() { ... }
...
}
员工类包含员工的姓名、工号、入职日期等属性,并且实现了Comparable接口,它的自然排序是按照Name来排序的(具体代码见上面的Name类)。假如现在我们不想让它按照Name来排序,而是按照入职日期来排序,利用Comparator来实现:
static final Comparator<Employee> SENIORITY_ORDER =
new Comparator<Employee>() {
public int compare(Employee e1,Employee e2) {
//根据入职日期进行排序,本质上还是利用了Date类型的compareTo方法
return e2.hireDate().compareTo(e1.hireDate());
}
};
// Employee database
static final Collection<Employee>employees = ... ;
public static void main(String[] args) {
List<Employee> e = new ArrayList<Employee>(employees);
Collections.sort(e, SENIORITY_ORDER); //传入指定的比较器
System.out.println(e);
}
同步“包装”机制
通用的集合类都是线程不安全的,如果需要线程安全的集合类,可以通过Collections类的包装对它们进行转换。
六个核心的接口都有一个静态的工厂方法:
public static <T> Collection<T>synchronizedCollection(Collection<T> c);
public static <T> Set<T> synchronizedSet(Set<T>s);
public static <T> List<T> synchronizedList(List<T>list);
public static <K,V> Map<K,V>synchronizedMap(Map<K,V> m);
public static <T> SortedSet<T>synchronizedSortedSet(SortedSet<T> s);
public static <K,V> SortedMap<K,V>synchronizedSortedMap(SortedMap<K,V> m);
例如,通过下面的这行语句:
List<Type>list = Collections.synchronizedList(new ArrayList<Type>());
我们就得到了一个线程安全的List
在多线程的情况下,使用者在进行迭代的时候需要注意集合的同步状态,推荐的做法是这样:
Collection<Type> c = Collections.synchronizedCollection(myCollection);
synchronized(c){
for (Type e : c)
foo(e);
}
如果使用的是显式迭代器,Iterator方法必须在同步快中调用。对Map的视图进行迭代时也是同样的要求。
Map<KeyType,ValType> m = Collections.synchronizedMap(new HashMap<KeyType,ValType>());
...
Set<KeyType> s = m.keySet();
...
// Synchronizingon m, not s!
synchronized(m){
while (KeyType k : s)
foo(k);
}
方法列表
static <T>boolean addAll(Collection<? superT> c, T... elements)
将所有指定元素添加到指定collection 中。
static <T>int binarySearch(List<? extendsComparable<? super T>> list, T key)
使用二分搜索法搜索指定列表,以获得指定对象。
static <E>Collection<E> checkedCollection(Collection<E>c, Class<E> type)
返回指定 collection 的一个动态类型安全视图。
static <E>List<E> checkedList(List<E>list, Class<E> type)
返回指定列表的一个动态类型安全视图。
static<K,V> Map<K,V> checkedMap(Map<K,V>m, Class<K> keyType, Class<V> valueType)
返回指定映射的一个动态类型安全视图。
static <E>Set<E> checkedSet(Set<E>s, Class<E> type)
返回指定 set 的一个动态类型安全视图。
static<K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K,V>m, Class<K> keyType, Class<V> valueType)
返回指定有序映射的一个动态类型安全视图。
static <E>SortedSet<E> checkedSortedSet(SortedSet<E>s, Class<E> type)
返回指定有序 set 的一个动态类型安全视图。
static <T>void copy(List<? super T>dest, List<? extends T> src)
将所有元素从一个列表复制到另一个列表。
static boolean disjoint(Collection<?> c1,Collection<?> c2)
如果两个指定 collection 中没有相同的元素,则返回true。
static <T>List<T> emptyList()
返回空的列表(不可变的)。
static<K,V> Map<K,V> emptyMap()
返回空的映射(不可变的)。
static <T>Set<T> emptySet()
返回空的 set(不可变的)。
static <T>Enumeration<T> enumeration(Collection<T>c)
返回一个指定 collection 上的枚举。
static <T>void fill(List<? super T>list, T obj)
使用指定元素替换指定列表中的所有元素。
static int frequency(Collection<?> c, Objecto)
返回指定 collection 中等于指定对象的元素数。
static int indexOfSubList(List<?> source,List<?> target)
返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
static int lastIndexOfSubList(List<?>source, List<?> target)
返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
static <T>ArrayList<T> list(Enumeration<T>e)
返回一个数组列表,它按返回顺序包含指定枚举返回的元素。
static <Textends Object & Comparable<? super T>> T max(Collection<?extends T> coll)
根据元素的自然顺序,返回给定collection 的最大元素。
static <Textends Object & Comparable<? super T>> Tmin(Collection<? extends T> coll)
根据元素的自然顺序 返回给定 collection 的最小元素。
static <T>List<T> nCopies(int n, T o)
返回由指定对象的 n 个副本组成的不可变列表。
static <T>boolean replaceAll(List<T> list, T oldVal, T newVal)
使用另一个值替换列表中出现的所有某一指定值。
static void reverse(List<?> list)
反转指定列表中元素的顺序。
static void rotate(List<?> list, int distance)
根据指定的距离轮换指定列表中的元素。
static void shuffle(List<?> list)
使用默认随机源对指定列表进行置换。
static <T>Set<T> singleton(T o)
返回一个只包含指定对象的不可变 set。
static <T>List<T> singletonList(T o)
返回一个只包含指定对象的不可变列表。
static<K,V> Map<K,V> singletonMap(Kkey, V value)
返回一个不可变的映射,它只将指定键映射到指定值。
static <Textends Comparable<? super T>> voidsort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序。
static void swap(List<?> list, int i, int j)
在指定列表的指定位置处交换元素。
static <T>Collection<T> synchronizedCollection(Collection<T>c)
返回指定 collection 支持的同步(线程安全的)collection。
static <T>List<T> synchronizedList(List<T>list)
返回指定列表支持的同步(线程安全的)列表。
static<K,V> Map<K,V> synchronizedMap(Map<K,V>m)
返回由指定映射支持的同步(线程安全的)映射。
static <T>Set<T> synchronizedSet(Set<T>s)
返回指定 set 支持的同步(线程安全的)set。
static<K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V>m)
返回指定有序映射支持的同步(线程安全的)有序映射。
static <T>SortedSet<T> synchronizedSortedSet(SortedSet<T>s)
返回指定有序 set 支持的同步(线程安全的)有序 set。
static <T>Collection<T> unmodifiableCollection(Collection<?extends T> c)
返回指定 collection 的不可修改视图。
static <T>List<T> unmodifiableList(List<?extends T> list)
返回指定列表的不可修改视图。
static<K,V> Map<K,V> unmodifiableMap(Map<?extends K,? extends V> m)
返回指定映射的不可修改视图。
static <T>Set<T> unmodifiableSet(Set<?extends T> s)
返回指定 set 的不可修改视图。
static<K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,?extends V> m)
返回指定有序映射的不可修改视图。
static <T>SortedSet<T> unmodifiableSortedSet(SortedSet<T>s)
返回指定有序 set 的不可修改视图。
相关文章
- Java集合框架:Collections工具类
- 黑马程序员——Java基础---泛型、集合框架工具类:Collections和Arrays、JDK 1.5新特性
- Java集合框架之Collections工具类
- Java基础学习笔记之七(1)--Collection接口&Collections集合工具类
- 黑马程序员--泛型、集合框架工具类:collections和Arrays
- 黑马程序员_温习 集合六 (个人笔记)摘要(Collections集合工具类-----Arrays数组工具类-----高级for----可变参数----静态导入)
- Java基础---泛型、集合框架工具类:collections和Arrays
- 黑马程序员:Collections:集合框架工具类介绍及二分法原理介绍
- 黑马程序员——Map接口的使用,泛型机制,集合框架工具类Collections的使用
- JAVA基础学习之 Map集合、集合框架工具类Collections,Arrays、可变参数、List和Set集合框架什么时候使用等(4)