Java集合框架简介

集合概念

因为数组的大小是固定的,所以设计了集合来满足数组的不足,集合可以随着数据的增大而增大,空间大小是不固定的
集合框架设计满足几个目标

  • 框架必须是高性能的,基本集合的实现必须是高效的
  • 对集合的扩展和适应是简单的

Collection集合

Collection接口的一些常用方法

/* * boolean add(E e) //添加一个元素,List中,可以添加重复元素,总是返回true,Set中,添加重复元素,返回false * void clear() //清空集合 * boolean contain(Object o) //是否包含某元素 * boolean isEmpty() //判断集合是否为空 * boolean remove(Object o) //移除某个元素 * int size(Object o) //返回集合元素个数 * */
public class Demo1_Collection {
    public static void main(String[] args){
        Collection c=new ArrayList();
        c.add("Hi");    //添加元素
        c.add("HelloWorld");
        c.add("Hi");
        System.out.println(c);  //ArrayList的父类的父类重写了toString方法,返回的不是Object的toString类型
        c.remove("Hi"); //移除Hi元素
        System.out.println(c);
// c.clear(); //清空集合
// System.out.println(c);
        System.out.println(c.contains("Hi"));//是否包含HI
        System.out.println(c.size());   //返回元素个数
    }
}

迭代器遍历

/* * 集合中迭代器的简单使用 * */
public class Demo2_Collection_Iterator {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("chengfeilong");
        c.add("chenlixiang");
        c.add("qinhongzhi");
        Iterator it=c.iterator(); //获取迭代器
        while (it.hasNext())
            System.out.println(it.next());
    }
}

List

/* * List接口特有的方法 * void add(int index, E element) * E remove(int index) * E get(int index) * E set(ind index,E element) * */
public class Demo1_List {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
// list.add(1,"e");//在索引为1的位置,插入"e"元素
// list.add(10,"e"); //java.lang.IndexOutOfBoundsException,插入索引位置时,注意索引的大小
        System.out.println(list);

        list.remove(1); //移除索引值位置的元素,返回被删除的元素,删除的时候不会自动装箱
        System.out.println(list);
// System.out.println(list.get(1)); //获取索引值位置的元素,所以可以用此方法遍历集合
// 遍历集合
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        list.set(1,"e"); //修改索引值位置的元素
        System.out.println(list);
    }
}

ArrayList

  • ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。
  • ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
  • ArrayList 实现了RandomAccess 接口, RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持快速随机访问的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
  • ArrayList 实现了Cloneable 接口,即覆盖了函数 clone(),能被克隆
  • ArrayList 实现java.io.Serializable 接口,这意味着ArrayList支持序列化能通过序列化去传输
  • 和 Vector 不同,ArrayList 中的操作不是线程安全的!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者 CopyOnWriteArrayList。

ArrayList实现去重

/* * ArrayList实现集合重复数据的去除 * 思想:创建一个新的集合 * */
public class Demo3_ArrayList {
    public static void main(String[] args) {
        ArrayList list=new ArrayList();
        list.add("a");
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        list.add("c");
        list.add("d");
        ArrayList newList=getSingleList(list);
        System.out.println(newList);

    }
    public static ArrayList getSingleList(ArrayList list) {     //传入旧集合,处理掉重复的元素,组成一个新的集合
        ArrayList newList = new ArrayList();        //新的集合用来存放旧集合里不重复的元素
        Iterator it = list.iterator();      //获取迭代器
        while (it.hasNext())        //判断是否为空
        {
            Object o = it.next();       //取出来元素
            if(!newList.contains(o))    //判断新集合是否包含这个元素
                newList.add(o);         //不包含,就添加到新集合中去
        }
        return newList;     //返回新的集合,此时不包含重复元素
    }
}

ArrayList实现三种遍历方式

/* * 三种迭代的比较 * */
public class Demo5_ThreeIterator {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        arrayList.add("d");
        arrayList.add("e");
        //三种遍历方式
        System.out.println("迭代器遍历");
        Iterator<String> it=arrayList.iterator();//获取迭代器
        while (it.hasNext())
            System.out.print(it.next()+" ");

