Java集合笔记

来源:互联网 发布:java中几个Date的区别 编辑:程序博客网 时间:2024/05/21 17:22

集合框架图


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

数组和集合类同是容器,有何不同?
    数组虽然可以存储对象,但长度是固定的;集合长度是可变的。
    数组中可以存储基本数据类型,集合只能存储对象。

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

为什么会出现这么多的容器呢?
    因为每一个容器对数据的存储方式都有不同。
    这个存储方式称之为:数据结构


一、Colllection  ---  集合类的超级接口

Collection

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

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


基本操作

1.添加
    boolean add(Object); 参数类型是Object,以便于接收任意类型的对象,集合中存储都是对象的引用
    boolean addAll(Collection); //添加一组数据
    注意:
        1)参数类型是Object,以便于接收任意类型的对象
        2)集合中存储都是对象的引用
        
2.获取集合长度,即元素个数
    int size(); 获取数组长度
    
3.删除元素
    boolean remove(Object);
    boolean removeAll(Collection); 删除该集合中包含另一集合中的元素,A-B
    retainAll(Collection);  取交集,保留两个集合共有的元素
    void clear(); 清空集合
    
4.判断元素
    boolean contains(Object);判断是否存在某个元素
    boolean containsAll(Collection);判断是否包含另一集合中的所有元素
    boolean isEmpty(); 判断集合是否为空,实际上是判断集合的size是否为0
    
5. Iterator iterator();
       返回在此 collection 的元素上进行迭代的迭代器
       
6.集合转变成数组
    Object[] toArray();
    T[] toArray(T[]);


二、迭代器----Iterator
    其实就是集合的取出元素的方式
    对于集合的元素取出这个动作:

    当不足以用一个函数来描述,需要用多个功能来体现,所以就将取出这个动作封装成一个对象来描述。就把取出方式定义在集合

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

    而每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都有共性内容判断和取出。那么就可以将这些共性抽取。这些内部类都符合一个规则,该规则就是Iterator。通过一个对外提供的方法 iterator();,可以获取集合的取出对象。


Iterator类的常用操作

    boolean hasNext();判断是否还有元素

    E next();取出元素。

    注意:没有指定泛型的情况下返回的Object对象,必须进行强制类型转换

    void remove();移除元素

    取出元素的时候要注意用hasNext();判断是否还有元素,如果在没有元素的情况下调用next()会抛出没有元素可以迭代的异常----NoSuchElementException。所以在进行迭代操作的时候通常会搭配hasNext()方法来使用


示例代码:

public class CollectionDemo {public static void main(String[] args) {Collection coll = new ArrayList();//添加元素coll.add("hello");coll.add("jei");coll.add("heihei");//迭代输出//方式一Iterator iter = coll.iterator();while(iter.hasNext()){System.out.println("iter:"+iter.next());}//方式二for(Iterator iter2=coll.iterator() ; iter2.hasNext();){if("heihei".equals((String)iter2.next()))//用迭代器删除元素iter2.remove();}System.out.println(coll);}}


三、List集合

List 

    |--ArrayList    底层数据结构用的是数组。特点:查询速度很快,但是增删稍慢。线程不同步
    |--LinkedList  底层数据结构用的是链表结构。特点:增删速度很块,查询稍慢
    |--Vector         底层数据结构是数组。特点:线程同步,但是增删改查速度都相对较慢,被ArrayList替代

注:List中用来判断重复的是equals方法

1.List特有的方法

    凡是可以操作角标的方法都是该体系特有的方法
    
1)增
    add(index,element);指定位置添加元素
    addAll(index,Collection);指定位置添加指定集合中所有元素
    
2
    remove(index);删除指定位置的元素
    
3
    set(index,element);修改指定位置的元素
    
4
    get(index); 获取指定位置的元素
    sublist(fromIndex,toIndex);获取部分元素,包含头,不包含尾
    
5其他方法   
     indexOf(Object);  获取元素第一次出现的位置
     lastIndexOf(Object);  反向索引

     ListIterator listIterator(); 返回List特有的迭代器

     ListIterator listIterator(index); 返回List特有的迭代器,从列表的指定位置开始


2.ListIterator

    ListIteratorList集合特有的迭代器,是Iterator的子接口。

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

ListIterator特有的方法

    add(obj);  在当前元素之后增加一个元素

    set(obj);  将当前元素修改为obj

    hasPrevious();  判断前面有没有元素

    previous();  取前一个元素

    注:Listerator可以双向迭代,但是要先向后迭代,才能向前迭代


3.枚举-----Enumeration
    枚举就是Vector特有的取出方式

