集合框架之Collections静态工具类
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 的不可修改视图。
集合框架之Collections静态工具类的更多相关文章
- java内部类、接口、集合框架、泛型、工具类、实现类
.t1 { background-color: #ff8080; width: 1100px; height: 40px } 一.内部类 1.成员内部类. (1)成员内部类的实例化: 外部类名.内部类 ...
- Java集合框架GS Collections具体解释
Java集合框架GS Collections具体解释 作者:chszs.未经博主同意不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs GS Collec ...
- java基础课程笔记 static 主函数 静态工具类 classpath java文档注释 静态代码块 对象初始化过程 设计模式 继承 子父类中的函数 继承中的构造函数 对象转型 多态 封装 抽象类 final 接口 包 jar包
Static那些事儿 Static关键字 被static修饰的变量成为静态变量(类变量) 作用:是一个修饰符,用于修饰成员(成员变量,成员方法) 1.被static修饰后的成员变量只有一份 2.当成员 ...
- Java集合框架:Collections工具类
java.util.Collections工具类提供非常多实用的方法.使得程序员操作集合类的时候更加的方便easy,这些方法都是静态的. 整个Collections工具类源代码几乎相同有4000行.我 ...
- JDK1.6新特性,基础类库篇,集合框架(Collections)
2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马). 集合框架增强如下: 1. 增加了如下新接口(Int ...
- JDK1.5新特性,基础类库篇,集合框架(Collections)
集合框架在JDK1.5中增强特性如下: 一. 新语言特性的增强 泛型(Generics)- 增加了集合框架在编译时段的元素类型检查,节省了遍历元素时类型转换代码量. For-Loop循环(Enhanc ...
- java集合框架之Collections
参考http://how2j.cn/k/collection/collection-collections/369.html Collections是一个类,容器的工具类,就如同Arrays是数组的工 ...
- 57 容器(十一)——Collections容器工具类
Collections是一个工具类,它提供了与集合操作有关的方法,好比数组中的Arrays工具类.(jdk中的工具类名都是xxxs,有关工具类名参考:https://zhuanlan.zhihu.co ...
- spring 在静态工具类中使用注解注入bean
/** * @author: jerry * @Email: * @Company: * @Action: 日志处理工具类 * @DATE: 2016-9-19 */ @Component//泛指组件 ...
随机推荐
- nginx方向代理
nginx 的安装 # yum install nginx 新建配置文件 # vi /etc/nginx/conf.d/resume-xyz-8081.conf 配置 upstream resume ...
- [SDOI2011]消耗战
题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...
- APIO 2015
老师让我们打这套题练练手.感觉这套题还是挺有意思的,比国内某些比赛不知道高到哪里去.最后我拿了284/300,貌似比赛是IOI赛制啊,强行被当成OI赛制做了,不然我T3可能还能多骗点. T1.scul ...
- [APIO2014]
T1.回文树裸题. #include<cstdio> #include<iostream> #define ll long long using namespace std; ...
- 探索C++多态和实现机理
前一段时间被问到过一个问题,当时模模糊糊,就是说不清楚,问题问到说:什么情况下会将基类的析构函数定义成虚函数? 当时想到 如果子类B继承了父类A,那么定义出一个子类对象b,析构时,调用完子类析构函数, ...
- (ubuntu)linux C编程之sleep()和usleep()的使用和区别
### 函数名: sleep 头文件: #include <windows.h> // 在VC中使用带上头文件 #include <unistd.h> // 在gcc编译器中, ...
- jquery常用函数
.text() //获得或更改元素文本: .html() //获得或更改元素标签: .val() //获得或更改input值: .css() //获得或更改元素样式: .click() //点击触发事 ...
- tf.nn.conv2d 和 tf.nn.max_pool 中 padding 分别为 'VALID' 和 'SAME' 的直觉上的经验和测试代码
这个地方一开始是迷糊的,写代码做比较分析,总结出直觉上的经验. 某人若想看精准的解释,移步这个网址(http://blog.csdn.net/fireflychh/article/details/73 ...
- 线性回归(Linear Regression)均方误差损失函数最小化时关于参数theta的解析解的推导(手写)
第一页纸定义了损失函数的样子, theta, X 和 y 的 shape, 以及最终的损失函数向量表现形式. 第二页纸抄上了几个要用到的矩阵求导公式,以及推导过程和结果. 要说明的是:推导结果与the ...
- 什么样的简历受HR青睐?
简历是我们在求职过程中的名片,那么如何写出更容易受到HR青睐的简历呢? HR可能一天要看上百份的简历,他们都希望能够尽快筛选出合适的人,然后用更多的时间去跟候选人沟通.所以招聘人员一般看一份简历只会花 ...