黑马程序员——集合(一)

来源:互联网 发布:抽奖软件源代码下载 编辑:程序博客网 时间:2024/06/06 01:37

黑马程序员--集合(一)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

集合类

一、概述

1、集合类:储存对象最常用的方式的方式之一。数据多了用对象存,对象多了用集合存。
集合类的特点:只用于存储对象,长度可变,可存储不同类型的对象。
PS:
集合类和数组都是容器,有何不同?
数组长度固定,且只能存相同类型的对象。
集合长度可变;数组可储存基本数据类型,集合只能储存对象。

2、集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
集合框架的优点:
简化程序设计;提高程序效率;提高API的使用效率;提高代码复用性。
集合框架的构成和分类:

二、Collection接口

框架的顶层-->Collection接口:
1、常见方法:
1.1添加:
boolean add(Object obj);
boolean addAll(Collection coll);
1.2删除
boolean remove(Object obj);
boolean removeAll(Collection coll);
void clear();
1.3判断
boolean contains(Object obj);
boolean containsAll(Collection coll);
boolean isEmpty();判读集合中是否有元素。
1.4获取
int size();
Iterator iterator():返回迭代器接口。
迭代器接口:对所有Collection容器进行元素取出的公共接口。
具体方法:
hasNext():若仍有元素可迭代,则返回true。
next():返回迭代的下一个元素。

remove():从迭代器指向的collection中移除迭代器返回的最后一个元素。

PS:
由于不同集合数据结构不同,造成每一个集合存取的方式可能不同。一般当我们需要多个动作(判断、取出)
才能完成一个动作的取出时,我们就将取出动作封装成一个对象。同时,因为其操作元素在集合中,
通过定义内部类,取出方式就可以直接访问集合内容元素。同时,我们将内部类都符合的取出方式规则定义在Iterator接口中,
通过iterator()方法获取。
1.5其他
boolean retainAll(Collection coll):取交集
Object toArray():将集合转成数组

[java] view plaincopyprint?
  1. import java.util.*;  
  2. /* 
  3. 1.add方法的参数类型是Object.以便于接收任意类型对象。 
  4. 2.集合中存储的都是对象的引用(地址)。 
  5. 3.集合变数组。 
  6. Collection接口中的toArray方法。 
  7. 3.1指定类型的数组到底要定义多长? 
  8. 当指定类型的数组长度小于集合的size,那么该方法内部会创建一个新的数组。 
  9. 当指定类型的数组长度大于集合的size,就不会创建一个新的数组。而是使用传递进来的数组。 
  10. 所以创建一个刚刚好的数组内存处置最优。 
  11. 3.2为什么要将集合变数组? 
  12. 当不需要对集合元素增删时,可限定对元素的操作。因为数组长度固定。 
  13. */  
  14. class CollectionDemo  
  15. {  
  16.     public static void main(String[] args)  
  17.     {  
  18.         base_method();  
  19.         other_method();  
  20.     }  
  21.     public static void base_method()  
  22.     {  
  23.         Collection col1 = new ArrayList();  
  24.   
  25.         //添加元素   
  26.         col1.add("java01");  
  27.         col1.add("java02");  
  28.         col1.add("java03");  
  29.         sop("col1添加:"+col1);  
  30.   
  31.         Collection col2 = new ArrayList();  
  32.         col2.addAll(col1);  
  33.         sop("col2添加:"+col2);          
  34.   
  35.         //删除元素   
  36.         sop("删除java02:"+col1.remove("java02"));  
  37.         col1.clear();  
  38.         sop("清空后集合"+col1);  
  39.   
  40.         //判断元素   
  41.         sop("java03是否存在:"+col1.contains("java03"));  
  42.         sop("col2是否为空?"+col2.isEmpty());  
  43.           
  44.         //获取   
  45.         sop("获取col2中元素个数:"+col2.size());  
  46.         //获取迭代器,取出集合中的元素。接口性引用只能指向自己的子对象。it随for循环结束而释放,更节省内存。  
  47.         for(Iterator it = col2.iterator();it.hasNext();)  
  48.         {  
  49.             System.out.print(it.next()+" ");  
  50.         }  
  51.         System.out.println();  
  52.   
  53.         Collection col3 = new ArrayList();  
  54.   
  55.         col3.add("java02");  
  56.         col3.add("java05");  
  57.   
  58.         sop("col2:"+col2);  
  59.           
  60.         //取交集,去除交集   
  61.         col3.retainAll(col2);  
  62.         sop("取交集:"+col3);  
  63.   
  64.         col3.removeAll(col2);  
  65.         sop("移除相同元素:"+col3);  
  66.     }  
  67.     public static void other_method()  
  68.     {  
  69.         Collection<String> col4 = new ArrayList<String>();  
  70.   
  71.         col4.add("abc1");  
  72.         col4.add("abc2");  
  73.         col4.add("abc3");  
  74.   
  75.         //将集合转成数组   
  76.         String[] arr = col4.toArray(new String[col4.size()]);  
  77.           
  78.         sop("集合转数组:"+Arrays.toString(arr));  
  79.     }  
  80.     public static void sop(Object obj)  
  81.     {  
  82.         System.out.println(obj);  
  83.     }  
  84. }  
