zoukankan      html  css  js  c++  java
  • 黑马程序员__集合

    毕老师视频 day14-day17

    1.集合类:

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

    • 存储方式有:数组、集合类2种

    数组和集合类都是容器,不同之处:

    • 数组长度是固定的,集合长度是可变的。
    • 数组可以存储基本数据类型,集合只能存储对象。

    集合类的特点:

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

    为什么会出现很多容器:

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

    2.  集合框架  

     

      Collection接口的共性方法:

    • add方法的参数类型是Object,以便接收任意类型的对象;
    • 集合中存储的都是对象的引用。
            //创建一个集合容器,使用Collection接口的子类  ArrayList
            ArrayList al = new ArrayList();
            al.add("212334");
            al.add("japa");
            al.add("212");
            al.add("japa");//1.追加
            System.out.println(al);
            System.out.println(al.size());  //2.大小
            
            
            al.remove("japa"); //3.删除
            System.out.println(al);
                
            System.out.println(al.contains("japa"));//4.查询
            System.out.println(al.isEmpty());  //5.空否
            
        //    System.out.println(al.clear());  //6.清空
            System.out.println(al);
            
            ArrayList bl = new ArrayList();
            bl.add("japa");
            bl.add("japa1");
            bl.add("japa2");
        //    System.out.println(al.retainAll(bl));  //al保留交集部分,bl不变
            System.out.println(al.removeAll(bl));  //al移除交集部分,bl不变
            System.out.println(al);
            System.out.println(bl);

    3. 迭代器:

    • 集合的取出元素的方式。

    取出方式被定义成了集合的内部类,这样它就可以直接访问集合内容的元素。

    每个容器的数据机构不同,所以取出方式的细节也不同,但是有共性内容: 判断和取出

    这些内部类都符合一个规则: 接口 Iterator

    然后通过集合获取取出方式的对象?  通过每个集合类定义的  iterator() 方法

    接口Iterator 只有3个方法:

    boolean hasNext()   // 如果仍有元素可以迭代,则返回 true。
    E next()   //使迭代器移至下一个位置,返回迭代器经过的对象
    void remove()  //删除迭代器左边的对象

        Iterator it = al.iterator();
            System.out.println(it.hasNext());  
            System.out.println(it.next());  //返回第一个对象,
            it.remove();              //删除第一个对象 
            System.out.println(it.next());  //返回第二个对象
            System.out.println(al);
       

    4.  Collection接口的2个常见子接口:   List接口     Set接口

    List   元素是有序的,元素可以重复。因为该集合体系有索引。

    Set   元素是无序的,元素不可以重复。

    List集合特有方法:

    //
    void     add(int index, E element)  
    boolean addAll(int index, Collection<? extends E> c)  
    //
    E remove(int index)   //返回被删掉的数据
    //
    E set(int index, E element)  //返回被替代的数据 
    //
    E get(int index)  
    List<E>  subList(int fromIndex, int toIndex) 
    ListIterator<E>  listIterator(int index) 
    int indexOf(Object o)

    List集合特有的迭代器:  ListIterator

    在迭代时,不可以通过集合对象的方法操作集合中的元素,会发生异常。 所以只能用迭代器的方法操作元素。

    Iterator提供的方法有限,如果需要添加、修改操作,需要子接口 ListIterator。

     void add(E e)    //加到迭代器当前的位置,并使其右移一位
     
     boolean hasNext() 
     boolean hasPrevious() 
     
     E next()       //迭代器右移一位,返回经过的对象
     E previous() //迭代器左移一位,返回经过的对象
     
     int nextIndex()    //迭代器不动,返回迭代器右边的角标
     int previousIndex() 
            
     void remove()   //移除由 next 或 previous 返回的最后一个元素
     void set(E e)   //替换由 next 或 previous 返回的最后一个元素
    
            lit.next();   //迭代器在第一个与第二个之间    
            //lit.set("不是");
            lit.remove(); //移除第一个对象
            System.out.println(al);
    
                lit.next();
            lit.next();
            lit.previous();  //迭代器也在第一个与第二个之间        
            //lit.set("不是");
            lit.remove();  //移除第2个对象
            System.out.println(al);

    5.  List接口有3个常见的子类对象:  ArrayList   LinkedList   Vector

    • ArrayList 底层数据结构使用的数组结构:  查询速度快,增删速度慢。   线程不同步
    • LinkedList 底层数据结构使用的链表结构: 查询速度慢,增删速度快。   线程不同步
    • Vector 底层是数组数据结构, 是线程同步的。    1.0有的,1.2开始被ArrayList替代

    (ArrayList 默认长度10,超出后延迟50%;  Vector默认长度10,超出后延迟100%)

        
        /*
        枚举是Vector特有的取出方式。1.0时只有这种方式。
        因为枚举名称过长,已经被迭代器取代了
        */
            Vector  v = new Vector();
            v.add("kaka1");
            v.add("kaka1");
            v.add("kaka1");
            v.add("kaka1");
            for( Enumeration enu = v.elements();enu.hasMoreElements();)
                System.out.println(enu.nextElement());

    6.  LinkedList 特有方法:

     void addFirst(E e) 
     void addLast(E e)     //将指定元素添加到此列表的结尾。 
     E getFirst()  //返回此列表的第一个元素。 
     E getLast()   //返回此列表的最后一个元素。 
     E removeFirst() //返回并移除此列表的第一个元素。 
     E removeLast()  //返回并移除此列表的最后一个元素。没有元素抛出异常
    
    //JDK1.6版本后出现了替代方法,不再抛出异常
     boolean offerFirst(E e) //在此列表的开头插入指定的元素。 
     boolean offerLast(E e) //在此列表末尾插入指定的元素。 
     
     E peekFirst() //获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。 
     E peekLast()  //获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。 
     
     E pollFirst() //获取并移除此列表的第一个元素;如果此列表为空,则返回 null。 
     E pollLast()  //获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。 

    7.  Set集合的方法和 Collection 是一致的。

    HashSet底层数据结构是哈希表。 线程不同步。 HashSet如何保证元素的唯一性?:

    • 通过元素Object的方法 hashCode()  和 equals() 来完成。
    • 先判断hash值是否相等,如果哈希值相同,才会调用 equals 方法。
    • 因此,对应自定义对象,通常要重写hashCode 和 equals 方法。
    • HashSet的寻找和删除方法,contains(obj)  remove(obj) 依赖的也是元素的hashCode和equals方法。
    • ArrayList判断元素是否相同只调用equals().

    TreeSet  可以对Set集合中的元素进行排序。 底层数据结构是二叉树。  如何保证元素唯一性?:

    • compareTo  方法。  contains(obj)、 remove(obj)也调用的compareTo方法。
    • TreeSet排序的第一种方式:  让元素具备可比较性, 元素需要实现 Comparable 接口,重写 compareTo 方法。
    • 第二种方式: 元素不具备比较性时,需要让集合自身具备比较性。
    • 需要定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数
    • 当2种比较方式都存在时,会自动调用比较器方法。
    class Person implements Comparable
    {
        private String name;
        private int age;
        Person(String name, int age)
        {
            this.name = name;
            this.age = age;
        }
    
        public int compareTo(Object obj)
        {
            System.out.println("比较");
            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;
        }
        
    
    }
    
    class myCompare implements Comparator
    {
        public int compare(Object o1,Object o2)
        {
            Person p1 = (Person) o1;
            Person p2 = (Person) o2;
            return 1;
        }
    }

    8.  泛型: JDK1.5之后出现的新特性,用于解决安全问题,是一个安全机制。 好处:

    • 将运行时期可能出现的ClassCastException异常转移到了编译时期,方便程序员解决问题
    • 避免了强制类型转换。

    泛型格式: 通过 <>  来定义要操作的引用数据类型。

    什么时候使用泛型??

    • 通常在集合框架中很常见,只要见到<>就要定义泛型。
    • 在使用集合时,将集合要存储的数据类型作为参数传递到<>中即可。
    • 接口 Comparable 、 Comparator 都带泛型。

    9.泛型类:

    class Util<T>  //泛型类
    {
        private T t;
        public void setObject(T t)
        {
            this.t = t;
        }
        public T getObject()
        {
            return t;
        }
    }

    什么时候定义泛型?

    • 当类中要操作的引用数据的类型不确定时,
    • 早期用Object来完成扩展,现在用泛型来完成扩展。

    泛型方法:

    • 泛型类定义的泛型,在整个类都有效 
    • 当泛型类的实例指出了要操作的数据类型,所有方法的能操作的数据类型就固定了。
    • 为了让不同的方法可以操作不同类型的不确定数据, 可以把泛型定义在方法上
    class Util <QQ>   //可以在泛型类中定义泛型方法表示不同泛型
    {
        private QQ q;
        public <T> void setObject(T t)
        {
            
        }
        //泛型的声明,必须在方法的修饰符(public,static,final,abstract等)之后,返回值声明之前。
        //和泛型类一样,可以声明多个泛型,用逗号隔开。
        public static <T,K> T  getObject(K key)
        {
            return t;
        }
    }

    静态方法泛型:

    • 静态方法不可以访问类上定义的泛型
    • 静态方法只能使用方法自身上定义的泛型
    class Util<T>  //泛型类
    {
        private T t;
        public static <K> void method(K x)
        {
            System.out.println(x);
        }
    }

    泛型定义在接口上:

    interface Inter <T>
    {
        void show(T t);
    }
    class Demo1 implements Inter<String>
    {
        public void show(String str)
        {
            System.out.println(str);
        }
    }
    class Demo2<T> implements Inter<T>  //2个T
    {
        public void show(T t)
        {
            System.out.println(t);
        }
    
    }
    class Main
    {
        public static void main(String [] args)
        {
            Demo1 dm1 = new Demo1();
            dm1.show("haha");
            
            Demo2<Integer> dm2 = new Demo2<Integer>();
            dm2.show(007);
            }
    }

    ? 通配符

    泛型的限定:

    •  ?  extends E    :可以接收E类型或者E的子类型,  上限
    • ?  super E        :  可以接收E类型或者E的父类型 ,  下限
    class Person
    {
        private String name;
        Person(String str)
        {
            this.name = str;
        }
        public String getName()
        {
            return name;
        }
    }
    class Student extends Person 
    {
        Student(String str)
        {
            super(str);
        }
    }
    class Woker extends Person
    {
        Woker(String str)
        {
            super(str);
        }
    
    }
    
    class Comp implements Comparator<Person> //super泛型限定,可以比较Person的子类 
    {
        public int compare(Person s1, Person s2)
        {
            return s1.getName().compareTo(s2.getName());    
        }
    }
    
    
    class Main
    {
        public static void main(String [] args)
        {
            //super泛型限定,定义比较器时,可以定义Student或者它的父类 
            TreeSet<Student> ts = new TreeSet<Student>(new Comp());
            ts.add(new Student("学生11"));
            
            TreeSet<Person> ts2 = new TreeSet<Person>(new Comp());
            ts2.add(new Person("人11"));
            
    
            
            
        
            ArrayList<Person>  ala = new ArrayList<Person>();
            ala.add(new Person("人1"));
            ala.add(new Person("人2"));
            printAl(ala);
            
            ArrayList<Student>  alb = new ArrayList<Student>();
            alb.add(new Student("学生1"));
            alb.add(new Student("学生2"));
            printAl(alb);
                    
            ArrayList<Woker>  alc = new ArrayList<Woker>();
            alc.add(new Woker("工人1"));
            alc.add(new Woker("工人2"));
            printAl(alc);        
            
        }
        //extends泛型限定,定义参数时,可以定义Person或者它的子类 
        public static void printAl(ArrayList<? extends Person> al)
        {
            for(Iterator<? extends Person> it=al.iterator(); it.hasNext();)
            {
                System.out.println(it.next().getName());
            
            }
        }    
    }

    10. Map集合

    • Map集合表示映射关系, 键-->值,  键不可重复
    //添加
    V put(K key, V value) // 在映射中添加传入的键和值, 如果映射中已经包含了一个该键的映射,则旧值被替换。
    void putAll(Map<? extends K,? extends V> m) //从指定映射中将所有映射关系复制到此映射中
    
    //删除
    V remove(Object key) //如果存在一个键的映射,则将其从此 Map 中移除。
    void clear()   //从此映射中移除所有映射关系。 
     
     //查询
    boolean containsKey(Object key)     //如果此映射包含指定键的映射关系,则返回 true。 
    boolean containsValue(Object value) //如果此映射将一个或多个键映射到指定值,则返回 true。 
    boolean isEmpty() //如果此映射未包含键-值映射关系,则返回 true。 
     
     //获取
    V get(Object key) // 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 
    int size()         //返回此映射中的键-值映射关系数。  
    Collection<V> values()  //返回此映射中包含的值的 Collection 视图。 
      
    Set<Map.Entry<K,V>>   entrySet() //返回此映射中包含的映射关系的 Set 视图。 
    Set<K>  keySet()      // 返回此映射中包含的键的 Set 视图。

    |-- Hashtable 底层数据结构是哈希表,  不可以存入null , 线程同步。

    •    键必须实现HashCode和equals方法

    |-- HashMap  底层数据结构也是哈希表, 允许使用 null 键、 null 值, 线程不同步。

    |-- TreeMap  底层数据结构是红黑树。   线程不同步

    • 可以用于给map集合中的键进行排序

    Set集合的底层实现使用了Map集合

    11. Map集合有2种取出方式:

    • keySet 将Map中所有的键存入Set集合,使用Set集合的迭代器取出键,再根据get(key)方法取出值
    • entrySet  将Map集合中的映射关系存入 Set集合,使用Set集合的迭代器取出关系。这个关系的数据类型是:  Map.Entry
    • Map.Entry 是Map 接口的内部接口
    class Student implements Comparable<Student>
    {
        private String name;
        private int age;
        Student(String name, int age)
        {
            this.name = name;
            this.age = age;
        }
        
        public int hashCode()
        {
            return name.hashCode()+age*33;
        }
        public boolean equals(Object obj)
        {
            if(!(obj instanceof Student))
                throw new RuntimeException("类型异常");
            Student stu = (Student) obj;
            return this.name.equals(stu.name) && this.age==stu.age;
        }
        public int compareTo(Student stu)
        {
            if(this.name.compareTo(stu.name)!=0)
                return this.name.compareTo(stu.name);
            return this.age-stu.age;
        }
        public String toString()
        {
            return name+"::"+age;
        }
        
    }
    class Main
    {
        public static void main(String [] args)
        {
            HashMap<Student,String> hm = new  HashMap<Student,String>();
            hm.put(new Student("any",21),"beijing");
            hm.put(new Student("boy",29),"fffkk");
            hm.put(new Student("gir",25),"zhongng");
            hm.put(new Student("zip",18),"gasotan");
        
            //第一种取出方式
            Set<Student> keyset = hm.keySet();
            for(Iterator<Student> it=keyset.iterator(); it.hasNext();)
            {
                Student stu = it.next();
                String adr = hm.get(stu);
                System.out.println(stu+"--"+adr);
            }
            
             //第二种取出方式
             Set<Map.Entry<Student,String>> es = hm.entrySet();
            for(Iterator<Map.Entry<Student,String>> it=es.iterator(); it.hasNext();)
            {
                Map.Entry<Student,String> me = it.next();
                Student stu = me.getKey();
                String adr = me.getValue();
                System.out.println(stu+"==="+adr);        
            }
        }
    }

     12.Collections

    •  Collections是对集合框架的一个工具类。它里边的方法都是静态的,不需要创建对象。并未封装特有数据。
    •  在Collections工具类中大部分方法是用于对List集合进行操作的,如比较,二分查找,随机排序等。

    Collections和Collection的区别:

    •  Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。

             它有两个常用的子接口:

                    List:对元素都有定义索引。有序的。可以重复元素。        

                    Set:不可以重复元素。无序

    • Collections是集合框架中的一个工具类。该类中的方法都是静态的。提供的方法中有可以对list集合进行排序,二分查找等方法

           通常常用的集合都是线程不安全的。因为要提高效率。如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

    //查找
    T max(Collection<? extends T> coll);//根据集合的自然顺序,获取coll集合中的最大元素
    T max(Collection<? extends T> coll,Comparator<? super T> comp);//根据指定比较器comp的顺序,获取coll集合中的最大元素
    static <T> int  binarySearch(Lsit<? extends Comparable<? super T>> list,T key);//二分法搜索list集合中的指定对象
    //替换
    voidfill(List<? super T> list, T obj);//将list集合中的全部元素替换成指定对象obj
    boolean replaceAll(List<T> lsit,T oldVal,T newVal);//用newVal替换集合中的oldVal值
    void swap(Listlist,int i,int j);/在指定列表的指定位置处交换元素
    //排序:
    void shuffle(List<?> list);//使用默认随机源对list集合中的元素进行随机排序
    void sort(Lsit<T> list);//根据自然顺序对list集合中的元素进行排序
    void sort(List<T> lsit,Comparator<? super T> c);//根据指定比较器c的排序方式对list集合进行排序
    //反转
    reverse(List<?> list);//反转list集合中元素的顺序
    Comparator reverseOrder();//返回一个比较器,强行逆转了实现Comparable接口的对象的自然顺序
    Comparator reverseOrder(Comparator<T> cmp);//返回一个比较器,强行逆转了指定比较器的顺序
    //同步的集合
    List<T>  synchronizedList(List<T> list);//返回支持的同步(线程安全的)List集合
    Map<K,V> synchronizedList(Map<K,V> m); //返回支持的同步(线程安全的)Map集合

    13. Arrays

    • Arrays是用于操作数组的工具类。里边的方法也全是静态的。不需要创建对象。
    •  把数组变成List集合的好处:可以使用集合的思想和方法来操作数组中的元素。如:contains,get,indexOf,subList等方法。

    方法:

    Lsit<T>  asList (T... a);//将数组转换为集合,返回一个受指定数组支持的固定大小的列表
    • 将数组转换成集合,不可使用集合的增删方法,因为数组的长度是固定的。如果进行增删操作,则会产生UnsupportedOperationException的编译异常。
    • 如果数组中的元素都是对象,则变成集合时,数组中的元素就直接转为集合中的元素。
    • 如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
    binarySearch()//二分查找方法
    fill()      //替换方法
    sort()   //排序方法等

    集合也可以转换成数组:

    Collection接口中的toArray方法。

            <T> T[]  toArray(T[] a)  //将集合变为指定类型的数组。
    • 指定类型的数组到底要定义多长呢?

            当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。

             当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。

             所以创建一个刚刚好的数组最优。

    • 为什么要将集合变数组?

             为了限定对元素的操作。不需要进行增删了。

    14. 高级for循环:

      for(数据类型变量名 :被遍历的集合(collection)或者数组) {执行语句}

    特点:

    • 对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。可以看作是迭代器的简写形式。
    •   迭代器除了遍历,还可以进行remove集合中元素的动作。如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的操作。
  • 相关阅读:
    [NOIP2011提高组]聪明的质监员
    NOIP 2010 关押罪犯
    题目:埃及分数
    用scanf输入long long 型的数
    poj 1014 Dividing
    Cactus
    SQLite数据库的增删改查代码
    UltraGrid常用方法属性代码
    维护数据表常用SQL语句
    C#备份收藏夹代码
  • 原文地址:https://www.cnblogs.com/tyh2014/p/4257685.html
Copyright © 2011-2022 走看看