[Java基础] 集合(十二)

集合VS数组

数组

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

集合

  • 可以动态保存任意多个对象,使用比较方便
  • 提供一系列方便的操作对象的方法
  • 使用集合进行增加/删除元素比较简洁

框架体系

在这里插入图片描述

在这里插入图片描述

Collection接口

基本介绍

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

迭代器遍历

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

执行原理:

  1. .hasNext(); 判断是否还有下一个元素
  2. .next(); 作用:
    1⃣️指针下移
    2⃣️将下移以后集合位置上的元素返回
  3. 在调用iterator.next(); 方法之前必须调用iterator.hasNext(); 进行检测。若不调用,且下一条记录无效,直接调用iterator.next(); 会抛出

for循环加强

  • 基本语法
for(元素类型 元素名 : 集合名/数组名){
	访问元素
}

代码示例

package Java.Collection;

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

/**
 * @author 鹿青舟
 * @version 1.0
 */
public class CollectionIterator {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {

        Collection col = new ArrayList();
        col.add(new book("西游记", "吴承恩", 13.2));
        col.add(new book("三国演义", "罗贯中", 22.2));
        col.add(new book("红楼梦", "曹雪芹", 33.2));

        Iterator iterator = col.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }

        for (Object book : col) {
            System.out.println(book);
        }


    }
}
class book{
    private String name;
    private String author;
    private double price;
    public book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

List接口

基本介绍

  • List接口是Collection接口的子接口
  • List集合类中元素=有序(即添加顺序和取出顺序一致)、且可重复
  • List集合中的每个元素都有对应的顺序索引,即支持索引
  • List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

常用方法

  • 1⃣️在索引1插入对象
list.add(1"hi");
  • 2⃣️在索引1插入集合2
list.addAll(1,list2);
  • 3⃣️获取索引3的元素
list.get(3);
  • 4⃣️返回"tom"对象第一次出现的索引
list.indexOf("tom");
  • 5⃣️返回"tom"对象最后一次出现的索引
list.lastindexOf("tom");
  • 6⃣️替换索引1对象为"tom"
list.set(1,"tom");
  • 7⃣️移除索引0对象
list.remove(0);

遍历方式

  1. 使用iterator
Iterator iterator = col.iterator();
while (iterator.hasNext()) {
	Object obj = iterator.next();
	System.out.println(obj);
}
  1. 使用增强for
for (Object book : col) {
	System.out.println(book);
}
  1. 使用普通for
for (int i = 0; i < col.size(); i++) {
	Object obj = col.get(i);
	System.out.println(obj);
}

ArrayList

注意示例

  • ArrayList可以加入多个null
  • ArrayList是由数组来实现数据存储的
  • ArrayList基本等同于Vector
  • ArrayList是线程不安全的,没有synchronized,多线程不建议使用

底层源码

  • 1⃣️创建数组

无参构造:
在这里插入图片描述

有参构造:
在这里插入图片描述

  • 2⃣️
    1)确定是否扩容
    2)执行、赋值

在这里插入图片描述

  • 3⃣️
    1)判断是否为空,是则扩容10
    2)确定大小是否够

在这里插入图片描述

  • 4⃣️
    1)记录被修改次数
    2)判断空间是否够,不够则去扩容

在这里插入图片描述

  • 5⃣️
    1)按1.5倍扩容
    2)如果第一次则扩容10
    3)用copyOf()扩容

在这里插入图片描述

Vector

注意示例

  • Vector底层也是一个对象数组
  • Vector是线程安全的,即线程同步,有synchronized,多线程建议使用

比较

分类底层结构版本线程安全/效率扩容倍数
ArrayList可变数组jdk1.2不安全,效率高默认空间10,1.5倍扩容
Vector可变数组jdk1.0安全,效率不高默认空间10,2.0倍扩容

LinkedList

注意示例

  • LinkedList实现了双向链表双端队列的特点
  • LinkedList是线程不安全的,即没有实现同步
  • LinkedList底层维护了一个双向链表,还维护了两个属性firstlast分别指向首节点和尾节点,每个节点(Node)里面还维护了prevnextitem三个属性
  • LinkedList元素的添加和删除,不是通过数组完成的,效率高

比较

分类底层结构增删效率查改效率
ArrayList可变数组较低,数组扩容较高
LinkedList可变数组较高,链表追加较低

Set接口

基本介绍

  • 元素无序(即添加顺序、取出顺序不一致)、不允许重复
  • 没有索引,不能使用索引方式来获取元素

遍历方式

  1. 使用iterator
Iterator iterator = col.iterator();
while (iterator.hasNext()) {
	Object obj = iterator.next();
	System.out.println(obj);
}
  1. 使用增强for
for (Object book : col) {
	System.out.println(book);
}

不能使用普通for循环,不能使用索引

HashSet⚠️‼️‼️⚠️

注意示例

  • HashSet实现了Set接口
  • HashSet实际上是HashMap(HashMap底层:数组+链表+红黑树)
  • 不保证元素有序,不能有重复的元素/对象
  • 取出顺序一旦确定,就不会变化

