黑马程序员——12JavaAPI集合类

时间:2022-02-06 11:45:11

------------android培训java培训、期待与您交流!------------  
1,  面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
          数组和集合类同是容器,它们的区别是:
        数组虽然也可以存储对象,但 长度是固定的
        集合长度是可变的。数组中可以存储基本数据类型, 集合只能存储对象
           集合类的特点:集合只用于存储对象,集合长度是可变的,集合可以存储不同数据类型的对象。
2,    出现这么多容器,因为每一个容器对数据的存储方式都有不同。这个存储方式我们称之为:数据结构
      集合框架: 黑马程序员——12JavaAPI集合类 

 

                    集合体系
黑马程序员——12JavaAPI集合类 
            
3,    Collection定义了集合框架的共性功能, 集合中存储的都是对象的引用(地址)  。
          1)添加
           add(e);    // add方法的参数类型是Object。以便于接收任意类型对象。  
                 addAll(collection);
          2)删除
           remove(e);
           removeAll(collection);
           clear();
          3)判断。
           contains(e);
           isEmpty();
          4)获取
          iterator();
          size();
          5)获取交集。
          retainAll();
          6)集合变数组。
          toArray();
4, 迭代器 Iterator的原理:

黑马程序员——12JavaAPI集合类
迭代器 其实就是集合的取出元素的方式, 会直接访问集合中的元素, 所以将迭代器通过内部类的形式来进行描述。 通过容器的iterator()方法获取该内部类的对象。
   class  CollectionDemo{   public static void main(String[] args) {  ArrayList al = new ArrayList();   //1,添加元素。 
  al.add("java01");    //add(Object obj);
                  /*Iterator it = al.iterator();    //获取迭代器,用于取出集合中的元素。   while(it.hasNext()){   sop(it.next()); 
  }*/

                //应用for形式,迭代器用完即释放。更节省内存。  for(Iterator it = al.iterator(); it.hasNext() ; ){   sop(it.next());   } 
  }
}
    5,集合类的比较与总结:            
            1)Collection,List,Set,Map都属于集合框架中的接口。
     Collection,Map是顶层接口。List,Set继承Collection接口。
       2)List:列表,元素是有序的(元素带角标索引),可以 有重复元素 ,可以有null元素。
  Set:集合,元素是无序的(因为没有索引),元素 不可以重复 。可以有null元素。
  Map:顶层接口,该集合存储的是键值对,而且 键是唯一的
            3)Map和Set很像,因为 Set集合底层就是使用了Map集合。
   Map集合没有迭代器,要取出元素必须先将Map集合转换成Set集合才能遍历元素。
        4)实现List接口的常用类:
                4. 1),ArrayList(JDK1.2):
                            底层的数据结构: 数组数据结构。
                             特点:查询速度快(因为带角标),但是增删速度稍慢,因为当元素多时,增删一个元素则所有元素的角标都得改变, 线程不同步 。默认长度是10,当超过长度时,按50%延长集合长度。
                    4. 2),LinkedList(JDK1.2):
                            底层数据结构: 链表数据结构(即后面一个元素记录前一个)。
                        特点:查询速度慢,因为每个元素只知道前面一个元素,但增删速度快,因为元素再多,增删一个,只要让其前后的        元素重新相连即可,  线程是不同步 的。
                   4.3),Vector(JDK1.0):
                            底层数据结构: 数组数据结构。
                             特点:查询和增删速度都很慢。默认长度是10,当超过长度时,按100%延长集合长度。 线程同步
              注意: Vector功能跟ArrayList功能一模一样,已被ArrayList替代。
            5)实现Set接口的常用类:
                   5.1),HashSet(JDK1.2):
                            底层数据结构: 哈希表。
                            特点: 存取速度快,元素唯一,线程不同步。
                        保证性元素唯一的原理:
                先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true。
      注意: 往HashSet里面存的自定义元素要复写hashCode和equals方法,以保证元素的唯一性。
               5. 2),TreeSet(JDK1.2):
                            底层数据结构: 二叉树
                            特点: 可以对Set集合中的元素进行排序。元素有序,线程不同步。
                       保证元素唯一性的依据:compareTo方法return 0。
                         TreeSet排序的第一种方式:
                                        让元素自身具备比较性,比如八种基本数据类型或则字符串,实现Compareble接口,覆盖compareTo方法, 此方式是元素的自然顺序。  
                         TreeSet排序的第一种方式:
                                        当元素自身不具备比较性(比如存储学生对象时)或者具备的比较性不是我们所需要的比较性时(比如想字符串的长度排序),此时就需要让集合自身具备自定义的比较性。可在集合初始化时,就让集合具备比较方式。即定义一个类,实现Comparator接口,覆盖compare方法。
             6)实现Map接口的常用类:
          6. 1),HashTable(JDK1.0):
                              底层数据结构: 哈希表。
                              特点:不可以使用null键和null值,线程同步,效率低。
                               注意:用作键的对象必须实现hashCode和equals方法来保证键的唯一性。
      6. 2),HashMap(JDK1.2):
                              底层数据结构: 哈希表。
                              特点:允许使用null键和null值,线程不同步,效率高;
         保证元素唯一性的原理:先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true。
      6. 3),TreeMap(JDK1.2):
                              底层数据结构: 二叉树。
                              特点:允许使用null键和null值,线程不同步,可以给Map集合中的键进行排序。
       TreeMap排序的第一种方式:
                                           让元素自身具备比较性,比如八种基本数据类型或则字符串,实现Compareble接口,覆盖compareTo方法, 此方式是元素的自然顺序。  
               TreeMap排序的第一种方式:
                                           当元素自身不具备比较性(比如存储学生对象时)或者具备的比较性不是我们所需要的比较性时(比如想字符串的长度排序),此时就需要让集合自身具备自定义的比较性。可在集合初始化时, 就让集合具备比较方式。即定义一个类,实现Comparator接口,覆盖compare方法。
    6, List: 特有方法,凡是可以操作角标的方法都是该体系特有的方法。
          add(index,element);
         addAll(index,Collection);
         删 remove(index);
          set(index,elenment);
         查 get(index);
         subList(from,to);
         listIterator();
        在迭代时,不可以通过集合对象的方法操作集合中的元素, 因为集合和迭代器同时拥有元素对象的引用。此时迭代器去操作集合,有可能发生并发修改异常,即 ConcurrentModificationException异常。
        如果想要其他的操作如添加,修改等,就需使用 Iterator的子接口 ListIterator,   List集合特有的迭代器。
        该接口只能通过List集合的listIterator方法获取。
        import java.util.*;
        class ListDemo {
         public static void main(String[] args) {
         ArrayList al=new ArrayList();
         //添加元素
         al.add("java01");
         al.add("java02");
        System.out.println ("原集合是:"+al);
         for( al.listIterator() ;li.hasNext();) {
        System.out.println ("hasPrevious:"+li.hasPrevious());
         Object obj=li.next();
         if(obj.equals("java02")) {
         li.set("java006");
         li.add("java009");
         }
         System.out.println("hasNext():"+li.hasNext());
        System.out.println ("hasPrevious:"+li.hasPrevious());
         }
          }
         }

    7, 枚举就是Vector特有的取出方式 其实枚举和迭代是一样的。 因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
        import java.util.*;
        class VectorDemo {
         public static void main(String[] args) {
         Vector v=new Vector();
         v.add("java01");
         v.add("java02");
         for(Enumeration en=v.elements();en.hasMoreElements();) {
           System.out.println(en.nextElement());
         }
         }
        }
 
    8, LinkedList:
            特有方法:
                    addFirst();
                    addLast();
                    getFirst();
                    getLast();获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementExceptionremoveFirst();
                    removeLast();获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
                     在JDK1.6出现了替代方法。
                    offerFirst();
                    offerLast();
                    peekFirst();
                    peekLast();获取元素,但不删除元素。如果集合中没有元素,会返回null
                    pollFirst();
                    pollLast();获取元素,但是元素被删除。如果集合中没有元素,会返回null
             使用LinkedList模拟一个堆栈或者队列数据结构。
            堆栈:先进后出FILO
            队列:先进先出FIFO
            import java.util.*;
            class Queue{
                    private LinkedList link;
                    Queue(){
                            link=new LinkedList();
                    }
                    public void myAdd(Object obj) {
                             //头插法,保证先进先出。
                            link.addFirst(obj);
                    }
                    public Object myGet() {
                            return link.removeLast();
                    }
                    public boolean isNull(){
                            return link.isEmpty();
                    }
            }
            class LinkedListTest{
                    public static void main(String[] args) {
                            Queue d=new Queue();
                            d.myAdd("java01");
                            d.myAdd("java02");
                            while(!d.isNull()){
                                    System.out.println(d.myGet());
                            }
                    }
            }
 
    9,1)ArrayList保证元素唯一,即去除重复元素。需要定义一个临时容器, 用contains方法判断,同时需要复写equals方法。
            public static ArrayList singleElement(ArrayList al){
                    //定义一个临时容器。
                    ArrayList newAl=new ArrayList();
                    for(Iterator it=al.iterator();it.hasNext();){     
                            Object obj=it.next();
                            if(!newAl.contains(obj))
                                    newAl.add(obj);
                            }
                    return newAl;
             } 
         2)HashSet保证元素唯一。 复写hashCode(),equals(Object obj)方法。
            public int hashCode() {
                    return name.hashCode()+age*39; //扩大范围,避免出现重复值
            }
            public boolean equals(Object obj){     //注意:此处参数必须是Object,才能复写Object类中的equals方法。
    if(!(obj instanceof Person))
                            return false;
                    Person p=(Person)obj;
                    return this.name.equals(p.name)&&this.age==p.age;
            } 
 
     10, 当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较器。
            当两种排序都存在时,以比较器为主。
            class TreeSetDemo{
                    public static void main(String[] args){
                             //将自定义的 比较器作为参数传递给TreeSet构造函数。
                            TreeSet<Student> ts=new TreeSet<Student>(new MyCompare());
                            ts.add(new Student("lisi02",22));
                            ts.add(new Student("lisi007",20));
                            ts.add(new Student("lisi09",19));
                            for(Iterator<Student> it=ts.iterator();it.hasNext();){
                                    Student s=it.next();
                                    System.out.println(s.getName()+'\t'+s.getAge());
                            }
                    }
                     //第二种排序方法,自定义一个比较器,当两种排序同时存在时,此种方法生效。
                   class MyCompare implements Comparator<Student>{
                            //复写compare 方法。
                           public int compare(Student o1,Student o2){
                                     //此处使用泛型,不用强转。
                                    //Student s1=(Student)o1;
                                    //Student s2=(Student)o2;
                                    if(!o1.getName().equals(o2.getName()))
                                     return o1.getName().compareTo(o2.getName());
                                    else
                                            return new Integer(o1.getAge()).compareTo(new Integer(o2.getAge()));
                            }
                    }
                    //第一种排序方法, 强制让学生具备比较性。  
                    class Student implements Comparable<Student>{
                             private String name;
                            private int age;
                            Student(String name ,int age){
                                    this.name=name;
                                    this.age=age;
                            }
                             //复写compareTo方法。
                            public int compareTo(Student obj){
                             if(!(obj instanceof Student))
                                            throw new RuntimeException("不是学生对象");
                                    Student s=(Student)obj;
                                    System.out.println(this.name+"..compareTo.."+obj.name);
                                    if(this.age!=obj.age)
                                            return this.age-obj.age;//降序为s.age-this.age
                                    else
                                            return this.name.compareTo(obj.name); //降序为s.name.compareTo(this.name);
                            }
                    }

     11,泛型 :JDK1.5版本以后出现新特性,用于解决安全问题,是一个类型安全机制。
            好处:1)将运行时期出现的问题ClassCastException,转移到编译时期。方便于程序员解决问题。让运行时期问题减少。
                       2)避免了强制转换的麻烦。
            泛型格式:通过<>来定义要操作的引用数据类型。
            在使用java提供的对象时,泛型,通常在集合框架中很常见。
            只要见到<>就要定义泛型,其实<>就是用来接收类型的。
            当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
            class GenericDemo{
                    public static void main(String[] args){
                            ArrayList<String>al=new ArrayList<String>();
                            al.add("abc01");
                            //al.add(new Integer(4)); //编译时报错,泛型在编译时期检查类型。  
                            for(Iterator<String> it=al.iterator();it.hasNext();){
                                    String s=it.next();
                                    System.out.println(s+'\t'+":"+s.length());
                            }
                    }
            }

     12,自定义泛型。
            1)泛型定义在类上。
                    当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现定义泛型来完成扩展。
                     class Utils<Q>{
                            private Q q;
                            public void setObject(Q q){
                                    this.q=q;
                            }
                            public Q getObject(){
                                    return q;
                            }
                    }  
            2)泛型定义在方法上。 方法 声明泛型应紧靠返回值的前面。
                     泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
                              class Demo<T>{     //泛型类
                                    public void show(T t){
                                            System.out.println("show:"+t);
                                    }
                                    public <Q>void print(Q q){ //泛型方法。
                                            System.out.println("print:"+q);
                                    }
                                    public static <W>void method(W t){ //泛型定义在静态方法上。
                                            System.out.println("method:"+t);
                                    }
                            }
                  特殊之处:静态方法不可以访问类上定义的泛型。因为类上的泛型只对该类的对象有效。
                                  如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。
            3)泛型定义在接口上。    
                               interface Inter<T> {
                                     void show(T t);
                               }
                              class InterImpl<T> implements Inter<T> {
                                      public void show(T t) {
                                              System.out.println("show:"+t);
                                      }
                              }
 
                 13, ?通配符,也可以理解为占位符。
                          泛型的限定:
                                ?extends E:可以接收E类型或者E的子类。上限。
                                ?super E:可以接收E类型或者E的父类型。下限。
                        public static void printColl(ArrayList<?> al) {
                 for(Iterator<?> it=al.iterator();it.hasNext();) {
                 System.out.println(it.next());
                                         //.length()不可以,具体的类型方法。
//.toString()可以,所有对象都具备此方法。
                 }
                 }
 
                             14 Map集合:该集合存储键值对。一对一对往里存,而且要保证键的唯一性。
                 1)添加。
                  put(K key,V value);    //注意此处添加为put。
                  putAll(Map<? extends K,? extends V> m);
                  2)删除。
                  clear();
                  remove(Object key);
                  3)判断。
                  containsKey(Object key);
                  containsValue(Object value);
                  isEmpty();
                  4)获取。
                  get(Object key);
                  size();
                  values();
                  entrySet();
                  keySet();
                         Map集合的取出原理:将map集合转成Set集合,再通过迭代器取出。 
                        Map集合的两种取出方式:
                          1)Set<K>  keySet:
                                      将Map中所有的键存入到Set集合,因为set具备迭代器,所以可以用迭代方式取出所有的键,
                                      再根据get方法,获取每一个键对应的值。
    
                                      //先获取map集合中的所有键的Set集合,keySet();
                                 Set<String> keySet=map.keySet();
                                 //有了Set集合就可以获取其迭代器。
                                 for(Iterator<String> it=keySet.iterator();it.hasNext();) {
                                 String key=it.next();
                                 //有了键就可以通过Map集合的get方法获取其对应的值。
                                 String value=map.get(key);
                                 System.out.println("key:"+key+"...value:"+value);
                      }  
                                     2)Set<Map.Entry<K,V>>  entrySet:将map集合中的映射关系存入到set集合中, 而这个关系的数据类型就是:Map.Entry。                   
                                     //将Map集合中的映射关系取出,存入到Set集合中。
                                     Set<Map.Entry<String,String>> entrySet=map.entrySet();    
                                     for(Iterator<Map.Entry<String,String>> it=entrySet.iterator();it.hasNext();) {    
                                             Map.Entry<String,String> me=it.next();
                                 String key=me.getKey();
                                 String value=me.getValue();
                                 System.out.println(key+":::"+value);
                                 }

                15,其他API。
                        1)集合框架的工具类 Collections
                        二分查找: binarySearch(List<?
extends 
Comparable<? super T>> list, T key)

                        替换列表中的所有元素: fill ( List <? super T> list, T obj)  

                        2)集合变数组:toArray();
                        目的: 为了限定对元素的操作。不需要进行增删。 
                         String[] s=al.toArray(new String[al.size()]);
                        // 当指定的数组长度小于了集合的size,那么该方法内部会创建一个新的数组  
                     Arrays.toString(s);    
                        
                        3) 高级for循环,JDK1.5的新特性。
                            格式: for(数据类型 变量名:被遍历的集合(Collection)或者数组) { }
                             对集合进行遍历, 只能获取元素,不能对集合进行操作。
                             迭代器除了遍历,还可以remove集合中元素的动作。 如果使用ListIterator,还可以在遍历过程中进行增删改查的动作。                            
                             传统for和高级for的区别: 高级for有一个局限性,必须有被遍历的目标。
                                      建议在遍历数组的时候,还是希望使用传统for,因为传统for可以定义角标。  
                    
                        4) 方法的可变参数, JDK1.5版本的新特性。
                             在使用是注意:可变参数一定定义在参数列表的最后边。
                               public static void show(int... arr) {
                                     System.out.println(arr.length);
                              }    

                        5) StaticImport 静态导入,JDK1.5的新特性。
                              import java.util.*;
                               //导入Arrays这个类中的所有静态成员。  
                              import static java.util.Arrays.*;
                               //导入了System类中所有的静态成员。  
                              import static java.lang.System.*;                               
                              class StaticImport{
                                      public static void main(String[] args){
                                                out.println("haha");
                                                int[] arr={3,1,5};
                                                sort(arr);
                                                int index=binarySearch(arr,1);
                                                out.println(Arrays.toString(arr));
                                                out.println("Index:"+index);
                                       }
                                }
                            注意: 当类名重名时,需要制定具体的包 名。
                                             当方法重名时,需要指定具体所属的对象或者类。
  ------------android培训java培训、期待与您交流!------------  
详情请查看:http://edu.csdn.net/heima