    其实枚举和迭代是一样的,因为枚举的名称以及方法都名称都过长,所以被迭代器取代了。

枚举特有方法

    hasMoreElements();   是否还有更多元素

    nextElement();    取下一个元素


示例代码:

        Vector vector = new Vector();            vector.add("java01");        vector.add("java02");        vector.add("java03");        for(Enumeration enumeration = vector.elements();enumeration.hasMoreElements();)            System.out.println("enumeration:"+enumeration.nextElement());

4.LinkedList

LinkedList特有的方法

1)增加
    addFirst();    在集合头部增加元素
    addLast();    在集合尾部增加元素


2)获取   
    getFirst()      获取集合中第一个元素,集合为空时会抛出NoSuchElementException
    getLast();     获取集合中最后一个元素,集合为空时会抛出NoSuchElementException


3)删除
    removeFirst();    移除集合中第一个元素,集合为空时会抛出NoSuchElementException
    removeLast();    移除集合中第一个元素,集合为空时会抛出NoSuchElementException


示例代码:

        LinkedList ll = new LinkedList();               //在集合头部增加元素        ll.addFirst("java01");        ll.addFirst("java02");        ll.addFirst("java03");        System.out.println(ll);        //获取集合中最后一个元素        System.out.println("the last element in LinkedList is :"+ll.getLast());        //删除集合中第一个元素        ll.removeFirst();        System.out.println("after removeFirst:  "+ll);

运行截图:


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

1)增

        offerFirst();

        offerLast();

2)获取

        获取元素,但是不删除。如果集合中没有元素,会返回null

        peekFirst();

        peekLast();

3)删

        获取元素,并删除元素。如果集合中没有元素,会返回null

        pollFirst();

        pollLast();

示例代码:

LinkedList ll = new LinkedList();//在集合尾部增加元素ll.offerLast("java01");ll.offerLast("java02");ll.offerLast("java03");System.out.println(ll);//获取集合中第一个元素System.out.println("the first element in LinkedList is :"+ll.peekFirst());//删除集合中最后一个元素ll.pollLast();System.out.println("after pollLast: ");//链表输出方式while(!ll.isEmpty()){System.out.print(ll.poll()+"\t");

运行截图:

模拟堆栈和队列:

/*使用LinkedList模拟一个堆栈或者队列数据结构堆栈:后进先出, 如同一个杯子队列:先进先出, 如同一个水管 *///队列class Duilie{private LinkedList link;public Duilie(){link = new LinkedList();}public void myAdd(Object obj){link.addLast(obj);}public Object myGet(){Object obj = link.removeFirst();return obj;}public boolean isNull(){return link.isEmpty();}}//堆栈class Stack{private LinkedList link;public Stack(){link = new LinkedList();}public void myAdd(Object obj){link.addLast(obj);}public Object myGet(){Object obj = link.removeLast();return obj;}public boolean isNull(){return link.isEmpty();}}


四、Set

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

Set:元素是无序的(存入和取出第顺序不一定一致),元素不可以重复
    |--HashSet:底层数据结构是哈希表。
    |--TreeSet:

1.HashSet

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

                如果元素的hashCode值相同,才会判断equals是否为true。
                如果元素的哈希值不同,不会调用equals。
                注意:对于判断元素是否存在,以及删除等操作,依赖的是元素的哈希值和equals方法


示例代码:

