黑马程序员 集合

来源:互联网 发布:linux root密码破解 编辑:程序博客网 时间:2024/06/05 15:24

    --------android培训java培训、期待与您交流! ----------

 

集  合


一:集合的概念

集合:保存数量不确定的数据,以及保存具有映射关系的数据的容器,简单的理解就是用于存储数量不等的多个对象的容器。
集合和数组不一样,数组元素既可以是基本类型的值,也可以是对象(对象的引用变量);而集合里只能保存对象(对象的引用变量)。
Java集合类主要由两个集合框架的根接口派生而出:Collection和Map
Java中Collection接口的体系机构:
Collection接口和Iterator接口:
Collection接口是List、Set和Queue接口的父接口,该接口中定义了一些操作集合元素的方法:
下面列举一些常见的方法:
boolean add(Object o):该方法用于向集合里添加一个元素。
boolean addAll(Collection c):该方法把集合c里的所有元素添加到指定的集合里。
void clean():清除集合里的所有元素,将集合长度变为0。
boolean contains():返回集合里是否包含指定元素。
boolean containsAll():返回集合里是否包含集合c里的所有元素。
boolean isEmpty():返回集合是否为空。当集合长度为0时返回true,否则返回false。
Iterator iterator():返回一个Iterator对象,用于遍历集合中的元素。
boolean remove(Object o):删除集合中指定的元素o,当集合中包含了一个或多个元素o时,这些元素将被删除,该方法将返回true。
boolean removeAll(Collection c):从集合中删除集合c里包含的所有元素。
boolean retainAll(Collection c):从集合中删除集合c里不包含的元素(相当于取得把调用该方法的集合变为该集合和集合c的交集),如果该操作改变了调用该方法的集合,返回true。
int  size():该方法返回集合里元素的个数。
Object[]  toArray():该方法把集合转换成一个数组,所有集合元素变成对应的数组元素。
Iterator接口:
Iterator接口也是Java集合框架的成员,但它与Collection系列、Map系列的集合不一样:Collection系列集合和Map系列的集合主要用于盛装其他对象,而Iterator则主要用于遍历集合的元素。又叫迭代器。
Iterator接口隐藏了各种Collection实现类的底层细节,只向应用程序提供遍历集合元素的统一编程接口。
Iterator接口定义了三个方法:
boolean hasNext():如果被迭代的集合元素还有没遍历,则返回true。
Object next():返回集合里的下一个元素。
void remove():删除集合里上一次next方法返回的元素。
Iterator仅用于遍历集合,如果需要创建Iterator对象,则必须有一个被迭代的集合。没有集合和Iterator仿佛无本之木,没有存在的意义。
当使用Iterator对集合元素进行迭代时,Iterator并不是把集合元素本事传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量的值对集合元素本事没有影响。
当使用Iterator来迭代访问Collection集合元素时,Collection集合里的元素不能被修改,只能通过remove方法删除上次next方法返回的集合元素才可以,否则报java.util.ConcurrentModificationException异常。
Iterator迭代器采用的是快速失败(fail-fast)机制,一旦在迭代过程中检测到该集合已经被修改(通常是其他线程进行修改),程序将报java.util.ConcurrentModificationException异常。而不是显示修改后的结果,这样可以避免共享资源而引发的问题。
foreach循环变量集合元素
格式:
for(类型   新对象:集合){

用法和Iterator类似。

二:Set接口

Set集合是无顺序的,其集合元素不允许重复。
Set集合判断两个对象相同不是使用==运算符,而是根据equals方法。简单的说,如果只要两个对象用equals方法比较返回true,Set集合就不会接受这两个对象;反之,则成立。
HashSet类:
HashSet是Set集合的实现类,HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet集合特点:
(1)不能保证元素的排列顺序,顺序有可能发生变化。
(2)HashSet不是同步的,如果多个线程同时访问一个HashSet,如果有2条或2条以上线程同时修改HashSet集合时,必须通过代码实现线程同步。
(3)集合元素值可以是null。

向HastSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值来决定该对象在HashSet中存储位置。如果有两个元素通过equals方法比较返回true,但它们的hashCode()方法返回值不相等,HashSet将会把它们存储在不同的位置,就可以添加成功(简单的理解HastSet集合判断两个元素是否相等的标准是两个对象通过equals方法比较相等,且两个对象的hashCode()方法返回的值也要相等)。


TreeSet类:
TreeSet是SortedSet接口的唯一实现,TreeSet可以确保集合元素处于排序状态。
TreeSet新添的方法:
(1)Comparator  comparator():返回当前Set使用的Comparator,或者返回null,表示以自然方式排序。
(2)Object  first():返回集合中的第一个元素。
(3)Object  last():返回集合中的最后一个元素。
(4)Object  lower(Object e):返回集合中位于指定元素之前的元素。
(5)Object  higher(Object e):返回集合中位于指定元素之后的元素。
(6)SortedSet  subSet(fromElement,toElement):返回此Set的子集合,范围冲fromElement(包含)到toElement(不包含)。
(7)SortedSet  headSet(toElement):返回此Set的子集,由小于toElement的元素组成。
(8)SortedSet  tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。

TreeSet集合并不是根据元素的插入顺序进行排序,而是根据元素实际值进行排序。
TreeSet集合采用红黑树的数据结构对元素进行排序。TreeSet集合支持两种排序方法:自然排序和定制排序。默认使用自然排序。

自然排序
TreeSet调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这就是自然排序。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数,实现该接口的类必须实现该方法,当一个对象调用该方法与另一个对象进行比较时,比如:obj1.compareTo(obj2),如果该方法返回0,则表明两个对象相等,如果返回是一个正整数,则表明obj1大于obj2,如果返回是一个负数,则表明obj1小于obj2。
注意:向TreeSet集合中添加元素时,只有第一个元素可以不实现Comparable接口,后面添加的所有元素都必须实现Comparable接口。否则报ClassCastException异常。

当把一个对象加入TreeSet集合中时,TreeSet调用该对象的compareTo方法与集合中的其他对象比较大小,然后根据红黑树算法决定它存储的位置。如果两个对象相等,TreeSet将把他们存储在同一位置。TreeSet集合比较两个对象相等的标准是:两个对象通过equals方法返回true,或通过compareTo方法比较返回0,则认为两个对象是同一个对象。


定制排序
通过实现Comparator接口中的compare方法来实现集合的定制排序,
int   compare(T o1,T o2)方法比较大小,如果返回是正整数,则表明o1大于o2,如果返回0,则表明两个对象相等,如果返回负数,则表明o1小于o2。
如果需要实现定制排序,则需要在创建TreeSet集合对象时,并提供一个Comparator对象与该集合关联,由该Comparator对象负责集合的排序逻辑。

实例

public class TreeSetTest {      public static void main(String[] args) {          //定义TreeSet集合,并为集合提供一个排序的Comparator对象(这里是匿名内部类)。          TreeSet<M> ts = new TreeSet<M>(new Comparator<M>() {              @Override              public int compare(M m1, M m2) {                  // TODO Auto-generated method stub                  if (m1.num > m2.num) {                      return -1;//这是按降序排序,如果想按升序排序,这里返回正整数,下面else中返回负数,即可。                  } else if (m1.num == m2.num) {                      return 0;                  } else {                      return 1;                  }              }          });          //向集合中添加数据          ts.add(new M(5));          ts.add(new M(-3));          ts.add(new M(8));          ts.add(new M(6));          System.out.println(ts);        }  }    class M {      // 定义一个变量      int num;        public M(int num) {          // 构造函数中为变量赋值          this.num = num;      }        // 重写toString方法      public String toString() {          return "M对象num的值为" + this.num;      }  } 


总结
HashSet和TreeSet是Set的两个典型实现,HashSet的性能总比TreeSet好(添加,查询操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。TreeSet是有序的集合。
HashSet还有一个子类LinkedHashSet,对于普通的插入,删除操作,LinkedHashSet比HashSet要慢一点点,这是因为维护链表所带来的开销。不过遍历集合时,LinkedHashSet就非常块 。
EnumSet是所有Set实现类中性能最好 ,但它只能保存同一个枚举类的枚举值作为集合元素。

注意:Set的三个实现类HashSet 、TreeSet、EnumSet都是线程不安全的。如果有多条线程同事访问一个Set集合,并且有超过一条线程修改集合的值,则必须手动保证集合的同步性,否则将无法访问修改后的集合


List接口
List集合代表一个有序的集合 ,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,通过索引来访问指定位置的集合元素。
List集合在Collection的基础上新添加的方法:
(1)void  add (int index,Object element):将元素element插入在List集合的index处。
(2)boolean  addAll(int index,Collection c):将集合c所包含的所有元素都插入在List集合的Index处。
(3)Object  get(int index):返回集合index索引处的元素。
(4)int  indexOf(Object o):返回对象o在List集合中出现的位置索引。
(5)int  lastIndexOf(Object o):返回对象o在List集合中最后一次出现的位置索引。
(6)Object  remove(int index):删除并返回index索引处的元素。
(7)Object  set(int index,Object element):将index索引处的元素替换成element对象,返回新元素。
(8)List subList(int fromIndex,int toIndex):返回从索引fromIndex(包含)到索引toIndex(不包含)处所有集合元素组成的子集合。

ListIterator接口:
ListIterator接口是Iterator的子接口,提供了专门操作List的方法。
ListIterator接口新增的方法:
(1)boolean  hasPrevious():返回该迭代器关联的集合是否还有上一个元素。
(2)Object  previous():返回该迭代器的上一个元素。
(3)void  add():在指定位置插入一个元素。
根据上面的三个方法和解释,不难发现ListIterator新增加了向前迭代的功能,而且ListIterator还可以通过add方法向List集合中添加元素。

实例:
public class ListTest {      public static void main(String[] args) {          List<String> list = new ArrayList<String>();          list.add("smarhit");          list.add("heima");          list.add("sichuan");          list.add("chengdu");          ListIterator<String> lit = list.listIterator();          while (lit.hasNext()) {              System.out.print(lit.next()+"\t");          }          System.out.println("\n----------开始反向迭代--------------");          while (lit.hasPrevious()) {              System.out.print(lit.previous()+"\t");          }          /*          * 打印的结果是:          * smarhit heima sichuan chengdu          *  ----------开始反向迭代--------------          * chengdu sichuan heima smarhit          */        }  }  

ArrayList和Vector实现类
ArrayList和Vector类都是基于数组实现的List类,ArrayList和Vector类封装了一个动态在分配的Object[ ]数组。每个ArrayList或Vector对象有一个capacity属性,该属性表示他们所封装的数组的长度,当想ArrayList或Vector中添加元素时,它们的capacity会自动增加。对于通常编程中,程序员无须关心ArrayList或Vector的capacity属性。但如果向ArrayList集合或Vector集合中添加大量元素时,可使用ensureCapacity方法一次性的增加capacity。这样可以提高性能。
ArrayList和Vector在用法上几乎完全相同(Vector是古老的集合,JDK1.0就存在了),但ArrayList集合是线程不安全的,当多条线程访问同一个集合时,如果有超过一条线程修改了ArrayList集合,则程序必须手动保证该集合的同步性。而Vector集合则是线程安全的。无须程序保证集合的同步性。所以Vector的性能比ArrayList的性能低。
Vector还提供了一个Stack子类,它用于模拟了“栈”这中数据结构,“栈”通常是指“后进先出”的容器。最后“push”进栈的元素,将最先被“pop”出栈。
Stack类提供的方法:
(1)Object  peek():返回“栈”的第一个元素,但并不将该元素"pop"出栈。
(2)Object  pop():返回"栈"的第一个元素,并将该元素"pop"出栈。
(3)void  push(Object item):将一个元素“push”进栈,最后一个进“栈”的元素总是位于“栈”顶。
实例:
public class StackTest {        public static void main(String[] args) {          Stack<String> s=new Stack<String>();          s.push("smarhit");          s.push("beijin");          s.push("neijiang");          s.push("chengdu");          System.out.println(s);//打印[smarhit, beijin, neijiang, chengdu]          System.out.println(s.peek());//打印chengdu          System.out.println(s);//打印[smarhit, beijin, neijiang, chengdu]          System.out.println(s.pop());//打印chengdu          System.out.println(s);//打印[smarhit, beijin, neijiang]      }  }  

固定长度的List
数组的工具类 Arrays提供的asList()方法是把一个数组或指定个数的对象转换成一个List集合, 但这个List集合既不是ArrayList实现类的实例,也不是Vector实现类的实例,而是Arrays的内部类ArrayList实例。Arrays.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可增加,删除该集合中的元素。
LinkedList实现类:
LinkedList类是一个比较特殊的类,它实现了List接口,还实现了Deque接口,Deque接口是Queue接口的子接口,它代表一个双向队列。
LinkedList类提供的方法:
(1)void  addFirst(Object e):将指定元素插入该双向队列的开头。
(2)void addLast(Object e):将指定元素插入该双向队列的尾部。
(3)Iterator descendingIterator():返回以该双向队列对应的迭代器,该迭代器将以逆向顺序来迭代队列中的元素。
(4)Object  getFirst():获取、但不删除双向队列的第一个元素。
(5)Object  getLast():获取、但不删除双向队列的最后一个元素。
(6)boolean  offerFirst(Object e):将指定的元素插入该双向队列的开头。
(7)boolean  offerLast(Object e):将指定的元素插入该双向队列的尾部。
(8)Object   peekFirst():获取、但不删除该双向队列的第一个元素;如果此双向队列为空,则返回null。
(9)Object   peekLast():获取、但不删除该双向队列的最后一个元素;如果此双向队列为空,则返回null。
(10)Object  pollFirst():获取、并删除该双向队列的第一个元素;如果此双向队列为空,则返回null。
(11)Object  pollLast():获取、并删除该双向队列的最后一个元素;如果此双向队列为空,则返回null。
(12)Object  pop():pop出该双向队列所表示的栈中第一个元素。
(13)void  push(Object e):将一个元素push进该双向队列所表示的栈中。
(14)Object  removeFirst():获取、并删除该双向队列的第一个元素。
(15)Object  removeFirstOccurrence(Object o):删除该双向队列的第一个出现元素o。
(16)removeLast():获取、并删除该双向队列的最后一个元素。
(17)removeLastOccurrence(Object  o):删除该双向队列的最后一次出现元素o。

总结:LinkedList与ArrayList、Vector的实现机制完全不同。ArrayList、Vector内部以数组的形式来保存集合中的元素,因此随机访问集合元素上有较好的性能;而linkedList内部以链表的形式来保存集合中的元素,因此随机方法集合元素时性能较差,但在插入、删除元素时性能非常出色(只需改变指针所指的地址即可)。




     --------android培训java培训、期待与您交流! ----------