Java中的集合框架

集合

概念:当我们需要对数据进行保存时,数据的类型可能多种多样,于是就有了数据结构,在java中对数据结构的实现就是我们的集合

1.可以动态保存多个对象,使用方便

2.提供一些方便操作的方法,增加,删除,查找

集合API

集合体系概述:Java集合框架是由一些接口,抽象类和具体类组成的,都位于Java.util包中

Java中的集合框架

 

Collection接口

在Collection接口中定义了一些集合共有的方法

下面是用代码进行总结的这些方法

    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        Collection<String> co = new ArrayList<String>();
        c.add("asd");//增加单个元素
        c.add("b");
        c.add("c");
        //c.clear();//全部删除
        System.out.println(c.remove("b"));//删除指定元素,返回值为boolean类型
        System.out.println(c.contains("a"));//查找指定元素,返回值为bolean类型
        System.out.println(c.size());//长度
        System.out.println(c.isEmpty());//判断是否为空
        co.add("zxc");
        co.add("c");
        c.addAll(co);//将co中所有元素加到c中
        System.out.println(c);
        //c.removeAll(co);
        //System.out.println(c);//删除指定集合,不包含时删除共有元素
        System.out.println(c.containsAll(co));//查找指定集合,返回值为bolean类型
    }

List集合

1.List接口中元素有序(添加顺序和取出顺序一致)且可重复

2.List接口中每个元素都有其对应的顺序索引

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("e");
        list.add("a");
        list.add(0, "z");//在指定位置添加元素
        System.out.println(list.get(2));//获取指定位置的元素
        System.out.println(list.indexOf("a"));//返回指定元素在集合中首次出现的位置
        System.out.println(list.lastIndexOf("a"));//返回指定元素最后一次出现在集合中的位置
        list.set(0, "x");//将指定位置上元素进行替换
        System.out.println(list);
        list.remove(0);//删除指定位置上的元素
        System.out.println(list);
        System.out.println(list.subList(0, 4));//截取指定区间的元素,左闭右开
​
    }

List三种遍历方式:

for循环:

  
  public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        arrayList.add("d");
        arrayList.add("e");
        arrayList.add("a");
        arrayList.add("b");
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }
    }
}

增强for:

    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");
        arrayList.add("a");
        arrayList.add("b");
        for(String item : arrayList){
            System.out.println(item);
        }
    }

Iterator迭代:

    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");
        arrayList.add("a");
        arrayList.add("b");
        System.out.println(arrayList);
        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()){
            Object next = iterator.next();
            System.out.println(next);
        }
    }

ArrayList实现类

arrayList底层原理是数组,是线程不安全的,但效率高

扩容机制:当创建一个ArrayList对象时,若使用无参构造时,当添加第一个元素时,将自动扩容为10,如果不能满足时,则会在当前容量下扩容1.5倍;若使用无参构造时,开始给定一定的容量的话,在容量不能满足的情况下,就会在当前容量的基础上扩容1.5倍

LinkedList实现类

LinkedList底层实现了双向链表和双端队列的特点,可以添加任意元素,可包括null,线程不安全没有实现同步

Vector实现类

Vector底层也是对象数组,是线程同步的,也就是线程安全的,但效率不高因为带有synchronized,在开发过程中,考虑到线程安全时,考虑使用Vector

扩容机制:如果是无参构造时,默认为10,满后则按当前容量的2倍进行扩容;若果是有参构造,指定大小,每次直接按2倍进行扩容

Set接口

Set中所存储的元素是不能重复的,最多包含一个null

Set中元素是无序的,取出和添加的顺序是不一致的,没有索引

Set接口中的一些方法:由于Set接口继承了Collection接口,所以常用方法和Collection接口中的一样

Set接口的遍历方式与Collection接口中的遍历也是一样的可以通过,增强for,迭代器,但是不能用索引来获取

HashSet

HashSet实现了Set接口,实际上是HashMap

可以存放null值,但只有一个,元素无序,取决于hash后再决定索引