/*在HashSet中存储自定义对象*/public class SetDemo {public static void main(String[] args) {Set hashSet = new HashSet(); //多态//添加数据hashSet.add(new Person("person01", 18));hashSet.add(new Person("person02", 28));hashSet.add(new Person("person03", 19));hashSet.add(new Person("person02", 28));  //重复元素,添加不进去//输出System.out.println("\n集合中的元素为:");for(Iterator iter = hashSet.iterator(); iter.hasNext();){Person p = (Person)iter.next();System.out.println(p.getName()+"...."+p.getAge());}}}class Person{private String name;private int age;public Person(String name, int age){this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//重写hashCode方法public int hashCode(){System.out.println(this.name+"-----hashCode");return this.name.hashCode() + this.age * 39;}//重写equals方法public boolean equals(Object obj){if(!(obj instanceof Person))return false;Person p = (Person)obj;System.out.println(this.name+"----equals----"+p.getName());if(this.name.equals(p.getName()) && this.age == p.age)return true;return false;}}

运行截图

    从运行结果可以看出,每次添加元素都会调用hashCode方法获取哈希值进行判断,如果哈希值不同就将元素添加进去,如果哈希值相同则继续调用equals方法判断是否是同一个对象,如果是同一个对象则不添加


2.TreeSet

TreeSet:底层的数据结构为二叉树结构(红黑树结构),线程不同步。

                可以对Set集合中的元素进行排序。因为TreeSet类实现了NavigableSet接口,该接口强制让增加到集合中的对象进行了比较,使用元素的自

                然顺序对元素进行排序,元素所在类需要实现Comparable接口并复写compareTo方法,或者根据创建 set 时提供的 Comparator进行排序,

                具体取决于使用的构造方法。

                   java中的很多类都具备比较性,其实就是实现了Comparable接口。

               注意:排序时,当主要条件相同时,可以增加对次要条件的比较。

               对于增加元素、判断元素是否存在,以及删除等操作,依赖的是元素的compareTo方法或者传入的比较器中compare方法的

              返回值,是正整数、负整数或零,则两个对象较大、较小或相同。相等时则不会存入。

二叉树示意图

值得注意的是每增加完一个元素,二叉树都会根据平衡二叉树的原理调整原来得二叉树结构


1.Tree排序的两种方式

     1)第一种排序方式:自然排序

           让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也被称为元素的自然顺序,或者叫做默认顺序。

示例代码:

public class TreeSetDemo {public static void main(String[] args) {Set ts = new TreeSet();//添加元素ts.add(new Person("lili1", 20));ts.add(new Person("lili2", 21));ts.add(new Person("lili3", 22));ts.add(new Person("lili4", 24));ts.add(new Person("lili3", 23));//迭代输出System.out.println("集合内容是:");for(Iterator iter=ts.iterator(); iter.hasNext();)System.out.println(iter.next());}}class Person implements Comparable{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    //重写hashCode方法    public int hashCode(){        System.out.println(this.name+"-----hashCode");        return this.name.hashCode() + this.age * 39;    }    //重写equals方法    public boolean equals(Object obj){        if(!(obj instanceof Person))            return false;        Person p = (Person)obj;        System.out.println(this.name+"----equals----"+p.getName());        if(this.name.equals(p.getName()) && this.age == p.age)            return true;        return false;    }    //覆写Object类的toString方法    public String toString(){        return this.name+"----"+this.age;    }    //覆写Comparable接口中的compareTo方法    public int compareTo(Object o) {        Person p = (Person)o;        System.out.println(this.getName()+"--compare--"+p.getName());        int num = this.getName().compareTo(p.getName());//String实现了Comparable接口,并覆写了compareTo方法,这里直接调用        //如果名字相同则比较年龄        if(num==0){            if(this.age > p.getAge())                return 1;            else if(this.age < p.getAge())                return -1;            else return 0;        }        return num;    }}

运行截图:

由运行结果可知,每次插入元素都会调用compareTo方法进行比较,且会不断的调整二叉树的结构。

    2)第二种排序方式:传入比较器

        当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。

        在集合初始化时,就有了比较方式。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

        比较器构造方式:定义一个类,实现Comparator接口,覆盖compare方法。

        注意:当两种排序都存在时,以比较器为主。

示例代码:

public class TreeSetDemo {public static void main(String[] args) {Set ts = new TreeSet(new MyComparator());  //带比较器的集合//添加元素ts.add(new Person("lili1", 20));ts.add(new Person("lili2", 21));ts.add(new Person("lili3", 22));ts.add(new Person("lili4", 24));ts.add(new Person("lili3", 23));//迭代输出System.out.println("集合内容是:");for(Iterator iter=ts.iterator(); iter.hasNext();)System.out.println(iter.next());}}//自定义比较器class MyComparator implements Comparator{//覆写Comparator接口的compare方法public int compare(Object o1, Object o2) {Person p1 = (Person)o1;Person p2 = (Person)o2;System.out.println(p1.getName()+"--compare--"+p2.getName());int num = p1.getName().compareTo(p2.getName());//姓名相同时调用Integer类实现的compareTo方法if(num==0)return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge())); return num;}}class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    //重写hashCode方法    public int hashCode(){        System.out.println(this.name+"-----hashCode");        return this.name.hashCode() + this.age * 39;    }    //重写equals方法    public boolean equals(Object obj){        if(!(obj instanceof Person))            return false;        Person p = (Person)obj;        System.out.println(this.name+"----equals----"+p.getName());        if(this.name.equals(p.getName()) && this.age == p.age)            return true;        return false;    }    //覆写Object类的toString方法    public String toString(){        return this.name+"----"+this.age;    }}

运行截图:


运行结果和之前的一模一样


五、Map---键值对

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

注意:Hashtable、HasgMap中要保证键的唯一性,则作为键存入到对象必须重写hashCode方法和equals方法

            TreeMap中则实现Comparable接口重写CompareTo方法,或者向TreeMap对象中传入比较器

Map
    |--Hashtable:底层是哈希表数据结构,不可以存入null键和null值。该集合是线程同步的。JDK1.0 效率低。
    |--HashMap:底层是哈希表数据结构,允许使用null值和null键。该集合是不同步的。JDK1.0 效率高。
    |--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
和Set很像。
其实Set底层就是使用了Map集合。
   
1.常用方法
1)添加

    V put(K key, V value);
    注意:如果要放入的key不存在,则返回;如果已经存在,则返回key对应的value,并且将集合中原来得value替换为新的value
    void putAll(Map<? extends k,? extends V> m);

2)删除
    clear();
    remove(Object key);
    
3)判断

    containsKey(Object Key);
    containsValue(Object value);
    isEmpty();

4)获取
    V get(Object key); 通过键获取值
    int size();  获取长度
    Collection<V> values(); 得到值的集合
    Map集合输出的两种方式
    Set<K> keySet();    得到键的Set集合,因为键是不允许重复的,所以这里用的Set集合
    Set<Map.Entry<K,V>> entrySet(); 返回此映射中包含的映射关系的 Set 视图

