集合框架和泛型

集合框架概述

  1. 集合類的作用:存儲對象,長度可變。
  2. 所屬的包:java.util
  3. 集合框架常用體系
     
    Collection
    |---List(有序):通過重寫equals()保證唯一性。
    |---ArrayList(變長數組):查詢效率高,更新效率低。線程不同步
    |---LinkedList(鏈表):更新效率高,查詢效率低。
    |---Vector(數組):線程同步,效率低,被ArrayList取代。
    |---Set(唯一)
    |---HashSet(哈希表):重寫hashCode()和equals()保證唯一性。
    |---TreeSet(二叉樹):通過讓元素具備比較性或讓集合具備比較性保證唯一性和排序。
    Map
    |---HashMap(哈希表):允許使用null鍵null值,線程不同步,效率高。
    |---TreeMap(二叉樹):可以按鍵排序,不同步。
    |---HashTable(二叉樹):不允許使用null鍵null值,線程同步,效率低。
  4. 如何選擇具體的集合類?
    1. 要求時間複雜度:List
      • 查詢操作多:ArrayList
      • 更新操作多:LinkedList
    2. 要求空間複雜度:Set
      • 只要求唯一性:HashSet
      • 要求唯一、有序:TreeSet

Collection接口

  1. 共性方法(關於集合)

    1. 增:add(Object)
    2. 刪:remove(Object)、clear()
    3. 查:size()、contains(Object)、isEmpty()
    4. 並:addAll(Collection)
    5. 交:retainAll(Collection)
    6. 差:removeAll(Collection)
  2. Iterator迭代器

    1. 爲什麼出現迭代器?

      由於Collection子接口下有的有索引有的沒索引,不能像數組循環一樣獲取元素,因此必須有hasNext()和next(),兩個方法只有一起使用時纔有意義,因此將其封裝成Collection的內部類,修飾爲private並對外提供獲取內部類對象的接口iterator(),返回類型是Iterator。比喻:Collection接口是娃娃機,Iterator是娃娃機的夾子,娃娃機夾子有抓取娃娃的操縱桿next()。

    2. 迭代器示例

      Iterator it = al.iterator();
      while(it.hasNext())
      {
          sop(it.next());
      }
    3. 注意

      在迭代時不可以通過集合對象的方法操作集合中的元素,因爲會發生併發修改異常,所以只能通過迭代器的方法操作元素。

  3. List接口

    1. List特有方法(關於索引)
       
      增:add(index,ele)、addAll(index,Collection)
      刪:remove(index)
      改:set(index,ele)
      查:get(index)、indexOf(ele)、subList(from,to)、listIterator()
    2. ListIterator迭代器

      ListIterator相較於Iterator迭代器的作用:由於List集合有索引,因此可在迭代的同時使用ListIterator迭代器的增刪改查方法對元素進行操作。方法:add(ele)、remove()、set(ele)、hasNext()、hasPrivious()。

      ListIterator li = al.listIterator();
      while(li.hasNext())
      {
          Object obj = li.next(); 
          if(obj.equals("haha"))
              li.add("hehe");     //利用迭代器進行集合的添加元素
      }
    3. LinkedList特有方法(關於收尾結點)

      1.增:addFirst()、addLast()、
      2.刪:removeFirst()、removeLast()
      3.查:getFirst()、getLast()
      若集合中沒有元素,會出現NoSuchElementException異常
      
      JDK1.6出現的替代方法
      1.增:offerFirst()、offerFirst()
      2.刪:peakFirst()、peakLast()
      3.查:pollFirst()、pollLast()
      若集合中沒有元素,會返回null。
      
  4. Set接口

    1. HashSet保證唯一性依據:hashCode和equals()。先比較兩個對象的hashCode是否相同,若不同,直接存儲進集合;若相同,再用equals()比較是否是同一個對象,若不是就存儲進集合,否則不存儲。代碼示例。

      import java.util.*;
      class Person
      {
          private String name;
          private int age;
          Person(String name,int age)
          {
              this.name = name;
              this.age = age;
          }
      
          //重寫hashCode()
          public int hashCode()
          {
              return name.hashCode()+age;
          }
      
          //重寫equals()
          public boolean equals(Object obj)
          {
              if(!(obj instanceof Person))
                  return false;
              Person p = (Person)obj;
      
              return name.equals(p.name) && age == p.age;
          }
      
          public String getName()
          {
              return name;
          }
          public int getAge()
          {
              return age;
          }
      }
      class  HashSetDemo
      {
          public static void main(String[] args) 
          {
              HashSet hs = new HashSet();
      
              hs.add(new Person("a1",11));
              hs.add(new Person("a2",12));
              hs.add(new Person("a2",12));    //重複元素
              hs.add(new Person("a3",13));
      
      
              for(Iterator it  = hs.iterator();it.hasNext();)
              {
                  Person p = (Person)it.next();
                  System.out.println(p.getName()+":"+p.getAge());
              }
          }
      }
      
    2. TreeSet可實現元素排序,排序的兩種方式

      • 讓元素自身具備比較性:實現Comparable,重寫compareTo(),使元素實現自然排序。
      • 讓集合具備比較性:自定義比較器類,實現Comparator接口,重寫compare(),傳自定義比較器類的對象給集合的構造函數,讓集合排序。應用場景:當使用別人的類,但比較性不是自己需要的時候。
      //第一種排序方式:讓元素自身具備比較性,實現自然排序
      import java.util.*;
      class Person implements Comparable      
      {
          private String name;
          private int age;
          Person(String name,int age)
          {
              this.name = name;
              this.age = age;
          }
      
          //重寫compareTo方法
          public int compareTo(Object obj)
          {
              if(!(obj instanceof Person))
                  throw new RuntimeException("不是人對象");
              Person p = (Person)obj;
      
              if(this.age > p.age)
                  return 1;
              if(this.age == p.age)   //若主要依據相同,要比較次要依據
                  return this.name.compareTo(p.name);
              return -1;
          }
      
          public String getName()
          {
              return name;
          }
          public int getAge()
          {
              return age;
          }
      }
      class TreeSetDemo 
      {
          public static void main(String[] args) 
          {
              TreeSet ts = new TreeSet();
      
              ts.add(new Person("lisi01",22));
              ts.add(new Person("lisi02",25));
              ts.add(new Person("lisi03",22));
              ts.add(new Person("lisi03",22));    //重複元素
              ts.add(new Person("lisi04",23));
      
              for(Iterator it = ts.iterator();it.hasNext();)
              {
                  Person p = (Person)it.next();
                  System.out.println(p.getName()+":"+p.getAge());
              }
          }
      }
      //第二種排序方式:讓集合具備比較性
      import java.util.*;
      class MyComparator implements Comparator
      {
          //重寫compare方法
          public int compare(Object o1,Object o2)
          {
              Person p1 = (Person)o1;
              Person p2 = (Person)o2;
      
              int num = p1.getName().compareTo(p2.getName());
              if(num == 0)        //若主要依據相同,要比較次要依據
                  return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
              return num;
          }
      }
      class TreeSetDemo1
      {
          public static void main(String[] args) 
          {
              //傳入比較器對象使集合具備比較性
              TreeSet ts = new TreeSet(new MyComparator());
      
              ts.add(new Person("lisi01",22));
              ts.add(new Person("lisi02",25));
              ts.add(new Person("lisi03",22));
              ts.add(new Person("lisi03",22));    //重複元素
              ts.add(new Person("lisi04",23));
      
              for(Iterator it = ts.iterator();it.hasNext();)
              {
                  Person p = (Person)it.next();
                  System.out.println(p.getName()+":"+p.getAge());
              }
          }
      }

