集合的类图关系如下:
集合的主要接口是Collection和Map,其中List和Set都是继承的Collection
1.List
List的主要实现类是ArrayList和LinkedList。List中的数据能够重复,ArrayList存放的数据适合随机存取,而LinkedList适合数据插入和删除比较频繁的情况。Vector是ArrayList的线程同步的版本,但是效率比较低。下面是一个简单的List的例子。
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- public class TestList {
- public static void main(String[] args) {
- List<String> l = new ArrayList<String>();
- l.add("java");
- l.add("c++");
- l.add("asp.net");
- // Iterator it = l.iterator();
- // while(it.hasNext()){
- // System.out.println(it.next().toString());
- // }
- for (Object o : l) {
- System.out.println(o.toString());
- }
- Object[] str = l.toArray();
- for (Object s : str) {
- System.out.println(s.toString());
- }
- }
- }
在创建一个集合时一般都包装为上层的接口,因为如果对集合的操作有改变的话可以直接修改创建的类而不用修改其它的代码。
对集合进行遍历时有两种方法。一种是利用集合类的iterator()方法生产一个集合的迭代器。Iterator接口的hasNext()方法返回true当存在下一个元素时。next()则返回下一个元素。另一个方法是利用foreach语句.
2.Set接口public interface Set<E>extends Collection<E>
Set集合里面存放的元素都是不能重复的,更确切的是不能存放e1.equals(e2)==true的元素对e1和e2。Set集合的主要实现类有
HashSet和TreeSet。
(1)HashSet 因为存放的元素不能重复,所以放入HashSet集合的元素必须重写equals()和hashCode()方法。利用HashSet放入一个元素时首先调用元素的hashCode()方法,若hashCode值与集合中其他的元素不同,则添加成功。若hashCode值相同,则比较两个元素是否equals,如果返回true,则添加失败。所以两个元素equals时hashCode值必须相同。HashSet的实现其实是一个HashMap,
- public HashSet() {
- p = new HashMap<E,Object>();
- }
- public boolean add(E e) {
- eturn map.put(e, PRESENT)==null;
- }
- public V put(K key, V value) {
- if (key == null)
- return putForNullKey(value);
- int hash = hash(key.hashCode());
- int i = indexFor(hash, table.length);
- for (Entry<K,V> e = table[i]; e != null; e = e.next) {
- Object k;
- if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//增加元素时,比较hash值和是否equals,当都为true时,更新value,但是对Set来说,并//没有添加新的元素
- V oldValue = e.value;
- e.value = value;
- e.recordAccess(this);
- return oldValue;
- }
- }
- modCount++;
- addEntry(hash, key, value, i);
- return null;
- }
由此可以看出在HashSet集合中插入元素时先考虑hash值再考虑是否equals。
- import java.util.HashSet;
- import java.util.Set;
- public class TestSet {
- class Obj{
- int i;
- public Obj(int i){
- this.i = i;
- }
- public String toString(){
- return i+"";
- }
- public boolean equals(Object o){
- return (o instanceof Obj)&&(((Obj)o).i==i);
- }
- public int hashCode(){
- return i;
- }
- }
- public static void main(String [] args){
- new TestSet().test();
- }
- public void test(){
- Obj o1 = new Obj(1);
- Obj o2 = new Obj(2);
- Obj o3 = new Obj(2);
- Obj o4 = new Obj(2);
- System.out.println(o2.equals(o3));
- Set<Obj> set = new HashSet<Obj>();
- set.add(o1);
- set.add(o2);
- set.add(o3);
- for(Obj o : set){
- System.out.println(o);
- }
- }
- }
- true
- 1
- 2
- import java.util.Iterator;
- import java.util.Set;
- import java.util.TreeSet;
- public class TestTreeSet {
- private class Obj implements Comparable<Obj>{
- private int i;
- public Obj(int i) {
- this.i = i;
- }
- public String toString() {
- return "i=" + i;
- }
- public int compareTo(Obj o) {
- if(this.i>o.i){
- return 1;
- }
- else if(this.i<o.i){
- return -1;
- }
- return 0;
- }
- }
- public void test() {
- Set<Obj> set = new TreeSet<Obj>();
- Obj o1 = new Obj(1);
- Obj o2 = new Obj(2);
- Obj o3 = new Obj(3);
- set.add(o3);
- set.add(o2);
- set.add(o1);
- set.add(o3);
- Iterator it = set.iterator();
- while (it.hasNext()) {
- System.out.println(it.next().toString());
- }
- }
- public static void main(String[] args) {
- new TestTreeSet().test();
- }
- }
- i=1
- i=2
- i=3
所以存在TreeSet中的元素排列顺序只与元素的大小有关,与放入的先后顺序无关。
3.Map (public interfaceMap<K,V>)
Map中存放的元素都是以键值对存在的。Map集合中存放的元素不能有相等的key。
Map接口的主要实现类有HashTable,HashMap和TreeMap。
(1)、HashMap和HashTable
HashTable是线程安全的而HashMap不是,所以HashMap的效率更高。HashMap的键值都能为null,而Hashtable不能。
由于需要保证HashMap的key的唯一性,所以放在HashMap中的键必须重写hashCode()和equals()方法。
(2)、TreeMap放在TreeMap中的元素都是按照key的大小来排列的。所以存在TreeMap的key其类必须实现Compareable接口并实现CompareTo方法。
Map提供了valus()方法可以得到value的Collection,通过keySet()方法可以得到key的Set
遍历Map
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class TestMap {
public void test1(){
Map<String , Integer> map = new HashMap<String ,Integer>();
map.put("one", 1);
map.put("one", 11);
map.put("two", 2);
map.put("three", 3);
Set<java.util.Map.Entry<String, Integer>> set = map.entrySet();
for(java.util.Map.Entry<String,Integer> entry : set){
System.out.println("key:"+entry.getKey()+"value:"+entry.getValue());
}
}
public static void main(String [] args){
new TestMap().test1();
}
}
4.集合常见的面试题
(1)、 Iterator与ListIterator有什么区别?
Iterator:只能正向遍历集合,适用于获取移除元素。ListIerator:继承Iterator,可以双向列表的遍历,同样支持元素的修改。
ListItrator只能由List接口的实现类通过得到listIterator()
方法得到。
(2)、