运行结果:

2、List、Set接口

2.1 List接口
2.1.1 List常见方法:
这些方法有一个共性特点:都可以操作角标。
2.1.1.1 添加
void add(index,element);
void addAll(index,Collection);
2.1.1.2 删除
Object remove(index);
2.1.1.3 修改
Object set(index,element);
2.1.1.4 获取
Object get(index);
int indexOf(object);
int lastIndexOf(object);
List subList(form,to);//展现列表

[java] view plaincopyprint?
  1. import java.util.*;  
  2. class ListDemo  
  3. {  
  4.     public static void main(String[] args)  
  5.     {  
  6.         base_method();  
  7.     }  
  8.     public static void base_method()  
  9.     {  
  10.         List li = new ArrayList();  
  11.   
  12.         //添加元素   
  13.         li.add("java01");  
  14.         li.add("java03");  
  15.         li.add("java03");  
  16.           
  17.         sop("添加元素:"+li);  
  18.   
  19.         //删除指定位置的元素   
  20.         li.remove(2);  
  21.         sop("被删除后的集合:"+li);   
  22.   
  23.         //修改元素   
  24.         li.set(1,"java02");  
  25.         sop("被修改后的集合"+li);  
  26.   
  27.         li.add(2,"java02");  
  28.         sop("定点添加:"+li);  
  29.   
  30.         //通过角标获取元素   
  31.         sop("get(1):"+li.get(1));  
  32.   
  33.         //获取所有元素   
  34.         for(int x=0;x<li.size();x++)  
  35.         {  
  36.             System.out.print("li("+x+")="+li.get(x)+" ");  
  37.         }  
  38.         System.out.println();  
  39.   
  40.         for(Iterator it = li.iterator();it.hasNext();)  
  41.         {  
  42.             System.out.print("next:"+it.next()+" ");  
  43.         }  
  44.         System.out.println();  
  45.   
  46.         //通过indexOf获取对象的位置   
  47.         sop("index="+li.indexOf("java02"));  
  48.         sop("lastIndexOf:"+li.lastIndexOf("java02"));  
  49.   
  50.         List sub = li.subList(0,3);  
  51.         sop("sub"+sub);  
  52.     }  
  53.     public static void sop(Object obj)  
  54.     {  
  55.         System.out.println(obj);          
  56.     }  
  57. }  
运行结果:

2.1.1.5 ListIterator接口
ListIterator接口是Iterator的子接口。它是List集合特有的迭代器。它只能通过listIterator()方法获取。
Iterator方法只能对元素进行判断、取出、删除的操作,当迭代器需要增加元素等操作时,必须通过集合的方法,
这是会出现并发访问异常,存在安全隐患。ListIterator接口扩展了Iterator接口功能。避免了混合使用集合问题。
ListIterator接口常见方法:
add();
hasNext():正向遍历; 
hasPrevious():逆向遍历; 
next():返回列表中下一个元素;
previous():返回列表中的前一个元素;
remove():移除元素;
set():替换。