TreeSet

当使用无参构造器创建TreeSet对象时,他仍然是无序的

当使用它的有参构造器时(Comparator),可以指定排序规则

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet();
        treeSet.add(new Student("小明", 12458));
        treeSet.add(new Student("小红", 12465));
        treeSet.add(new Student("小白", 12452));
        treeSet.add(new Student("小黑", 12450));
        treeSet.add(new Student("小明", 12451));
        System.out.println(treeSet);
    }
}
​
​
class Student implements Comparable<Student>{
    private String name;
    private int id;
​
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
​
    @Override
    public int compareTo(Student o) {
        //return this.name.compareTo(o.name);
        return this.id-o.id;
    }
}

Map接口

Map接口与Collection接口并列存在是双列的就有一对键值对(K-V)

Map 中的Key是不可以重复的,Value可以重复.其中Key可以为null,但只能有一个,而Value也可以为null,但是可以有多个

常用String作为Map中的"Key"

Key和Value之间存在单向一对一关系,通过Key可以找到对应的Value

常用方法:

    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put(10, "zz");//添加元素
        map.put(15, "bb");
        map.put(6, "kk");
        map.put(23, "oo");
        map.put(10, "zzzz");
        System.out.println(map.isEmpty());//判断是否为空
        System.out.println(map.remove(6));//删除指定的键,返回对应的值
        System.out.println(map.size());//返回键值对数量
        System.out.println(map.containsKey(15));//查找指定键是否存在
        System.out.println(map.containsValue("bb"));//查找指定值
        System.out.println(map.get(23));//获取指定键对应的值
        System.out.println(map.hashCode());
        map.replace(23, "ttt");//替换指定键所对应的值
        System.out.println(map);
    }

HashMap,TreeMap,Hashtable都实现Map接口

HashMap TreeMap Hashtable
为null的键 可以存储一个 不能
排序 无序 实现Comparable接口 无序
线程安全 不安全 安全

ArrayList添加元素的过程及扩容机制

ArrayList是List接口的一个实现类,他是一个根据需求而动态增长的数组.在Java中数组的标准长度是在创建时就定义好的,一旦给定就无法更改,有时我们需要一些动态的数组来存储数据,此时就可以使用ArrayList,但他的线程不是安全的,它的存储是通过添加的顺序进行存放数据

ArrayList扩容是在调用add()方法时,调用ensureCapacityInternal()来扩容的,通过判断是否需要扩容,扩容的话调用扩容的关键方法是grow()方法,空间扩至原来的1.5倍

我们可以看出其实就是通过判断新的数组的size,然后将原来的数组复制到新的数组中去

HashMap的底层实现原理

HashMap是使用默认长度为16数组加链表的形式存储的,每个数组中存储着链表

使用put方法添加元素时,首先会调用HashCoede方法,判断其哈希值,然后经过特定运算取余,得到在数组中的索引,如果索引位置尚未有元素存储,则直接存储,若有元素,然后通过equals方法进行比较,若Key值相同,则保留原有的值,若Key值不同,则就此链表继续向下进行比较,直到最后一个元素也不相同,然后将此元素插入.

数组的扩容机制是扩大到原来的二倍

当一个位置上出现八个元素时,就会认为Hash函数设计不好,且数组长度大于64,就会自动转换为红黑树,提高性能

Hashtable扩容机制

底层有数组Hashtable$Entry[],初始化大小为11,当达到它的临界值也就是11*0.75就会进行扩容,按照当前容量的2倍+1进行扩容

ArrayList和LinkedList的区别

ArrayList LinkedList
存储 底层以数组来实现 基于双向链表存储
占用内存大小 占内存大 占内存小
访问效率
理论上在非首位上插入和删除

总体上来说想要查询元素就使用ArrayList想要删除,插入快就选择LinkedList

上一篇:Java-Work10-泛型(2)


下一篇:HashSet、LinkedHashSet以及TreeSet存储自定义对象