示例代码:

public class MapDemo {public static void main(String[] args) {Map hashMap = new HashMap();//添加元素hashMap.put("01", "lily01");hashMap.put("02", "lily02");hashMap.put("03", "lily03");hashMap.put("04", "lily04");//键可以取null值hashMap.put(null, "lily");//添加元素,如果出现要添加的键已经存在,那么后添加到值会覆盖原有键对应的值,并且put方法会返回被覆盖的值。System.out.println(hashMap.put("05", "lily05"));System.out.println(hashMap.put("05", "new lily05"));  //一些操作//System.out.println("containsKey:"+hashMap.containsKey("02"));//System.out.println("remove:"+hashMap.remove("02"));//可以通过get方法都返回值来判断一个键是否存在,通过返回null来判断//System.out.println("get:"+hashMap.get("01"));//获取Map集合中所有的值Collection coll = hashMap.values();System.out.println("所有的value:"+coll);System.out.println("hashMap:"+hashMap);  //HashMap内重写了toString方法}}

2.Map集合输出的两种方式
Map集合的取出原理:将map集合转成set集合,再通过迭代器取出。
    1)Set<K> keySet:将map中所有的键存入到Set集合。因为Set具备迭代器。
                          所以可以用迭代方式取出的所有的键,再根据get方法获取每一个键对应的值

示例代码:

public class MapDemo {public static void main(String[] args) {Map hashMap = new HashMap();//添加元素hashMap.put("01", "lily01");hashMap.put("04", "lily02");hashMap.put("03", "lily03");hashMap.put("02", "lily04");//先获取map集合的所有键的set集合,keySet();Set keySet = hashMap.keySet();//有了Set集合,就可以获取其迭代器Iterator iter = keySet.iterator();while(iter.hasNext()){String key = (String)iter.next();//有了键可以通过map集合的get方法获取其对应的值 String value = (String)hashMap.get(key);System.out.println("key:"+key+", value:"+value);}}}
      
    2)Set<Map.Entry<K,V>> entrySet:将map集合中映射放系存入到了set集合中,而这个关系的数据类型就是:Map.Entry

       其实Entry是Map接口中的一个内部接口
       interface Map{
              public static interface Entry{
                  public abstract Object getKey();
                  public abstract Object getValue();
           }
       }

     注:之所以定义在Map接口的内部:①先有Map这个集合,才有映射关系的存在,而且此类关系是集合的内部事务

