集合源码分析与List操作 与Set集合

 

ArrayList, LinkedList,Vector 三者的异同点

同 : 三个类都实现了List 接口 存储数据的特点相同: 存储有序 可重复

不同 :  ArrayList 作为List的主要实现,线程不安全,效率高, 底层使用Object [] 存储
        LinkedList 对于频繁的使用插入, 删除操作效率比ArrayList效率高 底层使用双向链表存储

        Vector 线程安全 效率低 底层使用Object[] elementData存储\

 

 

ArrayList源码分析

        ArrayList list = new ArrayList(10);  // 底层创建了长度是10的Object[]数组 elementDate
        list.add(123);  ---> elementData[0] = new Integer(123);
        ...
        list.add();  // 如果此次的添加导致底层的elementData数组容量不够,则扩容,默认情况下扩容为原来的1.5倍
                        同时需要将原有数组中的数据复制到新的数组中

        建议开发中使用带参的构造器 :ArrayList list = new ArrayList(int capacity)


        ArrayList() jdk1.8 源码分析

        ArrayList list =  new ArrayList(10)  elementData 初始化为{}并没有创建底层为10 的数组
        list.add(123); 第一次调用add添加操作的时候才创建底层为10 的数组并添加数据

        扩容的机制和jdk7的相同

        小结: jdk7的ArrayList的对象创建相当于单例模式的饿汉式, jdk8的ArrayList的对象创建相当于单例模式的懒汉式

 

 

LinkedList源码分析

    LinkedList 源码分析
        LinkedList list = new LinkedList()内部声明了Node的类型first和last属性,默认值为null
        list.add(123)// 将123 封装到Node中 创建了Node对象  其中Node就是双向链表的体现

 

 

 

ArrayList基于Collection自行添加的方法

       /*
        ArraylList   方法

        增: add(Object obj)
        删: remove(int index) / remove(Object obj)
        改 : set(int index, Object obj)
        查: get(int index)
        插: add(int index, Object obj)
        长度: size()
        遍历: 1: Iterator 迭代器
              2: for循环
        */

 

List除了从Collection集合继承的方法外,List 集合里添加了一些根据索引来 操作集合元素的方法。
void add(int index, Object ele):在index位置插入ele元素
boolean addAll(int index, Collection eles):从index位置开始将eles中
的所有元素添加进来
Object get(int index):获取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出现的位置
int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 
Object remove(int index):移除指定index位置的元素,并返回此元素
Object set(int index, Object ele):设置指定index位置的元素为ele
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex 位置的子集合

 

 set(int index,oldValue);修改index下标的内容为oldValue

        System.out.println(list);  // [1, 0, 1, 3, 4, 5, 6, 7, 8]
        list.set(7,"老王");  // 修改下标为7的内容为老王
        System.out.println(list);  // [1, 0, 1, 3, 4, 5, 6, 老王, 8]

 

get(int index);根据下标获取内容,获取index下标的内容

        System.out.println(list);  // [1, 0, 1, 3, 4, 5, 6, 7, 8]
        System.out.println(list.get(2)); // 1

 

 

 

 

Set

HashSet 是Set的主要实现类 线程不安全可以存储null值
    |---- LinkedHashSet 作为HashSet的子类遍历其内部数据结构时可以按照添加顺序遍历
TreeSet 可以按照添加对象的指定属性 进行排序


Set接口中没有添加新的方法 都是使用Collection中的方法

1: 无序性: 不等于随机性 存储的数据再底层中并非按照数组索引的顺序添加,而是根据数据的哈希值来的
2: 不可重复性 :保证添加的元素按照equals()判断时,不能反回true, 即相同的元素只能添加一个

添加元素的过程:


        我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种蒜放计算出
        在HashSet底层数组中存放的位置(即为: 索引位置),判断数组此位置上是否已经有其他元素
            如果位置上没有其他元素,则把元素a添加到此位置,元素a添加成功 ---->情况1
            如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的哈希值
            如果hash值不同元素a添加成功 ---- > 情况2
            如果hash值相同,进而需要田勇元素a所在类的equals()方法:
            equals()返回true,元素a添加失败,
            equals()返回false,元素a添加成功 --- > 情况3


       对于添加成功的情况2 和3 而言,元素a与已经存在指定索引位置上的数据以链表的形式存储
       jdk7: 元素a放在的数组中,指向原来的元素
       jdk8: 原来的元素在数组中指向元素a

 

 

set 要求:

1: 向set中添加的数据,其所在的类一定要重写hashCode()和equals()方法
2: 重写的hashCode()和equals()尽可能保持一致性, 相等的对象必须具有相等的散列码

 

LinkedHashSet() 的使用

LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前和数据后一个数据

优点: 对于频繁的遍历操作, LinkedHashSet的效率高于HashSet

 

 

TreeSet 中添加的数据, 要求是相同类的对象

 

两种排序方式, 自然排序和Comparable接口和Comparator接口

 

TreeSet中添加元素必须是同一类型的  否则会报错 

        // TreeSet中添加的元素必须是同一种类型
        TreeSet set = new TreeSet();
        set.add(123);
        set.add(456);
//        set.add("AA"); // 报错 因为类型不一致
        System.out.println(set.size());


        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }P

 

 Practice

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Integer(1));
        list.add(new Integer(2));
        list.add(new Integer(2));
        list.add(new Integer(4));
        list.add(new Integer(4));
        List listOne = dumpList(list);
        for (Object integer:listOne
             ) {
            System.out.println(integer);
        }
    }

    public static List dumpList(List list){
        HashSet set = new HashSet();
        set.addAll(list);
        return new ArrayList(set);
    }
在List内去除重复数字值,要求尽量简单

 

 

 

 

 

 

.

posted @ 2020-01-18 22:07  可爱的红领巾  阅读(225)  评论(0编辑  收藏  举报