JAVA复习 集合 Day15+Day16+Linux的学习

14集合

14.1集合框架体系

14.1.1集合的介绍和好处

数组:
长度开始时必须指定,而且一旦指定不能更改
保存的必须为同一类型的元素
使用数组进行增加元素比较麻烦

集合:
可以动态保存任意多个对象,使用比较方便
提供了一系列方便的操作对象方法,add、remove、set、get
使用集合添加删除元素简单

14.1.2集合的框架体系图

单列集合
在这里插入图片描述
双列集合
在这里插入图片描述

14.2Collection

14.2.1Collection接口和常用方法

14.2.1.2特点

collection实现子类可以存放多个元素,每个元素可以是Object
有些Collection的实现类,可以存放重复的元素,有些不可以
Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的

14.2.1.3Collection接口常用方法

add:添加单个元素
remove:删除指定元素
contains:查找元素是否存在
size:获取元素个数
clear:清空
addAll:添加多个元素
containsAll:查找多个元素是否都存在
removeAll:删除多个元素

14.2.1.4Collection接口遍历元素方式,使用Iterator迭代器

Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即返回一个迭代器
Iterator仅用于遍历集合,Iterator本身并不存放对象

Ctrl+J显示快捷键的快捷键

当遍历到最后的时候,如果为空了,还希望再次进行遍历,则需要重置迭代器

public class exe01 {
    public static void main(String[] args) {
        @SuppressWarnings({"all"})
        ArrayList col = new ArrayList();
        col.add(new Book("三国演义","罗贯中",10.1));
        col.add(new Book("小李飞刀","古龙",5.1));
        col.add(new Book("红楼梦","曹雪芹",34.6));
        Iterator iterator =col.iterator();        
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);            
        }       
    }
}

class Book{
    private String name;
    private  String suthor;
    private  double price;

    public Book(String name, String suthor, double price) {
        this.name = name;
        this.suthor = suthor;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", suthor='" + suthor + '\'' +
                ", price=" + price +
                '}';
    }
}
14.2.1.4Collection接口遍历元素方式,for循环增强(大写I)

增强for循环,可以替代iterator迭代器
只能用于遍历集合或数组

for(元素类型  元素名: 集合名或数组名){
    访问元素
}

14.2.2List接口和常用方法

List集合类中元素有序、且可重复
List集合中的每个元素都有其对应的顺序索引,即支持索引
List容器中的元素都对应着一个整形型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
JDK API中List接口实现类
在这里插入图片描述
boolean addAll(int index,Collection else):从index位置开始将else中的所有元素添加进来

Object get(int index):获取指定index位置的元素

int indexOf(Object obj):返回obj在当前集合中末次出现的位置

Object remove(int index):移出指定index位置的元素,并返回此元素

Object set(int index,Object ele):设置指定index位置的元素为ele,相当于替换

List subList(int fromIndex ,int toIndex):返回从fromindex到toIndex位置的子集合

14.2.2.1List的三种遍历方式【ArrayList,LinkList,Vector】

方式一:使用iterator

方式二:使用增强for

方式三:使用普通for

14.2.2.2ArrayList底层结构和源码分析

注意事项:
permits all elements,including null,ArrayList 可以加入null,并且多个
ArrayList是由数组来实现数据存储的
ArrayList 基本等同于Vector,除了ArrayList是线程不安全(执行效率较高),在多线程的情况下,不建议使用ArrayList

底层结构和源码分析
ArrayList中维护了一个Object类型的数组elementDate
transient Object[] elementDate//transient 表示该属性不会被序列化

当创建ArrayList对象时,如果使用的是无参构造器,则初始elementDate容量为0,第一次添加,则扩容elementDate为10,如需要再次扩容,则elementDate扩容到1.5倍

如果使用的是指定大小的构造器,则初始elementDate容量为指定大小,如果需要扩容,则直接扩容elementDate为1.5倍

使用无参构造器的扩容机制

一、创建了一个空的数组

二、执行list.add;先确定是否要扩容;然后再执行赋值

三、第一次扩容为10

四、用一个值记录集合被修改的次数;如果elementData的大小不够,就调用grow()去扩容

五、在进行真正的扩容之前,使用扩容机制来确定要扩容到多大,第一次容量为10,第二次及其以后按照1.5e倍扩容

14.2.2.3Vector底层结构和源码分析

