黑马程序员java基础篇----集合总结

来源:互联网 发布:部落冲突龙宝升级数据 编辑:程序博客网 时间:2024/05/16 10:52

android培训java培训期待与您交流

一、集合框架体系结构

1、集合用于存放数量不等且可变的多个对象(仅能为对象),这点较于数组的固定长度与元素既可以是基本类型也可以是引用类型不同,但集合与数组一样,对引用类型的元素他们存放的都只是引用,而不是实际对象。
2、从元素结构上分为Collection与Map两大体系:

Collection:存放的都是单列元素

Map:存放的是双列的元素 (即键值对)。

从应用上分大致可分为三大体系:

List:允许包含重复元素,默认按元素的添加顺顺序设置元素的索引

Set:不允许包含重复元素,判断元素相等标准为equals()方法返回true

Map:用于存放键值对,对键值的要求同Set对元素的要求

二、Iterator

1、Iterator也是集合框架中的成员,只不过它不用于盛放对象,儿只负责遍历集合和中的元素,被称为迭代器。
2、Iterator是一个接口,它的实现被封装在Collection实现类的内部作为内部类存在,并可以通过iterator()方法的返回值获得。通过这种方式隐藏了Collection实现类的底层细节,对外统一遍历标准,这就是迭代器模式。
3、Iterator采用的是快速失败机制,一旦在迭代过程中检测到该集合被修改(通常是其他线程修改),立即引发ConcurrentModificationException异常,只能通过Iterator对象的remove()方法来对集合进行删除操作,另外