[java] view plaincopyprint?
  1. //获取数据的方法有两种:迭代器和集合,当两种方式混合使用时,会发生-->并发访问异常。  
  2. import java.util.*;  
  3. class ListDemo2  
  4. {  
  5.     public static void main(String[] args)   
  6.     {  
  7.         iterator_method();  
  8.     }  
  9.     public static void iterator_method()  
  10.     {  
  11.         //演示列表迭代器   
  12.         List li = new ArrayList();  
  13.         //添加元素   
  14.         li.add("java01");  
  15.         li.add("java02");     
  16.         li.add("java03");   
  17.         sop("li="+li);  
  18.           
  19.         //本例中,li是集合;it是迭代器。当两种方式访问同一数据时,会存在安全隐患。  
  20.         for(Iterator it = li.iterator();it.hasNext();)  
  21.         {  
  22.             //因为要判断的it.next()要==java02,所以obj(即it)为java01。  
  23.             Object obj = it.next();  
  24.             if(obj.equals("java02"))  
  25.                 //因为迭代器只有移除方法,没有添加,所以需要借助集合的add()方法。  
  26.                 li.add("java008");   
  27.                 it.remove();  
  28.             //会输出java01,因为remove只移除了引用,对象还存在。  
  29.             sop("obj="+obj);  
  30.             sop("li="+li);  
  31.         }     
  32.         sop(li);  
  33.     }  
  34.     public static void sop(Object obj)  
  35.     {  
  36.         System.out.println(obj);  
  37.     }  
  38. }  
运行结果:


[java] view plaincopyprint?
  1. /* 
  2. List定义了自己的迭代器接口:ListIterator()。避免Itetator接口中可使用方法较少,混合使用集合和迭代器的问题。 
  3. ListIterator是Iterator的子接口。该接口只能通过List集合的listIterator方法获取。 
  4. */  
  5. import java.util.*;  
  6. class ListDemo3  
  7. {  
  8.     public static void main(String[] args)   
  9.     {  
  10.         iterator_method();  
  11.     }  
  12.     public static void iterator_method()  
  13.     {  
  14.         //演示列表迭代器   
  15.         List li = new ArrayList();  
  16.         //添加元素   
  17.         li.add("java01");  
  18.         li.add("java03");   
  19.         li.add(1,"java02");   
  20.         sop("li="+li);  
  21.   
  22.         //其可以增、改、查的原因是它带角标。   
  23.         ListIterator lit = li.listIterator();  
  24.           
  25.         //判断迭代前有没有元素       
  26.         sop("hasPrevious():"+lit.hasPrevious());  
  27.         while(lit.hasNext())  
  28.         {  
  29.             Object obj = lit.next();  
  30.               
  31.             //替换元素   
  32.             if(obj.equals("java02"))  
  33.                 lit.set("java007");  
  34.         }  
  35.         //判断迭代后有没有元素   
  36.         sop("hasNext():"+lit.hasNext());  
  37.         sop("hasPrevious():"+lit.hasPrevious());      
  38.         sop("li="+li);  
  39.     }  
  40.     public static void sop(Object obj)  
  41.     {  
  42.         System.out.println(obj);  
  43.     }  
  44. }  
运行结果:

2.1.2List分类:
List:元素是有序的,元素可以重复。因为该集合体系有索引。
  |--Vector:底层是数组数据结构。线程同步。Vector生成20容量的数组,但是较浪费空间。被ArrayList替代。
  |--ArrayList:底层是数组数据结构。线程不同步。特点:查询块;增删慢。可变长度数组:超过10后,生成15容量的数组。
  |--LinkedList:底层使用的链表数据结构。特点:增删快;查询慢。

[java] view plaincopyprint?
  1. import java.util.*;  
  2. class LinkedListDemo  
  3. {  
  4.     public static void main(String[] args)  
  5.     {  
  6.         LinkedList link = new LinkedList();  
  7.       
  8.         //先存的为尾   
  9.         link.addFirst("java01");  
  10.         link.addFirst("java02");  
  11.         link.addFirst("java03");  
  12.   
  13.         sop("link="+link);  
  14.   
  15.         sop("获取尾元素:"+link.getFirst());  
  16.           
  17.         sop("获取头元素:"+link.getLast());  
  18.   
  19.         sop("移除尾元素:"+link.removeFirst());  
  20.   
  21.         sop("link="+link);  
  22.     }  
  23.     public static void sop(Object obj)  
  24.     {  
  25.         System.out.println(obj);  
  26.     }  
  27. }  
运行结果:

