zoukankan      html  css  js  c++  java
  • 黑马程序员——【Java基础】——集合框架

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

     一、集合框架概述

      (一)集合框架中集合类关系简化图

     

      (二)为什么出现集合类?

      面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是用于存储对象的。

      (三)数组和集合类同是容器,有何不同?

      、数组长度是固定的;集合长度是可变的。

      2、数组中可以存储基本数据类型,集合只能存储对象。

      (四)集合类的特点

      集合可以存储不同类型的对象。集合只用于存储对象,集合长度是可变的。

      (五)为什么会出现这么多容器?

      因为每一个容器对数据的存储方式都有不同,这个存储方式称为数据结构。

    二、Collection接口

      (一)Collection概述

      Collection是集合框架中的常用接口。其下有两个子接口:List(列表),Set(集)。

      所属关系:Collection

                     |--List:元素是有序的,元素可以重复。因为有索引(index)。

                     |--Set:元素是无序的,元素不可以重复,无索引。

      (二)Collection接口的常见方法

      1、添加

      add(Object obj):add方法的参数类型是Object。以便于接收任意类型对象。

      addAll(Collection coll):将指定 collection 中的所有元素都添加到此collection中。

      2、删除

      clear():清空集合

      remove(Object obj):

      removeAll(Collection col):移除此 collection 与指定 collection 中的交集元素。

      3、判断

      boolean contains(Object obj):判断collection是否包含obj这个元素

      boolean isEmpty():判断集合是否为空

      4、获取

      int size():返回此collection中的元素数。

      5、其他

      retainAll(Collection coll):保留两集合的交集元素。

      注:集合中存储的都是对象的引用(地址)。

    三、迭代器iterater

      (一)概述

      1、什么是迭代?迭代就是集合的取出元素种方式。

      2、集合迭代原理:将“取出方式”定义在集合的内部,这样“取出方式”就可以直接访问集合内部的元素,那么“取出方式”就被定义成了内部类。不同的数据结构,“取出方式”的具体实现细节也不相同,但都有共性内容“判断”和“取出”,将共性的规则抽取出来,即是Iterator。

      3、如何获取集合中的“对象”元素呢?

    通过一个对外提供的方法:iterator(),来获取集合中存储的对象。因为Collection中有iterator方法,所以Collection的每一个子类集合对象都具备迭代器。

      (二)迭代器的方法

      1、hasNext():有下一个元素,返回true

      2、next():取出下一个元素

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

      注:在迭代时循环中next调用一次,就要hasNext判断一次。

      4、Iterator的使用方法示例:

      ArrayList a = newArrayList();//创建一个集合

      Iterator it = a.iterator();//获取一个迭代器,用于取出集合中的元素。

      //方式一:for循环(老外的写法),好处在于it对象在迭代完成后就释放了,不占内存。

    1 for ( Iterator it = a.iterator() ; it.hasNext(); ){
    2     System.out.println ( it.next() );
    3 }

      //方式二:while循环

    1 while ( it.hasNext() ){
    2     System.out.println ( it.next() );
    3 }

      (三)迭代器的注意事项

      1、迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。

      2、迭代器的next()方法是自动向下取元素,要避免出现NoSuchElementException。

      3、迭代器的next()方法返回值类型是Object,所以要记得类型转换。

    四、List集合

      (一)List集合作用

      是可以完成对集合中元素的增、删、改、查。

      * List集合组成

      List:

        |--Vector:内部是数组数据结构,是同步的。增删,查询都很慢!

        |--ArrayList:内部是数组数据结构,是不同步的。替代了Vector。查询的速度快。

        |--LinkedList:内部是链表数据结构,是不同步的。增删元素的速度很快。

      (二)List集合常见方法

      List特有的常见方法,有一个共性特点就是都可以操作角标。

      1、添加(增)

      void add(index , element):指定位置添加元素

      boolean add(index , collection):

      2、删除(删)

      Object remove(index): 删除指定位置的元素

      3、修改(改)

      Object set(index,element):修改指定位置的元素

      4、获取(查)

      Object get(index):获取指定角标的元素

      int indexOf(object):获取元素第一次出现的位置,如果没有则返回-1

      int lastIndexOf(object):返回此列表中最后出现的指定元素的索引

      List subList(from , to):返回列表中指定的from (包括)到to(不包括)之间的部分。

      注:List集合判断元素是否相同,移除等操作,依据的是元素的equals方法。

      (ListIterator

      1、概述

      (1)ListIterator是List集合特有的迭代器,是Iterator的子接口。

      (2)在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常。所以在迭代器时,只能用迭代器的方法操作元素。可是Iterator方法有限,只能对元素进行判断、取出、删除的操作。如果想要其他的操作,如添加、修改等,就需要使用其子接口ListIterrator。该接口只能通过List集合的listIterator()方法获取。

      (3)为什么ListIterator才可以增、删、改、查?因为List集合中的元素都带角标。

      2、ListIterator特有的方法

      void add(obj):为list增加元素

      void set(obj):用指定元素替换 next 或 previous 返回的最后一个元素。

      boolean hasPrevious():判断前面有没有元素

      Object previous():返回列表中的前一个元素。

      (四)Enumeration

      1、枚举是Vector类特有的取出方式。

      2、Vector取出元素的方式:(1)迭代器方式取出;(2)for循环遍历,get方式取;(3)按角标索引取出;(4)枚举方式取出。

      3、特有方法

      addElement(obj):添加元素,相当于add(obj);

      Enumeration elements():Vector特有取出方式(枚举)

      hasMoreElements():是否还有元素,相当于Iterator的hasNext()方法

      nextElements():取出下一个元素,相当于Iterator的next()方法

      4、枚举方法示例:

    1 Vector v=new Vector();
    2 for ( Enumeration en = v.elements() ; e.hasMoreElements() ; ){
    3   System.out.println(en.nextElements());
    4 }

      (五)LinkedList(实现不同步)

      1、LinkedList底层:使用的是“链表”结构。

      2、特点:增删速度很快,查询稍慢。

      3、特有方法:

      (1)添加:addFirst();       addLast();

      (2)获取:获取元素,但不删除元素。

      包括:getFirst();   getLast();

      (3)删除:获取元素,并删除元素。

      包括:removeFirst();   removeLast();

      4、JDK1.6后,出现了替代方法。

      (1)添加:offerFirst();     offLast();

      (2)获取:获取元素,但是不删除。如果集合中没有元素,会返回null。包括:peekFirst();       peekLast();

      (3)删除:获取元素,并删除元素。如果集合中没有元素,会返回null。包括:pollFirst();     pollLast();

      5、LinkList示例练习

      /* 使用LinkedList模拟一个堆栈或者队列数据结构。

      堆栈:先进后出  如同一个杯子。

      队列:先进先出 First in First out  FIFO 如同一个水管。 */

     1 import java.util.*;
     2 class LinkedListTest{
     3     public static void main(String[] args) {
     4         LinkedList link = new LinkedList();
     5               link.addFirst("java01");
     6               link.addFirst("java02");
     7               l.addFirst("java03");
     8              link.addFirst("java04");
     9              link.addFirst("java05");
    10               //堆栈输出
    11         stack(link);
    12         //队列输出
    13         queue(link);
    14         }
    15     //堆栈
    16     public static void stack(LinkedList link) {
    17                while (!link.isEmpty()) {
    18             sop(link.removeFirst());
    19             }
    20     }
    21   
    22     //队列
    23     public static void queue(LinkedList link){
    24         while(!link.isEmpty()){
    25             sop(link.removeLast());
    26         }
    27     }
    28 
    29     //输出
    30     public static void sop(Object obj)
    31     {
    32         System.out.println(obj);
    33     }
    34 }

    五、Set集合

      (一)概述

        Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。

          |--HashSet:底层数据结构是哈希表,线程不同步。

          |--TreeSet:可以对Set集合中的元素进行排序。

      (二)HashSet

      1HashSet:保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true。

      2Set集合的功能和Collection是一致的。

      3、练习:HashSet代码示例

     1 //(1)HashSet示例
     2 import java.util.HashSet;
     3 import java.util.Iterator;
     4 public class HashSetDemo {
     5     public static void main(String[] args) {
     6         HashSet hs = new HashSet();
     7         hs.add("hehe");
     8 //        hs.add("heihei");
     9         hs.add("hahah");
    10         hs.add("xixii");
    11         hs.add("hehe");
    12         Iterator it = hs.iterator();
    13         while(it.hasNext()){
    14             System.out.println(it.next());
    15         }
    16     }
    17 }
    18 //(2)LinkedHashSet代码示例
    19 import java.util.HashSet;
    20 import java.util.Iterator;
    21 import java.util.LinkedHashSet;
    22 public class LinkedHashSetDemo {
    23 public static void main(String[] args) {
    24         HashSet hs = new LinkedHashSet();
    25         hs.add("hahah");
    26         hs.add("hehe");
    27         hs.add("heihei");
    28         hs.add("xixii");
    29 //        hs.add("hehe");
    30         Iterator it = hs.iterator();
    31         while(it.hasNext()){
    32             System.out.println(it.next());
    33         }
    34     }
    35 }

      (三)TreeSet

      1、TreeSet:默认按照字母的自然排序。底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0。

      TreeSet排序有两种方式:

      (1)第一种方式:让元素自身具备比较性,元素要实现Comparable接口,覆盖CompareTo方法,这种方式也称为元素的自然顺序,也叫默认顺序。代码示例如下:

     1 import java.util.*;
     2 //学生类
     3 class Student implements Comparable{
     4     private String name;
     5     private int age;
     6     Student(String name,int age){
     7         this.name=name;
     8         this.age=age;
     9     }
    10     public String getName(){
    11         return name;
    12     }
    13   
    14     public int getAge(){
    15         return age;
    16     }
    17     //复写hashCode 方法
    18     public int hashCode(){
    19         return name.hashCode()+age*39;
    20     }
    21     //覆写equals方法 
    22     public boolean equals(Object obj){
    23         if(!(obj instanceof Student))
    24             throw new RuntimeException();
    25         Student s = (Student)obj;
    26         return this.name.equals(s.name)&&this.age==s.age;
    27     }
    28     //覆写compareTo方法 
    29     public int compareTo(Object obj){
    30         Student s = (Student)obj;
    31         if(this.age==s.age)
    32             return this.name.compareTo(s.name);
    33         return this.age-s.age;
    34     }
    35 }
    36 
    37 class TreeSetTest{
    38     public static void main(String[] args){
    39         TreeSet<Student> t=new TreeSet<Student>();
    40         t.add(new Student("zhangsan",22));
    41         t.add(new Student("lisi",20));
    42         t.add(new Student("wangwu",19));
    43         t.add(new Student("zhouliu",19));
    44         t.add(new Student("zhaoqi",28));
    45 
    46         for (Iterator<Student> it=t.iterator(); it.hasNext(); ){
    47             Student s=it.next();
    48             System.out.println(s.getName()+"....."+s.getAge());
    49         }
    50     }
    51 }

      (2)第二种方式:当元素自身不具备比较性时,或者具备的比较性不是所需要时,这时就需要让集合自身具备比较性,就需要定义比较器,即定义一个类,实现Comparator接口,覆盖compare方法。比较器示例代码如下:

      /* 需求: 往TreeSet集合中存储自定义对象学生, 想按照学生的年龄进行排序。 */

     1 import java.util.*;
     2 //学生类
     3 class Student implements Comparable{
     4     private String name;
     5     private int age;
     6     Student(String name,int age){
     7         this.name=name;
     8         this.age=age;
     9     }
    10     public String getName(){
    11         return name;
    12     }
    13   
    14     public int getAge(){
    15         return age;
    16     }
    17     //覆写hashCode方法
    18     public int hashCode(){
    19         return name.hashCode()+age*39;
    20     }
    21 //覆写equals方法
    22     public boolean equals(Object obj){
    23         if(!(obj instanceof Student))
    24             throw new RuntimeException();
    25         Student s = (Student)obj;
    26         return this.name.equals(s.name)&&this.age==s.age;
    27     }
    28     //复写compareTo以便TreeSet集合调用
    29     public int compareTo(Object obj){
    30         Student s=(Student)obj;
    31         if(this.age==s.age)
    32             return this.name.compareTo(s.name);
    33         return this.age-s.age;
    34         //return new Integer(this.age).compareTo(new Integer(s.age)); 
    35     }
    36 }
    37 
    38 class  TreeSetTest{
    39     public static void main(String[] args){
    40         TreeSet<Student> t=new TreeSet<Student>(new LenCompare());
    41         t.add(new Student("zhangsan",22));
    42         t.add(new Student("lisi",20));
    43         t.add(new Student("wangwu",19));
    44         t.add(new Student("zhouliu",19));
    45         t.add(new Student("zhaoqi",28));
    46 
    47         for (Iterator<Student> it=t.iterator(); it.hasNext(); ){
    48             Student s=it.next();
    49             System.out.println(s.getName()+"....."+s.getAge());
    50         }
    51     }
    52   
    53 }
    54 //定义比较器,以姓名长度为主要比较
    55 class LenCompare implements Comparator<Student>{
    56     public int compare(Student s1,Student s2){
    57         int num=new Integer(s1.getName().length()).compareTo(new Integer(s2.getName().length()));
    58         if (num==0){
    59             return new Integer(s1.getAge()).compareTo(s2.getAge());
    60         }
    61         return num;
    62     }
    63 }

    六、Map集合

      (一)概述

        Map<K,V>集合是一个接口,和List集合及Set集合不同的是,它是双列集合。

      (二)Map集合子类体系

      Map:

        |--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0,效率低。

        |--HashMap:底层是哈希表数据结构。允许使用null键null值,该集合是不同步的。JDK1.2,效率高。

        |--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给Map集合中的键进行排序。

        Map和Set很像。其实Set底层就是使用了Map集合。

      (三)Map特点

      该集合存储键值对,一对一对往里存,而且要保证键的唯一性。

      (四)Map集合的常用方法

      1、添加

      value put(K key,V value):添加元素,如果出现添加时,相同的键,那么后添加的值会覆盖原有键对应值,并put方法会返回被覆盖的值。

      void putAll(Map <? extends K,? extends V> m):添加一个集合

      2、删除

      clear():清空

      value remove(Object key):删除指定键值对

      3、判断

      containsKey(Object key):判断键是否存在

      containsValue(Object value):判断值是否存在

      isEmpty():判断是否为空

      4、获取

      get(Object key):通过键获取对应的值

      size():获取集合的长度

      values():获取Map集合中所以得值,返回一个Collection集合

      5、两个取出方法

      Set<Map.Entry<K , V>>  entrySet();

      Set<K> keySet();

      注:HashMap集合可以通过get()方法的返回值来判断一个键是否存在,通过返回null来判断。

      (五)Map集合的两种取出方式

      Map集合的取出原理:将Map集合转成Set集合,再通过迭代器取出。

      1、Set<K> keySet():将Map集合中所有的键存入Set集合。因为Set具备迭代器。所以可以通过迭代方式取出所有键,再通过get方法获取每一个键对应的值。示例代码如下:

     1 import java.util.HashMap;
     2 import java.util.Iterator;
     3 import java.util.Map;
     4 public class MapDemo{
     5     public static void main(String[] args){
     6         Map<Integer,String> map = new HashMap<Integer,String>();
     7         map.put(1, "zhangsan");
     8         map.put(2, "lisi");
     9         map.put(3, "wangwu");
    10         map.put(4, "zhaoliu");
    11         map.put(5, "zhouqi");
    12         keyset(map);
    13     }
    14 //keySet取出方式
    15     public static void keyset(Map<Integer,String> hm){
    16         Iterator<Integer> it = hm.keySet().iterator();
    17         while(it.hasNext()){
    18             Integer key = it.next();
    19             String value = hm.get(key);
    20             System.out.println(key+":"+value);
    21         }
    22     }
    23 }

      2、Set<Map.Entry<K,V>> entrySet():将Map集合中的映射关系存入到Set集合中,而这个关系的数据类型就是:Map.Entry。关于Map.Entry:其实Entry也是一个接口,它是Map的接口中的一个内部接口。示例代码如下: 

     1 import java.util.HashMap;
     2 import java.util.Iterator;
     3 import java.util.Map;
     4 import java.util.Set;
     5 public class MapDemo{
     6     public static void main(String[] args){
     7         Map<Integer,String> map = new HashMap<Integer,String>();
     8         map.put(1, "zhangsan");
     9         map.put(2, "lisi");
    10         map.put(3, "wangwu");
    11         map.put(4, "zhaoliu");
    12         map.put(5, "zhouqi");
    13         keyset(map);
    14     }
    15     //Map.Entry取出方式
    16     public static void keyset(Map<Integer,String> hm){
    17         Set<Map.Entry<Integer,String>> entrySet = hm.entrySet();
    18         Iterator<Map.Entry<Integer,String>> it = entrySet.iterator();
    19         
    20         while(it.hasNext()){
    21             Map.Entry<Integer, String> me = it.next();
    22             Integer key = me.getKey();
    23             String value = me.getValue();
    24             System.out.println(key+":"+value);
    25         }
    26     }
    27 }

      (六)Map集合存储自定义对象

      /*  每一个学生都有对应的归属地。

           学生Student,地址String。

           学生属性:姓名,年龄。

           注意:姓名和年龄相同的视为同一个学生。

           保证学生的唯一性。

           思路: 1、描述学生类; 2、定义一个Map集合,存储学生对象和地址值;3、获取Map中的元素。*/

     1 import java.util.HashMap;
     2 import java.util.Iterator;
     3 import java.util.Set;
     4 public class MapDemo {    
     5     public static void main(String[] args) {
     6         /*将学生对象和学生的归属地通过键与值存储到map集合中。*/    
     7         HashMap<Student,String> hm = new HashMap<Student,String>();
     8         hm.put(new Student("lisi",38),"北京");
     9         hm.put(new Student("zhaoliu",24),"上海");
    10         hm.put(new Student("xiaoqiang",31),"沈阳");
    11         hm.put(new Student("wangcai",28),"大连");
    12         hm.put(new Student("zhaoliu",24),"铁岭");
    13         Iterator<Student> it = hm.keySet().iterator();    
    14         while(it.hasNext()){
    15             Student key = it.next();
    16             String value = hm.get(key);
    17             System.out.println(key.getName()+":"+key.getAge()+"---"+value);
    18         }
    19     }
    20 }
    21 //定义学生类,继承Person类
    22 class Student extends Person {
    23     public Student() {
    24         super();
    25     }
    26     public Student(String name, int age) {
    27         super(name, age);
    28     }
    29     @Override
    30     public String toString() {
    31         return "Student:"+getName()+":"+getAge();
    32     }
    33 }
    34 //定义Person类,实现Comparable接口
    35 class Person implements Comparable<Person> {
    36     private String name;
    37     private int age;    
    38     public Person() {
    39         super();
    40     }
    41     public Person(String name, int age) {
    42         super();
    43         this.name = name;
    44         this.age = age;
    45     }
    46     public int compareTo(Person p){
    47         int temp = this.age - p.age;
    48         return temp==0?this.name.compareTo(p.name):temp;
    49     }
    50     @Override
    51     public int hashCode() {
    52         final int prime = 31;
    53         int result = 1;
    54         result = prime * result + age;
    55         result = prime * result + ((name == null) ? 0 : name.hashCode());
    56         return result;
    57     }
    58     @Override
    59     public boolean equals(Object obj) {
    60         if (this == obj)
    61             return true;
    62         if (obj == null)
    63             return false;
    64         if (getClass() != obj.getClass())
    65             return false;
    66         Person other = (Person) obj;
    67         if (age != other.age)
    68             return false;
    69         if (name == null) {
    70             if (other.name != null)
    71                 return false;
    72         } else if (!name.equals(other.name))
    73             return false;
    74         return true;
    75     }
    76     public String getName() {
    77         return name;
    78     }
    79     public void setName(String name) {
    80         this.name = name;
    81     }
    82     public int getAge() {
    83         return age;
    84     }
    85     public void setAge(int age) {
    86         this.age = age;
    87     }
    88     @Override
    89     public String toString() {
    90         return "Person:"+getName()+":"+getAge();
    91     }
    92 }

      (七)Map练习

      /* 获取该字符串“jsdfjliwernsdfmxcjfoj”中的每个字母出现的次数,希望打印的结果是:a(1)b(2)..... */

     1 import java.util.*;
     2 class CharCount {
     3     public static void main(String[] args) {
     4         String str = "jsdfjliwernsdfmxcjfoj";
     5         System.out.println("str中各字母出现的次数:" + charCount(str));
     6     }
     7     // 定义一个方法获取字符串中字母出现的次数
     8     public static String charCount(String str) {
     9         char[] cha = str.toCharArray();// 转换为字符数组
    10         // 定义一个TreeMap集合,因为TreeMap集合会给键自动排序
    11         TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
    12         int count = 0;// 定义计数变量
    13         for (int x = 0; x < cha.length; x++) {
    14             if (!(cha[x] >= 'a' && cha[x] <= 'z' || cha[x] >= 'A'
    15                     && cha[x] <= 'Z'))
    16                 continue;// 如果字符串中非字母,则不计数
    17             Integer value = tm.get(cha[x]);// 获取集合中的值
    18             if (value != null)// 如果集合中没有该字母,则存入
    19                 count = value;
    20             count++;
    21             tm.put(cha[x], count);// 存入键值对
    22             count = 0;// 复位计数变量
    23         }
    24         StringBuilder sb = new StringBuilder();// 定义一个容器
    25         // 遍历集合,取出并以题目格式存入容器中
    26         for (Iterator<Character> it = tm.keySet().iterator(); it.hasNext();) {
    27             Character ch = it.next();
    28             Integer value = tm.get(ch);
    29             sb.append(ch + "(" + value + ")");
    30         }
    31         return sb.toString();// 返回字符串
    32     }
    33 }

     七、集合的一些技巧 

      需要唯一吗? 

        |——需要:Set 

        |             需要制定顺序吗? 

        |                    |——需要:TreeSet 

        |                    |——不需要:HashSet 

        |                    但是要想要一种存储一致的顺序,用LinkedHashSet。 

        | 

        |——不需要:List 

        |                    需要频繁增删吗? 

        |                           |——需要:LinkedList 

        |                           |——不需要:ArrayList 

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

  • 相关阅读:
    BFS(广搜训练题目)
    练习赛1(补题)
    练习赛1(AC题)
    codeup 1743: 算法3-4:表达式求值
    数学相关(更新ing)
    c语言常用函数(更新ing)
    大牛的博客(学习不止,更新不止)
    51nod 1005 大数加法
    js1-----预览js内容
    css10---转载---定位,浮动
  • 原文地址:https://www.cnblogs.com/jianxingjianyuan2014/p/4003952.html
Copyright © 2011-2022 走看看