        System.out.println();
        System.out.println("for循环遍历");
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.print(arrayList.get(i)+" ");
        }
        System.out.println();

        System.out.println("foreach循环遍历");
        for(String s : arrayList)
            System.out.print(s+" ");
    }
}

LinkedList

  • LinkedList是一个实现了List接口Deque接口的双端链表
  • LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性;LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法:

LinkedList特有方法

/* * LinkedList特有功能 * public void addFirst()和addLast() * public E getFirst()和getLast() * public E removeFirst()和removeLast() * public E get(int index)和ArrayList的不一样 * */
public class Demo4_LinkedList {
    public static void main(String[] args) {
        LinkedList linkedList=new LinkedList();
        linkedList.addFirst("a");   //头部添加一个元素
        linkedList.addFirst("b");
        linkedList.addFirst("c");
        linkedList.addFirst("d");
        linkedList.addLast("g");      //尾部添加一个元素

        linkedList.removeFirst();   //删除头部元素
        linkedList.removeLast();    //删除尾部元素
        Object o=linkedList.get(3); //根据索引找到元素
        System.out.println(o);
        System.out.println(linkedList);
    }
}

Vector

  • Java1.0版本中已经存在了,早期的集合工具类,后来被并入到Java集合框架中,逐渐被ArrayList替代
  • 因为是同步的,所以线程安全,不要求线程安全的情况下,建议使用ArrayList代替
/* * 早期Vector类实现集合功能实例 * */
public class Demo2_Vector {
    public static void main(String[] args) {
        Vector v=new Vector();
        v.addElement("a");  //添加元素
        v.addElement("b");
        v.addElement("c");
        v.addElement("d");
        Enumeration en=v.elements();    //获取迭代器
        while (en.hasMoreElements())    //判断是否为空
        {
            System.out.println(en.nextElement());   //输出值
        }

    }
}

Set

HashSet

HashSet如何保证元素唯一的

  • HashCode方法里常量为什么是31?
    • 31是个质数
    • 31这个质数不大也不小
    • 好算,31是2的5次方减1,也就是2左移5位-1
  • equals方法健壮性
  • 我们使用Set集合都是需要去除掉重复元素的,如果在存储的时候逐个equals()比较,效率较低,哈希算法提高了去重复的效率,降低了使用equals()的次数
  • 当HashSet调用add()方法存储对象的时候,先调用对象的hashCode()方法得到一个哈希值,然后集合中查找是否有哈希值相同的对象
    • 如果没有哈希值相同的对象就直接存入集合
    • 如果有哈希值相同的对象,就和哈希值相同的对象逐个进行equals()比较,返回false就存入,true就不存

TreeSet

  • TreeSet是使用二叉树的原理的add()的对象进行按照指定的顺序排序,每增加一个元素,就会排一次序,插入到二叉树指定的位置
  • IntegerString 对象都可以进行默认的 TreeSet 排序,而自定义类的对象是不可以的, 自己定义的类必须实现 Comparable 接口,并且覆盖相应的 compareTo()函数,才可以正常使用
  • 在覆写 compare()函数时,要返回相应的值才能使 TreeSet 按照一定的规则来排序
  • 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数

Map

HashMap

  • HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。
  • HashMap 最多只允许一条记录的键为 null,允许多条记录的值为 null。
  • HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections 的 synchronizedMap 方法使HashMap 具有线程安全的能力,或者使用 ConcurrentHashMap

HashTable

  • 历史遗留类,很多功能跟HashMap类似,不同的是继承自Dictionary类,并且是线程安全的,不过并发性不如ConcurrentHashMap,不建议使用

TreeMap

  • 实现了SortedMap接口,内部可自动排序,默认按键的升序排序
  • 在使用 TreeMap 时,key 必须实现 Comparable 接口或者在构造 TreeMap 传入自定义的Comparator,否则会在运行时抛出 java.lang.ClassCastException 类型的异常。

ConcurrentHashMap

  • 线程安全的高并发HashMap