Collection<String> c = new TreeSet<String>();c.add("blackHorse");c.add("java");c.add("itCastt");Iterator<String> it = c.iterator();while(it.hasNext()){String key = it.next();if(key.equals("java"))c.remove("java");//通过集合进行删除System.out.println(key);}

当用上述方式(非线程方式)在遍历集合时进行删除,针对不同的集合类会出现不同异常:
 (1)、当对List实现类进行如上操作时不能完全遍历,但不抛出异常
 (2)、当对Set实现类进行如上操作时不能完全遍历且抛出ConcurrentModificationException异常
4、使用foreach对集合进行遍历时底层实现使用的依然是Iterator,所以上述注意点同样使用。

三、Set
(一)HashSet
1、HashSet按hash算法来来存储集合中的元素,不能保证集合中元素的顺序,非线程安全类并且允许添加null元素。
2、当向HashSet集合中添加元素时,HashSet会调用该元素的hashcode()方法获取该元素的hash值,一次决定元素在集合中的存储位置。
3、HashSet判断集合元素相等的标准是两个对象通过equals()方法比较返回true且两个对象的hashCode()方法的返回值也相同。 如果两个对象通过equals()方法比较返回true但hashCode()方法的返回值不同,那这两个对象将会被添加到集合中不同的位置,如果两个对象通过equals()方法比较返回false但hashCode()方法的返回值相同,那这两个对象将会被添加到集合中不同的位置,如下:

public class HashSetTest {public static void main(String[] args) {A a1 = new A(1);A a2 = new A(2);Set<A> hs = new HashSet<A>();hs.add(a1);hs.add(a2);System.out.println(hs.size());}}class A {private int hash;public A(int hash){this.hash = hash;   }public boolean equals(Object obj){return true;  ①}public int hashCode(){return hash;  ②}}

上述代码运行结果为:2
如果将①处的true改为false,②处的hash改成一个常量,运行结果同样为:2。
上述第一种情况违背了Set集合的规则,第二种会降低HashSet集合的性能。
所以在重写元素类的equals()方法是一定要重写hashCode()方法,确保它们状态的一致性。

(二)TreeSet

1、TreeSet是基于二叉树的树集,是一个有序集合。
2、TreeSet有两种排序方式:
(1)、自然排序
在这种排序方式下,要求元素实现Comparable接口中的compareTo(Object o)方法。TreeSet会调用集合元素的
compareTo(Object o)方法来比较元素的大小关系,然后将集合元素按升序排序。还有一点要注意,在实现
compareTo(Object obj)方法时,都需要将被比较对象obj强制转换成相同类型。如下:

class A implements Comparable{public int compareTo(Object obj) {if(this.getClass() == obj.getClass()){if this > object  return 正数if this = object  return 0if this > object  return 负数}}}


这时TreeSet判断元素相等的标准为两个对象通过equals()方法比较返回true,通过compareTo()方法比较返回0。与HashSet类似,当元素类重写了equals()方法,一定要保证compareTo()方法与之有相同状态。如果两个元素通过equals()返回true,但是compareTo()不返回0,则会被放在集合中不同的位置,如果情况相反,则更麻烦,会影响性能。如果向集合添加的元素是可变对象,并且在添加完成后改变了元素的属性,将会引起混乱:

public class HashSetTest {public static void main(String[] args) {A a1 = new A(4);A a2 = new A(2);A a3 = new A(6);A a4 = new A(8);Set<A> ts = new TreeSet<A>();ts.add(a1);ts.add(a2);ts.add(a3);ts.add(a4);//a4.setCom(2);           ①//ts.remove(new A(2));    ②System.out.println(ts);}}class A implements Comparable{private int com;public A(int com){this.com = com;}public void setCom(int com){this.com = com;}public boolean equals(Object obj){return true;}    public String toString(){return com + "";}public int compareTo(Object obj) {if(this.getClass() == obj.getClass()){A tem = (A)obj;return this.com - tem.com;}return 0;}}

取消注释行之前,打印结果为[2,4,6,8]
取消注释①以后,打印结果为[2,4,6,2],出现了顺序混乱
取消注释②以后,打印结果为[4,6,2],只能删除没有改变属性的元素
所以尽量不要使用可变对象作为TreeSet的元素。

如果要反转集合中的排序方式,可以借助集合工具类Collections的无参的reverseOrder()方法获得一个与Comparable所定义比较规则相反的Comparator对象,然后调用Treeset的含有一个Comparator参数的构造器创建对象,如下:
Set<A> ts = new TreeSet<A>(Collections.reverseOrder());      切记不要修改源码!
(2)、定制排序
定制排序不要求集合内元素实现Comparable接口,可以创建一个Comparator子类实现其中的compare(T o1, T o2)方法,
在该方法中可以自由定义升序还是降序,如下:

class A implements Comparator{public int compare(Object o1, Object o2) {if o1>o2 return 1;if o1=o2 return 0;if o1<o2 return -1;}}

如果要反转集合中的排序方式,可以借助集合工具类Collections的有参的reverseOrder(Comparator comparator)方法获得一个与Comparable所定义比较规则相反的Comparator对象,然后调用Treeset的含有一个Comparator参数的构造器创建对象,
如下: Set<A> ts = new TreeSet<A>(Collections.reverseOrder(new A()));

四、List

(一)ListIterator

ListIterator在Iterator的基础上增加了前向遍历的功能,并且可以添加修改元素。但是有一个注意点,调用ListIterator的set()方法之前不可调用add()与remove()任何一个方法,即只有在next()或者previous()后接着调用set()才可行。

(二)ArrayList&Vector&LinkedList

1、List判断元素相等的标准时equals()方法返回true。
2、ArrayList&Vector都是基于动态再分配的Object[]数组的集合,只是ArrayList是非线程安全的,Vector是一个古老的线 程安全的,每个ArrayList&Vector对象有一个capacity属性,表示它们所封装的Object[]的长度。如果需要向ArrayList&Vector添加大量元素,可以直接使用ensureCapacity()一次性指定capacity的值。因为底部封装的是数组,所以随进访问效率会很可变,但删除,添加操作性能较差。
3、在Arrays工具类里有一个asList(Object...obj)方法,该方法可以把一个数组或者指定个数的对象转换成一个List集合,这个List集合不是ArrayList实现类的子类,而是Arrays的内部类ArrayList实例。Arrays.ArrayList是一个固定长度的 List集合,只能遍历,不能增删。
4、LinkedList是基于链表的集合,并且实现了双向队列,此类集合既可以当成队列使用也可以当成栈使用。因为基于链表,所以增加与删除性能比较优越,而且遍历效率也优于基于数组的ArrayList&Vector,只是随机查找会比较耗时。所以对于LinkedList,应该采用迭代器进行遍历。
5、Vector的特有方法:带有element的方法都是Vector的特有方法,其中elements()方法返回一个Enumeration对象,该对象 有两个方法hasMoreElements()与nextElement(),用来对Vector中的元素进行遍历
6、LinkedList特有方法:
 addFirst(),addLast()添加元素到集合的头或者尾
 getFirst(),getLast()获取集合头部或者尾部的元素
 removeFirst(),removeLast()删除并且获取集合头部或尾部的元素
 上面这些方法一旦操作失败都会抛出异常。
 offerFirst(),offerLast()添加元素到集合的头或者尾
 peekFirst(),peekLast()获取集合头部或者尾部的元素
 pollFirst(),pollLast()删除并且获取集合头部或尾部的元素
 上面这些方法一旦操作失败会返回特殊值而不是抛出异常。
五、Map

1、HashMap&Hashtable的关系类似于ArrayList&Vector,HashMap是非线程安全的,Hashtable是一个古老的线程安全的。Hashtable不允许null作为key和value,如果加入null元素,则会出现NullPointerException,HashMap允许null作为key或value。
2、HashMap&Hashtable中元素的存储状态类似于HashSet,不能保证元素顺序,他们判断元素key相等的标准与HashSet判断元素相等的规则形同,判断value想的标准为只需要equals()返回true。尽量不要往HashMap&Hashtable添加可变对象。
3、TreeMap对元素(key)的组织机制类似于TreeSet,也有自然排序和定制排序两种。
4、在Map里有三个方法

keySet()返回此映射中包含的键的Set视图
values()返回此映射中包含的值的Collection视图
entrySet()返回此映射中包含的映射关系的Set视图

 这三个方法返回的Collection对象都支持元素移除,通过Iterator.remove、Collection.remove、removeAll、 retainAll 和 clear 操作可从映射中移除相应的映射关系,但是都不支持add或addAll操作。

六、Collections

Collections里有三类需要注意的方法:
1、带unmodifiable前缀的方法,返回的都是集合的不可修改的视图,此类方法允许模块为用户提供对内部内容的“只读”访问。任何视图修改此类方法所返回的集合对象的操作都将导致抛出UnsupportedOperationException。 
2、带synchronized前缀的方法,此类方法返回的是相应集合的同步视图,但是这些视图只是对集合的方法进行了序列化,即只是对集合的方法进行了同步包装,多以要想真正让原集合达到同步安全的目的,还需要一些特殊的处理,首先可以切断任何对原集合对象的引用,然后就是当使用迭代器(包括Map集合获取的Set视图的迭代器)对视图集合进行遍历时,进行同步处理:

synchronized(collection) {Iterator i = collection.iterator(); // Must be in synchronized blockwhile (i.hasNext())     foo(i.next());}


3、带checked前缀的方法,放回的都是相应集合的被检视的视图,例如

List<String> ls = new ArrayList<String>();ArrayList al = (ArrayList)ls;al.add(new Date());//因为泛型被擦出,所以可以成功的将Data类对象加入,但是要等到当使用get()方法获取并   //强转成String时才会抛出ClassCastException,这样安全隐患可能会被隐藏


面对这种情况,如果使用被检视的视图则可以在执行add()方法时就抛出ClassCastException。

List<String> ls = new ArrayList<String>();List<String> ls2 = Collections.checkedList(ls, String.class);ArrayList a1 = (ArrayList)ls2;list1.add(new Date());


 

原创粉丝点击