Vector底层也是一个对象数组 ,protected Object[] elementDate;
Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized
在开发的过程中,需要线程同步安全时,考虑使用Vector

在这里插入图片描述
利用工具进行源码分析和阅读

14.2.2.4LinkedList底层结构和源码分析

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

1、LinkedList底层维护了一个双向链表
2、LinkedList中维护了两个属性first和last分别指向首节点和尾节点
3、每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个结点,最终实现双向链表
4、所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高
在这里插入图片描述

14.2.3Set接口和常用方法

14.2.3.1Set接口的基本介绍

无序的,没有索引(添加的数据和取出的顺序不一致)
但是取出的顺序的顺序是固定的
不允许重复元素,所以最多包含一个null

14.2.3.2Set接口常用方法

和List接口一样,Set接口也是Collection的子接口,因此常用方法和Collection接口一样

14.2.3.3Set接口的遍历方式

同Collection的遍历方式一样,因为Set接口时Collection接口的子接口
所以可以使用迭代器
增强for
不能使用索引的方式来获取
不能用普通的循环

14.2.3.4HashSet的介绍和底层机制

HashSet实现了Set接口
HashSet实际上是HashMap
可以存放null值,但是只能有一个null
HashSet不保证元素是有序的,(不保证存放元素的顺序和取出的顺序一致)
不能有重复元素/对象当添加相同元素的时候不成功

HashMap底层是数组+链表+红黑树

14.2.3.5HashSet的扩容机制

1、要添加元素的时候,先要得到hash值,会转成索引值
2、找到存储数据表table,看这个索引位置是否已经存放的有元素
3、没有的话直接加入,如果则,调用equals进行比较,如果相同则放弃添加如果不相同,则添加到最后
4、在JAVA8中,如果一条链表的元素个数到达
默认的8,并且table大于等于64则会进行树化

14.2.3.5LinkedHashSet的介绍

LinkedHashSet是HashSet的子类
LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,使得元素看起来是以插入顺序保存的
LinkedHashSet不允许添加重复元素

在这里插入图片描述

14.2.3.5LinkedHashSet的底层源码分析

LinkedHashSet加入顺序和取出元素/数据的顺序一致
LinkedHashSet底层维护的是一个LinkedHashMap(是HashMap的子类)
里面有一个table的表

LinkedHashSet底层结构(数组table+双向链表)

添加第一次时,直接将数组table扩容到16
存放的结点类型是LinkedHashMap$Entry
table数组类型是HashMap$Node[],她存放的元素是LinkedHashMap$Entry类型
//继承关系是在内部类完成的
 static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }
public class exe09 {
    public static void main(String[] args) {
        Set set =new LinkedHashSet();
        set.add(new String("AA"));
        set.add(456);
        set.add(456);
        set.add(new Customer("刘",1001));
        set.add(123);
        set.add("HSp");
        System.out.println("set="+set);
    }
}

class Customer{
    private String name;
    private  int no;

    public Customer(String name, int no) {
        this.name = name;
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }
}

此步骤是在加入set.add(new String(“AA”));查看的
在这里插入图片描述
set.add(456);之后查看的
在这里看的到table中的里面的HashMap$Node[]中有before和after两个,可以看到的是AA的after的指向了456的位置
在这里插入图片描述
源码分析

 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;
    //局部变量
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
        //如果table表为空或者长度为0就进行扩容
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
        //计算hash值看这个位置是否为空,如果等于空,则将其进行添加
    else {
        HashMap.Node<K,V> e; K k;
        if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
            //hash值相同并且满足括号中的一个(要加入的key和之前的结点key是同一个对象或者之前Node的结点key的equals()和准备加入的key比较后相同)就不能加入
        else if (p instanceof TreeNode)
            e = ((HashMap.TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            //如果p的运行类型是红黑树,就需要调用红黑树来添加
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                    //再进行所有的遍历之后没有相同的,将其加入,在这里进行判断看一个链的长度长度是否超过TREEIFY_THRESHOLD - 1,如果超过就进行树化,然后退出循环
                }
                
                if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
                //hash值相同并且满足括号中的一个(要加入的key和之前的结点key是同一个对象或者之前Node的结点key的equals()和准备加入的key比较后相同)就不能加入
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
                //进行替换工作
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;每次增加一个node,就让size加加
    if (++size > threshold)//如果达到临界值就进行扩容
        resize();
    afterNodeInsertion(evict);
    return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值