                                                             ②可以直接访问Map集合中的内部成员


示例代码:

public class MapDemo {public static void main(String[] args) {Map hashMap = new HashMap();//添加元素hashMap.put("01", "lily01");hashMap.put("04", "lily02");hashMap.put("03", "lily03");hashMap.put("02", "lily04");//将Map集合中的映射关系取出,存入到set集合中Set<Map.Entry> entry = hashMap.entrySet();Iterator iter = entry.iterator();while(iter.hasNext()){Map.Entry oo= (Map.Entry)iter.next();String key = (String)oo.getKey();String value = (String)oo.getValue();System.out.println("key"+key+", value:"+value);}}}<span style="font-size:14px;"></span>


3.TreeMap---key排序的Map
实现方式和TreeMap相同,1)key所在类实现Comparable接口重写compareTo方法。2)向TreeMap对象传入构造器

示例代码:


/*每一个学生都有对应的归属地。学生Student,地址String。学生属性:姓名,年龄。注意:姓名年龄相同的视为同一个学生。保证学生的唯一性。两种排序方式,1)按姓名排  2)按年龄排 */public class MapTest {public static void main(String[] args) {Map tm = new TreeMap();//Map tm = new TreeMap(new MyComparator2()); //帶比較器//添加元素tm.put(new Student("lily03", 21), "beijing");tm.put(new Student("lily02", 25), "shanghai");tm.put(new Student("lily04", 29), "wuhan");tm.put(new Student("lily01", 23), "shenzhen");//tm.put(new Student("lily04", 29), "wuhan1");//输出Set keySet = tm.keySet();for(Iterator iter=keySet.iterator(); iter.hasNext();){Student key = (Student)iter.next();String value = (String)tm.get(key);System.out.println(key+"---"+value);}}}//自定义比较器,以年龄为主要比较条件,姓名为次要比较条件class MyComparator2 implements Comparator{//重写compare方法public int compare(Object o1, Object o2) {Student s1 = (Student)o1;Student s2 = (Student)o2;int num = new Integer(s1.getAge()).compareTo(s2.getAge());if(num==0)return s1.getName().compareTo(s2.getName());return num;}}class Student implements Comparable{private String name;private int age;public Student(String name, int age){this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//覆写toString方法public String toString() {return this.name+"::"+this.age;}//覆写hashCode方法public int hashCode() {return this.name.hashCode()+this.age*39;}//覆写equals方法public boolean equals(Object obj) {if(!(obj instanceof Student))throw new ClassCastException("类型不匹配");Student s = (Student)obj;return this.name.equals(s.getName()) && this.age == s.getAge();}//重写compareTo方法,已姓名作为主要条件排序,年龄作为次要条件public int compareTo(Object o) {Student s = (Student)o;int num = this.getName().compareTo(s.getName());if(num==0)return new Integer(this.getAge()).compareTo(s.getAge());return num;}}

运行截图:


4.Map练习
1)“dkjdkjdishkalbkjdbifd"获取该字符串中字符出现的次数,
       希望打印结果:a(1)d(2)...

通过结果发现,每一个字母都有对应的次数
说明字母和次数之间都有映射关系,可以用Map集合来描述


示例代码:

/*1.将字符串变成字符数组2.定义一个map集合,将字母和对应的次数都存进去3.遍历字符数组,如果字母已经存在则次数加1,否则就存入4.将map集合转换成字符串 */public class MapTest2 {public static void main(String[] args) {String str = "alkjkldoskjaljaldjf";System.out.println(getCount(str));}//获取字符串中字母出现次数static String getCount(String str){char[] buf = str.toCharArray();//定义map集合Map<Character, Integer> tm = new TreeMap<Character, Integer>();for(int i=0, count=0; i<buf.length; i++, count=0){//非法字符则不会存入集合if(buf[i]<'a' || buf[i]>'z' || buf[i]<'A' || buf[i]>'Z')continue;Integer value = tm.get(buf[i]);if(value != null)  //字母在集合中存在则次数加1,不然就存入该字母count = value;count++;tm.put(buf[i], count);}//定义一个字符串容器StringBuilder sb = new StringBuilder();//取出集合中的数据,并转换成指定字符串     Set<Map.Entry<Character, Integer>> entrySet = tm.entrySet();for(Iterator<Map.Entry<Character, Integer>> iter=entrySet.iterator(); iter.hasNext();){Map.Entry<Character, Integer> entry = iter.next();sb.append(entry.getKey()+"("+entry.getValue()+")");}return sb.toString();}}

5.Map应用扩展

用Map实现多重映射

/*Map--多重映射学校有预热班和就业班预热班和就业班分别有自己的学生信息 */public class MapTest3 {public static void main(String[] args) {//预热班集合Map<String, String> yure = new HashMap<String, String>();yure.put("01", "lily");yure.put("02", "lily02");//就业班集合Map<String, String> jiuye = new HashMap<String, String>();jiuye.put("01", "coco");jiuye.put("02", "coco02");//学校集合Map<String, Map<String, String>> school = new HashMap<String, Map<String, String>>();//将预热班集合和就业班集合添加到学校集合中school.put("yure", yure);school.put("jiuye", jiuye);//输出所有学生信息Iterator<String> iter = school.keySet().iterator();while(iter.hasNext()){String key = iter.next();//获得班级学生信息集合Map<String, String> ban = school.get(key);//根据传入的班级输出学生信息out(ban);}}//按班级输出学生信息    public static void out(Map<String, String> ban){    Iterator<String> iter = ban.keySet().iterator();    while(iter.hasNext()){    String key = iter.next();    String value = ban.get(key);    System.out.println(key+"::"+value);    }    }}


原创粉丝点击