JDK1.6后方法:

[java] view plaincopyprint?
  1. /* 
  2. 使用LinkedList模拟一个堆栈或者队列数据结构。 
  3. 堆栈:先进后出  如同杯子。 
  4. 队列:先进先出  如同水管。 
  5. */  
  6.   
  7. import java.util.*;  
  8. class DuiLie  
  9. {  
  10.     private LinkedList link;  
  11.     DuiLie()  
  12.     {  
  13.         link = new LinkedList();  
  14.     }  
  15.     //先入的为尾   
  16.     public void myAdd(Object obj)  
  17.     {  
  18.         link.offerFirst(obj);  
  19.     }  
  20.     //获取并删除先存入的元素   
  21.     public Object myGet()  
  22.     {  
  23.         return link.pollLast();  
  24.     }  
  25.     public boolean isNull()  
  26.     {  
  27.         return link.isEmpty();  
  28.     }  
  29. }  
  30. class LinkedListTest  
  31. {  
  32.     public static void main(String[] args)  
  33.     {  
  34.         DuiLie dl = new DuiLie();  
  35.   
  36.         dl.myAdd("java01");  
  37.         dl.myAdd("java02");  
  38.         dl.myAdd("java03");  
  39.           
  40.         while(!dl.isNull())  
  41.         {  
  42.             System.out.print(dl.myGet()+" ");  
  43.         }  
  44.         System.out.println();  
  45.     }  
  46. }  
运行结果:

PS:
Enumeration(枚举):是Vector特有的取出方式。枚举和迭代功能一样。

2.2 Set接口
Set接口中元素不可以重复,无序(存入和输出顺序不一定一致)。它的方法和Collection一致。

HashSet保证元素唯一性原理:判断元素的hashCode值是否相同。
如果元素的哈希值相同,才会判断对象内容是否相同。

PS:
1、判断元素是否存在,以及删除等操作,HashSet依赖的方法是元素的hashCode和equals方法;
而ArrayList只依赖equals方法。TreeSet保证元素唯一性的依据compareTo方法。
原因:数据结构不同,所依赖方法也不一样。
2、让HashSet无序变有序,可使用LinkedHashSet。 

[java] view plaincopyprint?
  1. import java.util.*;  
  2. /* 
  3. 通过hashSet集合判断Person对象是否相同。姓名和年龄相同视为重复元素。 
  4. */  
  5. class Person  
  6. {  
  7.     private String name;  
  8.     private int age;  
  9.     Person(String name,int age)  
  10.     {  
  11.         this.name = name;  
  12.         this.age = age;  
  13.     }  
  14.     //复写hashCode()   
  15.     public int hashCode()  
  16.     {  
  17.         //看hashCode的调用记录   
  18.         System.out.println(this.name+"....hashCode()");  
  19.         //字符串name有自己的hashCode值,排除和相同的情况  
  20.         return name.hashCode()+age*37;  
  21.     }     
  22.     //复写equals     
  23.     public boolean equals(Object obj)  
  24.     {         
  25.         if(!(obj instanceof Person))  
  26.             return false;  
  27.   
  28.         //向下转型。因为要使用Person自己的方法。   
  29.         Person p = (Person)obj;  
  30.         System.out.println(this.name+"...equals.."+p.name);  
  31.   
  32.         return this.name.equals(p.name) && this.age == p.age;  
  33.     }  
  34.     public String getName()  
  35.     {  
  36.         return name;  
  37.     }  
  38.     public int getAge()  
  39.     {  
  40.         return age;  
  41.     }  
  42. }  
  43. class HashSetTest  
  44. {  
  45.     public static void main(String[] args)   
  46.     {  
  47.         HashSet hs = new HashSet();  
  48.   
  49.         hs.add(new Person("a1",11));  
  50.         hs.add(new Person("a2",12));  
  51.         hs.add(new Person("a3",13));  
  52.         hs.add(new Person("a4",13));  
  53.   
  54.         for(Iterator it = hs.iterator();it.hasNext();)  
  55.         {  
  56.             Person p = (Person)it.next();  
  57.             sop(p.getName()+"...."+p.getAge());  
  58.         }  
  59.     }  
  60.     public static void sop(Object obj)  
  61.     {  
  62.         System.out.println(obj);  
  63.     }  
  64. }  
