黑马程序员 笔记(十三)——集合框架

来源:互联网 发布:卡狐淘宝批量发货助手 编辑:程序博客网 时间:2024/06/09 19:52

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

集合类

    面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式.在很多情况下,我们不知道在程序中需要创建多少个对象,这时就不能依靠定义引用对象的变量来持有每一个对象。存储对象的容器就能帮我们解决这样的问题,而集合便是这样的容器。

数组和集合类同是容器,有何不同
  • 数组:存储对象,但长度是固定的,存储基本数据类型。
  • 集合:存储对象,但长度是可变,存储对象。
集合的特点:
  • 集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
  • 集合中存贮的是对象的地址。
集合框架概述
  1. Java中集合类定义主要是在java.util.*包下面。
  2. 集合的框架体系:
为什么需要这么多容器?
  1. 因为每一个容器对数据的存贮方式都有不同,这种存贮方式称为:数据结构
  1. Collection: 根接口(共性方法)(List:Set:)
    1. 增:add()方法的参数是Object,以便于接收任意类型的对象
      • boolean add(E e):向容器中添加对象
      • addAll(Collcetion<? extends E> c):将指定 collection 中的所有元素都添加到此 collection 中
      • void clear():移除此 collection 中的所有元素
      • boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话返回true
      • boolean removeAll(Collcetion<?> c)将集合中相同的部分去掉。
    2. 判断
      • boolean contains(Object o):判断是否包含某一个对象
      • boolean containsAll(Collcetion<?> c):如果此 collection 包含指定 collection 中的所有元素,则返回true
      • boolean equals(Object o):比较此 collection 与指定对象是否相等。
      • boolean isEmpty():判断容器中是否有对象。
      1. 迭代器:取出集合内部元素的一个接口,该接口的子类定义在集合的内部。这样就可以直接访问集合内部的元素。因为每一个容器的数据结构不同,所以取出动作的实现细节也不同,但是都有共性内容(判断和取出)。因此将其共性抽取。以后任何集合只要在内部实现Iterator接口,就可以将其元素取出。
      2. iterater iterater()
    3. 代码示例:
      • import java.util.*;class CollectionDemo {public static void main(String[] args) {ArrayList a1 = new ArrayList();ArrayList a2 = new ArrayList();//添加元素(对象)运用  add(Object obj)a1.add("Where");a1.add("there");a1.add("is");a2.add("I");a2.add("Love");a2.add("You");a1.addAll(a2);//获取个数,集合的长度sop("a1的Size:"+a1.size()+"\n");//删除元素sop(a1.remove("You")+"\n");//返回值为布尔型sop(a1+"\n");//取交集sop(a2.retainAll(a1));//返回的结果是布尔型,表示是否有交集sop("a1和a2的交集是:"+a2+"\n");//a1里现在是a1与a2的交集//取出元素//通过Iterator取出集合内的元素。for (Iterator it=a1.iterator();it.hasNext() ; ){sop(it.next()+"\t");}}public static void sop(Object o){System.out.print(o);}}

                  List:(Collection的子类之一)
                  1. 特点:元素是有序的,元素可以重复,因为该集合体系中有索引
                  2. 常见子类对象:
                    1. ArrrayList:底层的数据结构使用的是数组结构
                      • 特点:查询速度很快,因为有索引(角标),但增删速度稍慢。是线程不同步的。
                    2. LinkedList:底层使用的是链表的结构
                      • 特点:增删速度很快,但查询速度稍慢,因为每一个元素都链接到前一元素
                    3. Vector:底层是数组结构,线程同步,被ArrayList代替。
                  3. List中的特有方法:(凡事可以操作角标的方法都是该体系的特有方法)
                      1. void add(index,E e):在指定位置添加对象
                      2. void add(index,Collection);在指定位置插入一个集合
                      1. E remove(index):删除指定位置上的元素
                      1. set(index,element):修改指定位置上的元素
                      1. E get(index):获取指定位置的元素。
                      2. 通过迭代器Iterator进行取出:取出所有的元素。
                        • 迭代器是取出元素的方式。把取出方式定义在集合的内部,这样取出方式就可以直接访问集合的内的元素。
                        • 因为每一个容器的数据结构有所不同,所以取出的动作也不一样。但是都有共性的内容,判断和取出。因此就把这些共性的方法抽取出来,形成Iterator接口。
                      3. int indexOf(Object o):获取该对象在容器中的位置。
                      4. List subList(int fromIndex, int toIndex)获取指定到指定结束位置的对象。
                      5. 列表迭代器:ListIterator是Iterator的子接口
                        • 在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常,所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取
                  4. LinkedList:(链接列表)
                    1. 特有方法:
                      • void addFirst(E e)
                      • void addLast(E e)
                      • E get First()//get方法获取元素,但是不删除元素。当集合为空时,则抛出没有这个元素的异常。
                      • E getLast()
                      • E remove()//remove方法获取元素,并且删除该元素。当集合为空时,则抛出没有这个元素的异常
                      • E remove(int index)
                      • E removeFirst()
                      • E removeLast()
                      • 在JDK1.6中出现了替代方法
                        • offerFirst()   替代void add方法
                        • offerLast()
                        • peekFirst()替代get方法
                        • peekList()
                        • pollFirst()替代remove方法
                        • pollLast()
                    2. LinkedList示例:
                      • /*使用LinkedList模拟一个堆栈或者队列数据结构。堆栈:先进后出  如同一个杯子。队列:先进先出 First in First out  FIFO 如同一个水管。*/import java.util.*;class DuiLie{private LinkedList link;DuiLie(){link = new LinkedList();}public void myAdd(Object obj){link.addFirst(obj);}public Object myGet(){return link.removeFirst();}public boolean isNull(){return link.isEmpty();}}class  LinkedListTest{public static void main(String[] args) {DuiLie dl = new DuiLie();dl.myAdd("java01");dl.myAdd("java02");dl.myAdd("java03");dl.myAdd("java04");while(!dl.isNull()){System.out.println(dl.myGet());}}}


                  5. Vector方法中的特殊方法(枚举)
                    1. Enumeration elements()就是vector特有的取值方式(枚举)。相当与迭代器。
                      • Enumeration elements()中的方法:
                        • boolean hasMoreElements()
                        • E nextElements()
                    2. 由于枚举的名称以及方法的名称都过长,所以被迭代器取代了.


                  Set
                  1. 特点:没有索引,元素不可重复,存入和取出的顺序不一定一致。
                  2. 功能:和ArrayList
                  3. 常见子类:
                    1. hashSet():底层数据结构是哈希表。
                    2. TreeSet():底层的数据结构是二叉树。可以对Set集合中的元素进行排序(默认按ASCII编码)。
                  4. hashSet()
                    1. hashSet如何保证元素的唯一性?
                      • 通过调用元素的hashCode()方法和equals()方法来完成。如果元素的hashCode值相同,就接着判断equals()方法。如果都相同,则不会把重复的元素存进集合。(只有在hashCode的值相同的时候才会调用equasl方法进行比较。)
                      • 在尽力hashSet集合时,一般都要复写hashCode()和equals()方法,建立自己特有的比较方式,来提高工作效率。并且在复写hashCode()方法时,得保证hash值的唯一性。
                    2. 对于判断元素是否存在以及删除等操作,依赖的方法是元素的hashCode()和equals()方法。
                  5. TreeSet()
                    • 可以对Set集合中的元素进行排序(默认是按字母的ASCII码的顺序)。
                    1. 原理:当每次存进一个元素的时候,该集合对象就会自动调用该元素的compareTo()方法,将这个元素与已有的元素进行比较。通过返回的值将元素通过二叉树的结构进行存放。
                    2. TreeSet的排序
                      1. TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法。也种方式也成为元素的自然顺序,或者叫做默认顺序。
                      2. 示例:
                        class TreeSetDemo {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Student("lisi02",22));ts.add(new Student("lisi007",20));ts.add(new Student("lisi09",19));ts.add(new Student("lisi08",19));Iterator it = ts.iterator();while(it.hasNext()){Student stu = (Student)it.next();System.out.println(stu.getName()+"..."+stu.getAge());}}}class Student implements Comparable//该接口强制让学生具备比较性。{private String name;private int age;Student(String name,int age){this.name = name;this.age = age;}public int compareTo(Object obj)//覆盖compareTo方法,建立自己的比较方式。{if(!(obj instanceof Student))throw new RuntimeException("不是学生对象");Student s = (Student)obj;System.out.println(this.name+"....compareto....."+s.name);if(this.age>s.age)return 1;if(this.age==s.age){return this.name.compareTo(s.name);}return -1;}public String getName(){return name;}public int getAge(){return age;}}

                      3. TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性,在集合初始化时,就有了比较方式。当两种排序都存在时,以比较器为主。比较器的建立   定义一个类,实现Comparator接口,覆盖compare方法。
                      4. 示例:
                        class Student implements Comparable//该接口强制让学生具备比较性。{private String name;private int age;Student(String name,int age){this.name = name;this.age = age;}public int compareTo(Object obj){if(!(obj instanceof Student))throw new RuntimeException("不是学生对象");Student s = (Student)obj;if(this.age>s.age)return 1;if(this.age==s.age){return this.name.compareTo(s.name);}return -1;}public String getName(){return name;}public int getAge(){return age;}}class TreeSetDemo2 {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Student("lisi02",22));ts.add(new Student("lisi02",21));ts.add(new Student("lisi007",20));ts.add(new Student("lisi09",19));ts.add(new Student("lisi06",18));ts.add(new Student("lisi06",18));ts.add(new Student("lisi007",29));Iterator it = ts.iterator();while(it.hasNext()){Student stu = (Student)it.next();System.out.println(stu.getName()+"..."+stu.getAge());}}}class MyCompare implements Comparator//定义比较器  实现Compare接口{public int compare(Object o1,Object o2){Student s1 = (Student)o1;Student s2 = (Student)o2;int num = s1.getName().compareTo(s2.getName());if(num==0){return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));}return num;}}

                    3. TreeSet排序的另外一种方式:在构造集合的时候向集合中传入一个“比较器实体”。
                      1. 应用场合:当元素自身不具备比较性时,或者具备的比较性不是所需要的。
                      2. 比较器的定义:定义一个类实现Comparator接口,覆盖其中的compare()方法。compare()方法中定义的是比较的内容。
                      3. 当集合中的元素和集合都有比较的功能的时候,输出的结果是按照集合的比较方式排序的。
                      4. 示例:
                        1. import java.util.*;//导入包class Student implements Comparable//定义学生类,并且让其具有比较性{private int age;private String name;private String id;Student(String name,int age,String id){this.name = name;this.age = age;this.id = id;}public int compareTo(Object obj){if (!(obj instanceof Student))throw new RuntimeException("不是学生对象");else{System.out.println(this.getName()+"       "+this.getAge());Student s = (Student) obj;if(this.age != s.age)    return this.age - s.age;else if(this.name != s.name)return this.name.compareTo(s.name);return this.id.compareTo(s.id);}}public String getName(){return(this.name);}public int getAge(){return(this.age);}public String getId(){return(this.id);}}class MyCompartor implements Comparator//定义一个比较器{public int compare(Object obj1,Object obj2){if (!(obj1 instanceof Student)&&(obj2 instanceof Student))throw new RuntimeException(obj1+"and"+obj2+"中有对象不是学生类");else{Student stu1 = (Student) obj1;Student stu2 = (Student) obj2;int num1 = new Integer(stu1.getName().length()).compareTo(new Integer(stu2.getName().length()));if (num1 == 0){int num2 = new Integer(stu1.getAge()).compareTo(new Integer(stu2.getAge()));if(num2 == 0){return new String(stu1.getId()).compareTo(new String(stu2.getId()));}return num2;}return num1;}}}class MyTreeSet{public static void main(String[] args) {TreeSet ts = new TreeSet(new MyCompartor());ts.add(new Student("Zhang,Honemi",23,"520"));ts.add(new Student("Zhang,Honemi",22,"520"));ts.add(new Student("Zhang,Honemi",25,"520"));ts.add(new Student("Zhang,Honemi",23,"521"));ts.add(new Student("Zhang,Honemix",23,"520"));for (Iterator it = ts.iterator();it.hasNext() ; ){Student stu = (Student)it.next();System.out.println(stu.getName()+"……"+stu.getAge()+"……"+stu.getId());}}}


                      Map接口极其子类

                      Map接口(Map(Key,Value))是实现键-值映射数据结构的一个框架,可以用于存储通过键-值引用的对象。映射与集合有明显的区别,映射中的每个对象都是成对存在的。映射中存贮的每个对象都是通过一个键(key)对象来获取值(value)对象,键值的作用相当于数组中的索引,每一个键值都是唯一的(一个值只能对应一个键),可以利用键值来存贮数据结构中指定位置上的数据。这种存取不由键对象本身决定,而是通过一种散列技术进行处理,从而产生一个被称做散列码的整数值。散列码通常是一个偏置量,它相当于分派给映射的存贮去的起始位置。理想情况下,通过散列技术得到的散列码应该是在给定范围内均匀分布的整数值,并且每个键对象都应该得到不同的散列码。

                      1. Map接口中定义的常用方法
                        1. 添加
                          • V put(K key,Value v):向指定集合中添加指定的键-值映射关系。返回该键值之前对应的Value值。
                          • void putAll(Map<? extends K,? extends V> m ):从指定映射中将所有映射关系复制到此映射中
                        2. 删除
                          • void clear():移除集合中的所有的映射关系。
                          • V remove(Object key):如果存在指定的键对象,则移除该键对象的映射关系,并返回与该键对应的Value的值。
                        3. 判断
                          • boolean containsKey(Object key):如果存在指定的键的映射关系,则返回true,否则返回false
                          • boolean containsValue(Object Value):如果存在指定值的映射关系,则返回true,否则返回false
                          • boolean equals(Object o)用来查看指定的对象与该对象是否为同一个对象,是同一个对象返回true,否则返回false
                          • boolean isEmpty():判断该集合是否存在键-值映射。如果不存在,返回true
                        4. 获取
                          • V get(Object key):如果存在指定的键对象,则返回与该键对象对应的值对象,否则返回null
                          • int hashCode():返回此映射的哈希码值
                          • int size():获得该集合中键-值映射关系的个数。
                          • Collection<V> values():返回此映射中包含的值的Collection视图。
                          •  entrySet()
                          • keySet()
                        5. 常见方法演示
                          • import java.util.*;class MyMap {public static void main(String[] args) {Map<String,String> mymap = new HashMap<String,String>();//定义一个Map集合//向集合中添加元素/*1.通过put方法存元素的时候,返回值是该键之前对应的值2.在HashMap中null可以当作键值或者Value值存在。*/sop(mymap.put("01","Zhanghongmei"));sop(mymap.put("01","Zhanghongmei1"));mymap.put("02","ZHM");mymap.put("03","meimei");mymap.put("04",null);mymap.put(null,"MM");//判断集合中是否存在指定键或者指定值sop("mymap是否存在键值03:"+mymap.containsKey("03"));sop("mymap是否存在值ZHM:"+mymap.containsValue("ZHM"));sop("mymapz中是否存在键值003:"+mymap.containsKey("003"));sop("mymap中是否存在值ZHMx:"+mymap.containsValue("ZHMx"));//通过values方法,把集合中value值,取出。并存储在一个Collection集合中,返回该集合。sop("mymap中所有的值是:"+mymap.values());}public static<E> void sop(E e){System.out.println(e);}}/*运行结果===================================nullZhanghongmeimymap是否存在键值03:truemymap是否存在值ZHM:truemymapz中是否存在键值003:falsemymap中是否存在值ZHMx:falsemymap中所有的值是:[MM, null, Zhanghongmei1, ZHM, meimei]===================================*/


                        6. Map集合的两种取出方式:
                          1. keySet():
                            1. 思想:将Map集合中所有的键存入Set集合,再通过Set集合的迭代器,取出所有的键值,最后通过get(Object key)方法取出所有的Value值。
                            2. 代码示例:
                              import java.util.*;class MyMap1 {public static void main(String[] args) {Map<String,String> mymap = new HashMap<String,String>();//存入元素mymap.put("01","Zhang");mymap.put("02","Hong");mymap.put("03","Mei");//通过keySet方法取出键值Set<String> se = mymap.keySet();//获取Set集合的迭代器for(Iterator<String> it = se.iterator();it.hasNext();){String key = it.next();//通过Map集合的get方法取出对应的value的值String value = mymap.get(key);sop(key+"="+value);}}public static<E> void sop(E e){System.out.println(e);}}/*运行结果==============================01=Zhang02=Hong03=Mei==============================*/

                          2. Set<Map.Entry<k,v>> entrySet():
                            1. Map.Entry是一个接口里面有5个方法。
                              • boolean equals(Object o) :比较指定对象与此项的相等性。
                              • K getKey() :返回与此项对应的键。
                              • V getValue() :返回与此项对应的值
                              • int hashCode() :返回此映射项的哈希码值
                              • V setValue(V value) :用指定的值替换与此项对应的值。
                            2. 思想:将集合的通过调用entrySet()方法,将该集合内的所有元素的映射关系取出,并存进一个Set集合中,并返回这个集合。通过迭代器依次取出这种关系Map.Entry,然后调用Map.Entry里面的方法可以取出key值和value值,还可以替换value值。
                            3. 代码示例:
                              import java.util.*;class MyMap2 {public static void main(String[] args) {//建立一个Map集合Map<String,String> mymap = new HashMap<String,String>();//向Map集合中添加元素mymap.put("02","-zhangsan2");mymap.put("03","-zhangsan3");mymap.put("01","-zhangsan1");mymap.put("04","-zhangsan4");//将Map集合中的关系通过entrySet方法取出,存放在Set集合中Set<Map.Entry<String,String>> se = mymap.entrySet();//通过迭代器一次取出这种关系for (Iterator<Map.Entry<String,String>> it = se.iterator();it.hasNext() ; ){Map.Entry<String,String> re = it.next();//通过Map.Entry的方法取出key和value值String key = re.getKey();String value = re.getValue();sop(key+"="+value);}}public static<E> void sop(E e){System.out.println(e);}}/*运行结果==================================04=-zhangsan401=-zhangsan102=-zhangsan203=-zhangsan3==================================*/

                      2. Map接口的实现子类
                        1. Hashtable
                          1. 特点:
                            • 此类实现一个哈希表,底层是哈希表数据接口该哈希表将键映射到相应的值。任何非 null 对象都可以用作键或值。
                            • 为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和equals 方法。
                            • 出现在1.0版本,线程是同步的。
                        2. HashMap
                          1. 特点:
                            • 底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。除了非同步和允许使用 null 之外,HashMap 类与Hashtable 大致相同。
                        3. TreeMap
                          1. 特点:
                            • 底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
                            • 和Set很像,Set底层就是使用了Map集合。