泛型

  1. 作用

    1. 將運行時期出現的問題ClassCastException轉移到了編譯時期,方便於程序員解決問題。
    2. 避免了強制轉換麻煩。
    3. 一般在集合類中使用。
    import java.util.*;
    class  GenericDemo
    {
        public static void main(String[] args) 
        {
            //定義時就明確了要操作的類型
            ArrayList<String> al = new ArrayList<String>();
    
            //只能操作String類型
            al.add("abc01");
            al.add("abc02");
            al.add("abc03");
    
            for(Iterator<String> it = al.iterator();it.hasNext();)
            {
                String s = it.next();
                System.out.println(s);
            }
        }
    }
  2. 泛型類

    使用場景:當類的對象要操作的類型一確定,成員方法操作的類型就明確,就可定義泛型類。

    /*
    //泛型前做法
    class Tool
    {
        private Object obj;
        public void setObject(Object obj)
        {
            this.obj = obj;
        }
        public Object getObject()
        {
            return obj;
        }
    }
    */
    
    //泛型類
    class Utils<T>
    {
        private T t;
        public void setObject(T t)
        {
            this.t = t;
        }
        public T getObject()
        {
            return t;
        }
    }
    
    class GenericDemo2
    {
        public static void main(String[] args) 
        {
            //泛型前做法
    //      Tool t = new Tool();
    //      t.setObject(new String("abc"));
    //      String s = (String)t.getObject();   //需要轉型
    //      System.out.println(s);
    
            //泛型做法
            Utils<String> u = new Utils<String>();
            u.setObject(new String("abc"));
            String s = u.getObject();           //無需轉型
            System.out.println(s);
        }
    }
  3. 泛型方法

    使用場景:爲了讓類中的不同方法可以操作不同類型,就可以將泛型定義在法上,類似於重載。

    class Demo<T>
    {
        public void show(T t)       //跟隨類的泛s型
        {
            System.out.println("show:"+t);
        }
        public <Q> void print(Q q)  //方法上的泛型
        {
            System.out.println("print:"+q);
        }
    }
    
    class  GenericDemo3
    {
        public static void main(String[] args) 
        {
            Demo<Integer> d = new Demo<Integer>();  //指定操作的類型是Integer
    
            d.show(new Integer(3));
            //d.show("abc");                        //編譯出錯,show()參數類型只能是Integer
    
            d.print(3);                             //print()參數類型任意
            d.print("abc");
        }
    }

    靜態方法的泛型只能定義在方法上,因爲靜態比對象先加載。

  4. 泛型限定

    1. 泛型的限定:? 通配符,代表任意類型
    2. 泛型限定上限:<? extends E> 接收E或者E的子類型
    3. 泛型限定下限:<? super E>> 接收E或者E的父類型
    //泛型限定上限
    import java.util.*;
    class GenericDemo4 
    {
        public static void main(String[] args) 
        {
            TreeSet<Person> ts = new TreeSet<Person>(new Comp());
            ts.add(new Person("lisi1"));
            ts.add(new Person("lisi2"));
            ts.add(new Person("lisi3"));
    
            TreeSet<Student> ts1 = new TreeSet<Student>(new Comp());
            ts1.add(new Student("zhang1"));
            ts1.add(new Student("zhang2"));
            ts1.add(new Student("zhang3"));
    
            print(ts);
            print(ts1);
        }
    
        //泛型限定,只可以接收Person及其子類對象
        public static void print(TreeSet<? extends Person> al)  
        {
            for(Iterator<? extends Person> it = al.iterator();it.hasNext();)
            {
                //只能調用父類中的方法
                System.out.println(it.next().getName());
                //it.next().showName();     //編譯出錯,無法使用子類特有方法
            }
        }
    }
    
    class Person
    {
        private String name;
        Person(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return name;
        }
    }
    class Student extends Person
    {
        Student(String name)
        {
            super(name);
        }
        public void showName()
        {
            System.out.println(getName());
        }
    }
    
    //比較器泛型使用,可以比較Person和Person子類
    class Comp implements Comparator<Person>    
    {
        public int compare(Person p1,Person p2)
        {
            //只能用父類方法
            return p1.getName().compareTo(p2.getName());    
        }
    }
    //泛型限定下限
    import java.util.*;  
    import stu.love.v.Demo11;  
    
    //父類的比較器   <Person>  
    class CompareByAge implements Comparator<Person>  
    {  
        public int compare(Person s1,Person s2)  
        {  
            int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));  
            if(num==0)  
                return s1.getName().compareTo(s2.getName());  
            return num;  
        }  
    
    }  
    
    /*// 子類 特殊的 比較器  Student  
    class ComByAge implements Comparator<Student>  
    {  
        public int compare(Student s1,Student s2)  
        {  
            int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));  
            if(num==0)  
                return s1.getName().compareTo(s2.getName());  
            return num;  
        }  
    }  
    
    // 子類 特殊的 比較器 Teacher  
    class ComByAge2 implements Comparator<Teacher>  
    {  
        public int compare(Teacher s1,Teacher s2)  
        {  
            int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));  
            if(num==0)  
                return s1.getName().compareTo(s2.getName());  
            return num;  
        }  
    }*/  
    
    class Demo13   
    {  
        //TreeSet<E>(Comparator<? super E> comparator) 定義比較器時,可以是E類型,還可以是E的父類型,E在創建集合對象時確定  
        public static void main(String[] args)   
        {  
            TreeSet<Student> t1 = new TreeSet<Student>(new CompareByAge());  
            t1.add(new Student("zhaosi",23));  
            t1.add(new Student("lisi",25));  
            t1.add(new Student("wangwu",20));  
    
    
            TreeSet<Teacher> t2 = new TreeSet<Teacher>(new CompareByAge());  
            t2.add(new Teacher("wang",38));  
            t2.add(new Teacher("lilaoshi",48));  
            t2.add(new Teacher("zhanglaoshi",58));  
        }  
    }  