运行结果:

2.2.1TreeSet排序
a 元素的自然顺序(默认顺序)。让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。
[java] view plaincopyprint?
  1. /* 
  2. 需求:往TreeSet集合中存储自定义对象学生。按照学生的年龄进行排序。 
  3.  
  4. 注意:排序时,当主要条件相同时,一定判断一下次要条件。 
  5. Comparable是一个接口,用于强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。 
  6. compareTo():比较此对象与指定对象的顺序。返回负数、零、整数。 
  7. ClassCastException:类型转换异常。 
  8. */  
  9. import java.util.*;  
  10. //Comparable接口强制让学生具备比较性   
  11. class Student implements Comparable  
  12. {  
  13.     private String name;  
  14.     private int age;  
  15.   
  16.     Student(String name,int age)  
  17.     {  
  18.         this.name = name;  
  19.         this.age = age;  
  20.     }  
  21.   
  22.     //复写compareTo()   
  23.     public int compareTo(Object obj)  
  24.     {  
  25.         if(!(obj instanceof Student))  
  26.             throw new RuntimeException("不是学生对象");  
  27.         Student s = (Student)obj;  
  28.           
  29.         System.out.println(this.name+"...compareto..."+s.name);  
  30.   
  31.         int temp = this.age-s.age;  
  32.   
  33.         //有具体返回值可以用三元运算符,年龄相同,再按名字排。  
  34.         return temp==0?this.name.compareTo(s.name):temp;  
  35.     }  
  36.   
  37.     public String getName()  
  38.     {  
  39.         return name;  
  40.     }  
  41.     public int getAge()  
  42.     {  
  43.         return age;  
  44.     }  
  45. }  
  46. class TreeSetDemo  
  47. {  
  48.     public static void main(String[] args)  
  49.     {  
  50.         TreeSet ts = new TreeSet();  
  51.   
  52.         //所存元素必须具备比较性, TreeSet()才能排序。   
  53.         ts.add(new Student("lisi02",22));  
  54.         ts.add(new Student("lisi04",20));  
  55.         ts.add(new Student("lisi02",19));  
  56.         ts.add(new Student("lisi01",20));  
  57.       
  58.         for(Iterator it = ts.iterator();it.hasNext();)  
  59.         {  
  60.             Student stu = (Student)it.next();//向下转型。  
  61.             System.out.println(stu.getName()+"..."+stu.getAge());  
  62.         }  
  63.     }  
  64. }  
运行结果:

b 自定义比较器。让集合自身具备比较性:定义一个类,实现Comparator接口,覆盖compare方法。将该类对象
作为参数传递给TreeSet集合的构造函数。这种方法适用于:元素自身不具备比较性或不具备自己所需的比较性。
当两种方式都存在时,以比较器为主。

[java] view plaincopyprint?
  1. /* 
  2. 练习:按照字符串长度排序。 
  3. 自定义比较器:元素自身不具备比较性或不具备自己所需的比较性。 
  4. */  
  5. import java.util.*;  
  6. class TreeSetTest  
  7. {     
  8.     public static void main(String[] args)  
  9.     {  
  10.         TreeSet ts = new TreeSet(new StrLenComparator());  
  11.   
  12.         ts.add("abcd");  
  13.         ts.add("cc");  
  14.         ts.add("cba");  
  15.         ts.add("z");  
  16.         ts.add("hahhaha");  
  17.       
  18.         for(Iterator it = ts.iterator();it.hasNext();)  
  19.         {  
  20.             System.out.println(it.next());  
  21.         }  
  22.     }  
  23. }  
  24. //实现Comparator接口,覆盖compare方法。   
  25. class StrLenComparator implements Comparator  
  26. {  
  27.     public int compare(Object o1,Object o2)  
  28.     {  
  29.         String s1 = (String)o1;   
  30.         String s2 = (String)o2;   
  31.           
  32.         //String类的compareTo方法   
  33.         int num =new Integer(s1.length()).compareTo(new Integer(s2.length()));  
  34.   
  35.         if(num==0)  
  36.             //主要条件符合,判断次要条件   
  37.             return s1.compareTo(s2);  
  38.         return num;  
  39.     }  
  40.   
  41. }  
运行结果:

0 0