深入理解Java集合

时间:2021-02-14 19:24:23

Java集合可分为Collection和Map两种体系

  •       Collection接口:Set  元素无序(不等于随机性,真正的无序性,指的是元素在底层存储的位置是无序的)、不可重复的集合;List 元素有序,可重复的集合
  •       Map接口:具有映射关系"Key-Value对"的集合

一、List

     ArrayList和LinkedList的大致区别如下:

  • ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构 
  • 对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针 
  • 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据
  • ArrayList没有实现Queue队列接口,LinkedList实现了Queue接口

创建Person实体类

package com.yyx.test;

/**
 * 实体类 人
 * 
 * @author yyx 2018年6月11日
 */
public class Person {
    private String perName;
    private int perAge;

    public Person() {
        super();
    }

    public Person(String perName, int perAge) {
        super();
        this.perName = perName;
        this.perAge = perAge;
    }

    public String getPerName() {
        return perName;
    }

    public void setPerName(String perName) {
        this.perName = perName;
    }

    public int getPerAge() {
        return perAge;
    }

    public void setPerAge(int perAge) {
        this.perAge = perAge;
    }

    @Override
    public String toString() {
        return "Person [perName=" + perName + ", perAge=" + perAge + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (this.perAge != other.perAge)
            return false;
        if (this.perName == null) {
            if (other.perName != null)
                return false;
        } else if (!this.perName.equals(other.perName))
            return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + this.perAge;
        result = prime * result + ((this.perName == null) ? 0 : this.perName.hashCode());
        return result;
    }
}

    1.ArrayList(主要实现类)

package com.yyx.test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Pratice {
    public static void main(String[] args) {
        List<Person> listPerson = new ArrayList<Person>();
        
        Person perOne = new Person("张三", 22);
        Person perTwo = new Person("李四", 21);
        Person perThree = new Person("王五", 25);
        
        listPerson.add(perOne);
        listPerson.add(perTwo);
        listPerson.add(perThree);
        //遍历方法一
        for (int i = 0; i < listPerson.size(); i++) {
            System.out.println(listPerson.get(i).toString());
        }
        
        listPerson.remove(perOne);
        System.out.println();
        //遍历方法二
        for (Person person : listPerson) {
            System.out.println(person.toString());
        }
        
        listPerson.remove(1);
        System.out.println();
        //遍历方法三
        Iterator<Person> iterator=listPerson.iterator();
        while (iterator.hasNext()) {
            Person person =iterator.next();
            System.out.println(person.toString());
            
        }
    }
} 

    2.LinkedList

package com.yyx.test;

import java.util.Iterator;
import java.util.LinkedList;
/**
 * LinkedList的详细方法参考Api帮助文档
 * @author yyx 2018年6月11日
 */
public class Pratice {
    public static void main(String[] args) {
        LinkedList<Person> listPerson = new LinkedList<Person>();
        
        Person perOne = new Person("张三", 22);
        Person perTwo = new Person("李四", 21);
                
        listPerson.add(perOne);
        listPerson.add(perTwo);
                
        for (Person person : listPerson) {
            System.out.println(person.toString());
        }
        System.out.println();
        
        Person perThree = new Person("王五", 25);
        listPerson.addFirst(perThree);
        for (Person person : listPerson) {
            System.out.println(person.toString());
        }
        System.out.println();
        
        listPerson.removeLast();                        
        //遍历方法三
        Iterator<Person> iterator=listPerson.iterator();
        while (iterator.hasNext()) {
            Person person =iterator.next();
            System.out.println(person.toString());
            
        }
    }
}

    3.Vector

    Vector是线程安全的,影响效率,故此Vector的效率低于ArrayList,Vector类可以实现可增长的对象数组

    Vector与ArrayList的比较

  • Vector是线程安全的集合类,ArrayList并不是线程安全的类。Vector类对集合的元素操作时都加了synchronized,保证线程安全。
  • Vector与ArrayList本质上都是一个Object[] 数组,ArrayList提供了size属性,Vector提供了elementCount属性,他们的作用是记录集合内有效元素的个数。与我们平常调用的arrayList.size()和vector.size()一样返回的集合内有效元素的个数。
  • Vector与ArrayList的扩容并不一样,Vector默认扩容是增长一倍的容量,Arraylist是增长50%的容量。
  • Vector与ArrayList的remove,add(index,obj)方法都会导致内部数组进行数据拷贝的操作,这样在大数据量时,可能会影响效率。
  • Vector与ArrayList的add(obj)方法,如果新增的有效元素个数超过数组本身的长度,都会导致数组进行扩容

二、Set

      Set:存储的元素是无序的,不可重复的!

  • 1.无序性:无序性!= 随机性。真正的无序性,指的是元素在底层存储的位置是无序的
    2.不可重复性:当向Set中添加进相同的元素的时候,后面的这个不能添加进去

    1.HashSet (主要实现类)