Map接口

  1. 描述

    存儲鍵值對,一個鍵對應一個值,當後添加的鍵與之前的鍵相同時,後添加的元素會覆蓋之前的元素。

  2. 方法
     
    增:put(key,value)、putAll(Map)
    刪:remove(key)、clear()
    獲取:size()、get(key)、values()、entrySet()、keySet()
    判斷:isEmpty()、containsKey(key)、containsValue(value)
  3. 獲取元素的兩種方式:keySet和entrySet()

    1. keySet():獲取Map集合的鍵集合
    2. entrySet():獲取Map集合的映射關係集合
    //keySet()和entrySet()用法案例
    import java.util.*;
    class MapDemo2 
    {
        public static void main(String[] args) 
        {
            Map<String,String> map = new HashMap<String,String>();
    
            map.put("02","lisi2");
            map.put("01","lisi1");
            map.put("03","lisi3");
            map.put("04","lisi4");
    
            //1,通過keySet獲取鍵的集合
            Set<String> keySet = map.keySet();
            for(Iterator<String> it = keySet.iterator();it.hasNext();)
            {
                //取出一個鍵
                String key = it.next(); 
                //通過鍵獲取值            
                System.out.println(key+":"+map.get(key));   
            }
    
            //2,通過entrySet獲取映射關係集合
            Set<Map.Entry<String,String>> entrySet = map.entrySet();
            for(Iterator<Map.Entry<String,String>> it1 = entrySet.iterator();it1.hasNext();)
            {
                //取出一個映射關係
                Map.Entry<String,String> me = it1.next();
                //通過映射關係獲取鍵
                String key = me.getKey();
                //通過映射關係獲取值
                String value = me.getValue();
                System.out.println(key+":"+value);
            }
        }
    } 
    /*
        Map集合一鍵一值用例
    
        "yure"  Student("01","zhangsan")
        "yure"  Stduent("02","lisi")
    
        "jiuye"  Student("01" "wangwu")
        "jiuye"  Student("02" "zhaoliu")
        即一對多關係,由於Map是一對一關係,後會覆蓋前,
        因此要將一對多化解爲一對一:將值存儲在集合中。
    */
    
    import java.util.*;
    class  MapDemo5
    {
        public static void main(String[] args) 
        {
            //預熱班
            List<Student> yure = new ArrayList<Student>();
            yure.add(new Student("01","zhangsan"));
            yure.add(new Student("02","lisi"));
    
            //就業班
            List<Student> jiuye = new ArrayList<Student>();
            jiuye.add(new Student("01","wangwu"));
            jiuye.add(new Student("02","zhaoliu"));
    
            //學校
            HashMap<String,List<Student>>  czbk = new HashMap<String,List<Student>>();
            czbk.put("yure",yure);      //學校有預熱班和就業班
            czbk.put("jiuye",jiuye);
    
            //遍歷czbk集合,獲取所有教室
            for(Iterator<String> it  = czbk.keySet().iterator();it.hasNext();)
            {
                String roomName = it.next();                //獲取一個鍵(教室名稱)
                List<Student> room = czbk.get(roomName);    //通過教室名稱獲取學生集合
                System.out.println(roomName);   
                getInfos(room);         //輸出每個學生的信息
            }
        }
        //遍歷list集合中每個學生的信息
        public static void getInfos(List<Student> list)
        {
            for(Iterator<Student> it = list.iterator();it.hasNext();)
            {
                System.out.println(it.next());
            }
        }
    }
    class Student
    {
        private String id;
        private String name;
        Student(String id,String name)
        {
            this.id = id;
            this.name = name;
        }
        public String toString()
        {
            return id+name;
        }
    }

Collections 工具類

作用:由於List集合不能排序,Collections工具類提供了對List集合進行排序的方法和其他對集合進行操作的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章