集合-有时候被称为容器, 就像一手牌(牌的结合),一个邮箱(邮件的集合),或者一个电话簿(姓名和电话对应的关系图)
集合框架核心接口图
· Collection对集合核心接口的说明,所有的集合都实现了Collection这个接口,java没有类直接实现了Collection这个接口而是通过更加具体的子接口,比如Set and List
· Set 不能放重复元素添加重复的元素将毫无用处
·
List
有顺序的集合,可以存放重复的元素
· Queue
先进先出的集合
FIFO (first-in-first-out)
· Map
用键值对的关系来存储数据,键值不能重复,一个键只能对应一个值
· SortedSet,
SortedMap
分别是
Set和map的排序版本
Collection 接口:集合框架中的最顶的接口,集合中最抽象的一个接口
·
需要注意的方法:addAll
boolean addAll(Collection c)
将另外一个集合中的所有元素添加到这个集合中,
而如果用add()方法则是把集合C按照一个元素添加进去。
Set
接口:不能放重复的元素的集合。在java中有三种主要的实现
HashSet
, TreeSet
, and LinkedHashSet
· HashSet
效率最高,但是不能保证集合里面的元素是按顺序读取的
·
TreeSet
通过所存储的元素的值对元素进行排序,比HashSet慢
·
LinkedHashSet
通过集合里面的元素插入的时候的顺序进行排序
Eg1
import java.util.*;
public class TestSet {
public static void main(String args[]) {
Set s = new HashSet();
String test[]={"java", "FindDups" ,"i" ,"came", "i", "saw", "i", "left"};
String a;
for (int i=0;i
a=test[i];
if (!s.add(a))
System.out.println("Duplicate: " + a);
System.out.println(s.size()+" distinct words: "+s);
}
}
}
需要注意的一点是代码中一直引用的是 (Set
)这个接口而不是具体的实现类(HashSet
).这样做的好处就是给你的程序带来了很好的适应性。上面的例子中的输出是没有经过排序的,如果你希望进行排序,仅仅把hashset的实现换成treeset就好了
Eg2假设你想知道在一串字符中那些只是出现了一次,那些有重复,并且只是在最后打印结果
可以通过两个set来实现
import java.util.*;
public class FindDups2 {
public static void main(String args[]) {
Set
Set
for (String a : args)
if (!uniques.add(a))
dups.add(a);
//Destructive set-difference
uniques.removeAll(dups);
System.out.println("Unique words: " + uniques);
System.out.println("Duplicate words: " + dups);
}
}
Eg3
去掉重复的元素
Monster m=new Monster(i);
List c=new ArrayList();
c.add(m);
c.add(m);
HashSet noDups = new HashSet(c);
Iterator it=noDups.iterator();
while(it.hasNext()){
Monster mon=(Monster)it.next();
System.out.println();
System.out.println("new"+mon.toString());
}
List接口是一个有顺序的集合,可以有重复的元素
· List接口有两种比较常用的实现ArrayList
和LinkedList
如果两个List 以相同的顺序存储相同的元素那这两个list就是equal的
Queue
接口,先进先出的集合
FIFO (first-in-first-out)
import java.util.*;
public class Countdown {
public static void main(String[] args)
throws InterruptedException {
int time = Integer.parseInt(args[0]);
Queue
for (int i = time; i >= 0; i--)
queue.add(i);
while(!queue.isEmpty()) {
System.out.println(queue.remove());
Thread.sleep(1000);
}
}
}
Map 接口用键值对的关系来存储数据,键值不能重复,一个键只能对应一个值Map
的实现类: HashMap , TreeMap , and LinkedHashMap 和set类似
Map
的基本方法:
(put
, get
, containsKey
, containsValue
, size
, and isEmpty
)
Eg1 输入 java Freq if it is to be it is up to me to delegate
输出 8 distinct words:
{to=3, delegate=1, be=1, it=2, up=1, if=1, me=1, is=2}
import java.util.*;
public class Freq {
public static void main(String args[]) {
Map
new HashMap
// Initialize frequency table from command line
for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null ? 1 : freq + 1));
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
}
}
Object Ordering 对象的顺序
一个 List l可以像下面那样去排序
Collections.sort(l);
如果List 包含String元素,会按照字幕的顺序进行排序。如果包含Date元素会按照日期的顺序进行排序。这是因为String 和 Date 都实现了Comparable这个接口。Comparable接口提供了类的顺序下面的表是总结了java的一些类实现了这个接口的顺序
Classes Implementing Comparable |
|
Class |
Natural Ordering |
Byte |
Signed numerical |
Character |
UnSigned numerical |
Long |
Signed numerical |
Integer |
Signed numerical |
Short |
Signed numerical |
Double |
Signed numerical |
Float |
Signed numerical |
BigInteger |
Signed numerical |
BigDecimal |
Signed numerical |
Boolean |
Boolean.FALSE < Boolean.TRUE |
File |
System-dependent lexicographic on path name |
String |
Lexicographic |
Date |
Chronological |
CollationKey |
Locale-specific lexicographic |
import java.util.*;
public final class Name implements Comparable
private final String firstName, lastName;
public Name(String firstName, String lastName) {
if (firstName == null || lastName == null)
throw new NullPointerException();
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() { return firstName; }
public String lastName() { return lastName; }
public boolean equals(Object o) {
if (!(o instanceof Name))
return false;
Name n = (Name) o;
return n.firstName.equals(firstName) &&
n.lastName.equals(lastName);
}
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 这个对象是不能变的
· 在构造函数中坚持参数是否是null,这样保证了其他方法不会抛出空指针异常。
· 重新定义 hashCode 方法 (Equal objects must have equal hash codes.)
· 重新定义 equals方法返回false当比较的对象是null 或者是不相符的类型的时候
· 定义toString 方法让它返回能读懂的东西。
Comparators
当你想用另外一种方法去排序对象,或者已有的类没有实现Comparable这个接口的时候怎么办呢?
Interface Comparator 出现了,他封装了排序
假设你有一个类叫做 Employee
public class Employee implements Comparable
public Name name() { ... }
public int number() { ... }
public Date hireDate() { ... }
...
}
假设这个类是通过名字进行排序的,你的老板突然想让你通过入职日期来进行排序
import java.util.*;
class EmpSort {
static final Comparator
new Comparator
public int compare(Employee e1, Employee e2) {
return e2.hireDate().compareTo(e1.hireDate());
}
};
//Employee database
static final Collection
public static void main(String[] args) {
List
Collections.sort(e, SENIORITY_ORDER);
System.out.println(e);
}
}
需要注意的地方:compareTo方法一定要小心写,要考虑到需要比较的对象条件是相等的情况。例如如果两个相同日期入职的员工Jack和andy 那由于compareTo方法的问题只能有一个人存储到treeset里面
static final Comparator SENIORITY_ORDER =
new Comparator() {
public int compare(Employee e1, Employee e2) {
int dateCmp = e2.hireDate().compareTo(e1.hireDate());
if (dateCmp != 0)
return dateCmp;
return (e1.number() < e2.number() ? -1 :
(e1.number() == e2.number() ? 0 : 1));
}
};
选择使用那种集合的时候需要考虑 首先是速度,那种最适合,序列化,线程,
· Arrays 直接是由硬件实现的,速度最快 ArrayList,
· Linked lists 时候插入和删除操作
· Hash tables 键值
· Trees
HashSet 最常用的set通过一个 hash table来实现
General-purpose Implementations |
|||||
Interfaces |
Implementations |
||||
|
Hash table |
Resizable array |
Tree |
Linked list |
Hash table + Linked list |
Set |
HashSet |
|
TreeSet |
|
LinkedHashSet |
List |
|
ArrayList |
|
LinkedList |
|
Queue |
|
|
|
|
|
Map |
HashMap |
|
TreeMap |
|
LinkedHashMap |