底层源码

  • 1⃣️add()

在这里插入图片描述

  • 2⃣️put()

在这里插入图片描述

  • 3⃣️putval()

在这里插入图片描述

  • hash()

在这里插入图片描述

  • resize()

在这里插入图片描述
在这里插入图片描述

LinkedHashSet

注意示例

  • 是HashSet的子类,底层是一个LinkedHashMap,底层维护了一个数组+双向链表
  • 不能添加重复元素,且是有序
  • LinkedHashSet中维护了一个hash表和双向链表,还维护了headtail分别指向头节点和尾节点,每个节点有beforeafter属性,形成双向链表
  • 插入顺序和遍历顺序一致,添加时先求哈希值,再求索引

Map接口

基本介绍

  • Map与Collection并列存在,用于保存具有映射关系的数据(key- value双列元素)
  • Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
  • Map中的key不允许重复,当有相同的key,就等价于替换,value可以重复
  • Map中的key、value也可以是null,key为null只能有一个,value为null可以有多个
  • 一般常用String类作为Map中key
  • key和value之间存在单向一对一关系,即通过key找到对应的value

注意示例

  • key-value最后是HashMap$Node
node = newNode(hash,key,value,null);
  • key-value为了方便程序员的遍历,创建了EntrySet集合,存放的元素类型Entry,Entry对象有key-value
  • Map.EntrySet中定义的类型是Map.Entry,但实际上存放的是HashMap$Node
static class Node<K,V> implements Map.Entry<K,V>
  • 当把HashMap$Node对象存放到EntrySet方便遍历,因为Map.Entry提供了getKeygetValue
for(Object obj : map.entrySet()){
	Map.Entry entry = (Map.Entry) obj;
}

在这里插入图片描述

Map体系

在这里插入图片描述

常用方法

  • 添加
map.put("No1",1);
  • 根据键删除映射关系
map.remove("No1");
  • 根据键获取值
map.get("No1");
  • 获取元素个数
map.size();
  • 判断个数是否为0
map.isEmpty();
  • 清除key-value
map.clear();
  • 查看键是否存在
map.containskey("No1");

遍历方式

  1. 根据KeySet
        //1⃣️
        System.out.println("------1------");
        for (Object key : map.keySet()) {
            System.out.println(key + "-" + map.get(key));
        }

        System.out.println("------1-2------");
        Iterator iteratorKey = map.keySet().iterator();
        while (iteratorKey.hasNext()) {
            Object next =  iteratorKey.next();
            System.out.println(next + "-" + map.get(next));
        }
  1. 根据Values
        //2⃣️
        System.out.println("------2------");
        for (Object value : map.values()) {
            System.out.println(value);
        }

        System.out.println("------2-2------");
        Iterator iteratorVal = map.values().iterator();
        while (iteratorVal.hasNext()) {
            Object next =  iteratorVal.next();
            System.out.println(next);
        }
  1. 根据entrySet
        //3⃣️
        System.out.println("------3------");
        for (Object enterSet : map.entrySet()) {
            Map.Entry entry = (Map.Entry) enterSet;
            System.out.println(entry);
        }

        System.out.println("------3-2------");
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
//            System.out.println(next.getClass());
        }

HashMap

注意示例

  • Map接口的常用实现类:HashMap(使用最多)、Hashtable、Properties
  • HashMap是线程不安全的,即线程不同步,方法没有做同步互斥的操作,没有synchronized
  • jdk7的HashMap底层:数组+链表
  • jdk8的HashMap底层:数组+链表+红黑树

扩容机制

  • 第一次添加,扩容table容量为16,临界值(threshold)为12,加载因子(loadfactor)为0.75
  • 再Java8中,如果一条链表的元素个数为超过TREEIFY_THRESHOLD(默认8),并且table大小 >= MIN_TREEIFY_CAPACITY(默认64)就会进行树化
  • 元素个数到8,table是16,继续向链表添加,table扩容——不树化
  • 元素个数到9,table是32,继续向链表添加,table扩容——不树化
  • 元素个数到10,table是64,继续添加——树化

底层源码

  1. 执行构造器new HashMap();初始化加载因子 loadfactor = 0.75
HashMap$Node[] table = null;
  1. 执行put,分别调用hash.putVal方法
public V put(K key , V value){
	return putVal(hash(key), key, value, false, true)
}
  1. 执行putVal,若空间不足,执行resize

Hashtable

注意示例

  • Hashtable的键和值都不能为null,否则会抛出NullPointerException
  • Hashtable是线程安全

扩容机制

  • 底层有数组Hashtable$Entry[] ;初始化大小为11,加载因子0.75
  • 将key-value封装到Entry
addEntry(hash,key,value,index)
  • 按(*2倍 + 1)扩容
int newCapacity = (oldCapacity << 1) + 1;

比较

分类版本线程安全效率键值对
HashMapjdk1.2不安全效率高允许null键值
Hashtablejdk1.0安全效率较低不允许null键值
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你怎么知道我头发乌黑浓密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值