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

来源:互联网 发布:等式约束优化 数值求解 编辑:程序博客网 时间:2024/06/05 12:48

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

 

                  集合体系
图片 
          
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的原理:

图片
迭代器其实就是集合的取出元素的方式,会直接访问集合中的元素,所以将迭代器通过内部类的形式来进行描述。通过容器的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()可以,所有对象都具备此方法。
                }
                }
 
                             14Map集合:该集合存储键值对。一对一对往里存,而且要保证键的唯一性。
                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