package com.yyx.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Pratice {
    public static void main(String[] args) {
        /**
         * 要求添加进Set中的元素所在的类,一定要重写equals()和hashCode()方法。 
         * 进而保证Set中元素的不可重复性
         */
        Set<Person> set = new HashSet<Person>();

        Person p1 = new Person("GG", 23);
        Person p2 = new Person("GG", 23);
        Person p3 = new Person("FF", 22);

        set.add(p1);
        set.add(p2);
        set.add(p3);

        Iterator<Person> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        
        System.out.println(p1.equals(p2));
        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());
        System.out.println(p3.hashCode());
    }
}

    2.TreeSet

  • 向TreeSet中添加的元素必须是同一个类的
  • 可以按照添加进集合中的元素的指定的顺序遍历。像String,包装类等默认按照从小到大的顺序遍历
  • 当向TreeSet中添加自定义类的对象时,有两种排序方法:①自然排序②定制排序
  • 自然排序:要求自定义类实现java.lang.Comparable接口并重写其compareTo(Object obj)的抽象方法在此方法中,指明按照自定义类的哪个属性进行排序
  • 向TreeSet中添加元素时,首先按照compareTo()进行比较,一旦返回0,虽然仅是两个对象的此属性值相同,但是程序会认为这两个对象是相同的,进而后一个对象就不能添加进来

     注意:compareTo()与hashCode()以及equals()三者保持一致!

package com.yyx.test;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/**
 * 
 * @author yyx 2018年6月11日
 */
public class Pratice {
    public static void main(String[] args) {
        Set<Person> set = new TreeSet<Person>();

        set.add(new Person("CC", 23));
        set.add(new Person("MM", 21));
        set.add(new Person("GG", 25));
        set.add(new Person("JJ", 24));
        set.add(new Person("KK", 20));
        set.add(new Person("DD", 20));
        
        /**
         * 当Person类没有实现Comparable接口时,当向TreeSet中添加Person对象时,
         * 报ClassCastException
         */
        Iterator<Person> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }            
    }
}

    TreeSet的定制排序: 见下面的步骤 compare()与hashCode()以及equals()三者保持一致!

package com.yyx.test;
/**
 * 
 * @author yyx 2018年6月12日
 */
public class Customer {
    private String name;
    private Integer id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Customer(String name, Integer id) {
        super();
        this.name = name;
        this.id = id;
    }

    public Customer() {
        super();
    }

    @Override
    public String toString() {
        return "Customer [name=" + name + ", id=" + id + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Customer other = (Customer) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}
package com.yyx.test;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * 
 * @author yyx 2018年6月11日
 */
public class Pratice {
    public static void main(String[] args) {
        // 1.创建一个实现了Comparator接口的类对象
                Comparator com = new Comparator() {
                    // 向TreeSet中添加Customer类的对象,在此compare()方法中,指明是按照Customer
                    // 的哪个属性排序的。
                    @Override
                    public int compare(Object o1, Object o2) {
                        if (o1 instanceof Customer && o2 instanceof Customer) {
                            Customer c1 = (Customer) o1;
                            Customer c2 = (Customer) o2;
                            int i = c1.getId().compareTo(c2.getId());
                            if (i == 0) {
                                return c1.getName().compareTo(c2.getName());
                            }
                            return i;
                        }
                        return 0;
                    }
                };
                // 2.将此对象作为形参传递给TreeSet的构造器中
                TreeSet<Customer> set = new TreeSet<Customer>(com);
                // 3.向TreeSet中添加Comparator接口中的compare方法中涉及的类的对象。
                set.add(new Customer("AA", 1003));
                set.add(new Customer("BB", 1002));
                set.add(new Customer("GG", 1004));
                set.add(new Customer("CC", 1001));
                set.add(new Customer("DD", 1001));

                for (Object str : set) {
                    System.out.println(str);
                }
    }
}

    3.LinkedHashSet

  •      LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
  •      LinkedHashSet 是 HashSet 的子类
  •      LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能
package com.yyx.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 
 * @author yyx 2018年6月11日
 */
public class Pratice {
    public static void main(String[] args) {
        Set<Person> set = new LinkedHashSet<Person>();

        Person p1 = new Person("GG", 23);
        Person p2 = new Person("GG", 23);
        Person p3 = new Person("FF", 22);
        Person p4 = new Person("EE", 22);

        set.add(p3);
        set.add(p1);
        set.add(p2);
        set.add(p4);
        
        Iterator<Person> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        
        System.out.println(p1.equals(p2));
        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());
        System.out.println(p3.hashCode());
    }
}

三、Map

 

  •  Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value
  •      Map 中的 key 和  value 都可以是任何引用类型的数据
  •      Map 中的 key 用Set来存放,不允许重复,即同一个,常用String类作为Map的“键”
  •      key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value

    HashMap(常用类)