JAVA集合知识总结

集合

什么是集合

数组也算一个集合 集合实际上就是一个容器 可以容纳其他类型的数据 在实际开发种 Java程序会将多条数据封装成多个对象 然后把多个对象放到一个集合中 将集合传到前端 然后遍历集合

注意:

集合不能直接存储基本数据类型 也不能直接存储java对象 集合当中存储的都是java对象的的内存地址 集合在Java种本身是一个容器 一个对象 在java中每一个不同的集合 底层会对应不同的数据结构 往不同的集合种存储元素 等于将数据放到了不同的数据结构中

集合的分类

1. Collection类

存储方式:单个方式存储元素

包:java.util.Collection

存放元素要求:

没有使用泛型之前 可以存放object所有子类型 使用了泛型后 只能存储某个具体类型

工具类:

java.util.Collection 集合接口 java.util.Collections 集合工具类 Collections.synchronized() 变成线程安全

Collections.sort(); 给List集合排序,要求集合中的元素实现了Comparable接口 如果想给set集合排序 可以把set转成List List<> list = new ArrarList<>(set) 不想实现Comparable接口可以用:Collections.sort(List,比较器接口);

1.1 接口常用方法

1、添加 Boolean add(E e):在集合中添加一个对象,如果添加成功,返回true,如果失败,返回false

Boolean addAll(Collection<?extend E> e):在集合中添加另一个集合,成功true,失败false;

2、删除 Boolean remove(object obj):删除一个对象,会改变集合的长度

Boolean removeAll(Colleciton con);删除一个集合,还有两个集合中相同的元素

void clear():删除所有

3、判断 Boolean contains(object obj):在集合中是否包含指定的对象

Boolean containsAll(Collection con):在集合是否包含另一个集合

Boolean isEmpty( ):判断集合是否为空

4、获取 int size( ):得到集合的尺寸大小 数组:length 字符串:length( ); 5、交集 boolean retainAll(Collection c):返回两个集合的交集元素,删除其他元素,功能和removeAll相反。 有A,B两个集合,做完交集后,A集合中的元素发生变化,取得是A和B相同的元素,B不变化。 boolean值的问题-------->只要A集合变化,那么返回true.否则false

6、集合转数组 Object[ ] toArray():把集合转换成对象。

7.迭代器: 注意:迭代器第一次不是指向第一个元素,是指向第一个前面的位置 boolean hasNext(); 如果仍有元素可以迭代 返回true Object next(); 返回迭代的下一个元素

    c.add("abc");
    c.add("def");
    c.add(100);
    c.add(new Object());
    Iterator it = c.iterator();  //获取迭代器
​
    while(it.hasNext()){
        Object obj = it.next(); // 取元素,且返回的元素类型是object
        System.out.println(obj);

注意:

集合结构只要发生改变 迭代器必须重新获取,比如删除元素之后集合结构发生改变,应该重新获取迭代器 原因: 获取迭代器对象 迭代器来遍历集合 此时相当于对当前集合的状态拍了一个快照 迭代器迭代的时候会参照这个快照进行迭代 而直接通过集合去删除元素 没有通知迭代器 会导致迭代器的快照和原集合状态不同

迭代器删除元素:

使用迭代器删除元素 it.remove(); 此时会删除迭代器中的元素 不会产生和快照参照时不同的情况

注意: 放在集合里的元素需要重写equals方法,因为object的equals方法比较的是内存地址

1.2 List

List集合存储元素特点:有序可重复,存储元素有下标。即存进去的顺序和取出来的顺序是一样的,有序是因为list集合都有下标

实现类:

ArrayList:采用数组的数据结构,是非线程安全的 LinkedList:采用双向链表数据结构 Vector:采用数组的数据结构,是线程安全的,所有的方法都有synchronized关键字修饰,所以线程安全,但效率低,所以使用较少

常用方法:

List接口继承Collection List特有方法: add(下标,元素); 在指定位置添加元素 add(元素); 向集合末尾添加元素 get(下标); 根据下标提取元素 indexof(元素); 获取指定元素第一次出现的索引 lastindexof(元素); 获取指定元素最后一次出现的索引 remove(下标) 删除指定下标的元素 set(下标 新元素); 修改指定位置的元素值

1.2.1 ArrayList

初始化容量:10

指定初始化容量 List mylist=new ArrayList(容量大小值);

集合底层:Object类型的数组、

底层先创建了一个长度为0的数组 当添加第一个元素时 初始化容量为10 集合扩容:原容量的1.5倍 ​ 建议给定一个预估计的初始化容量,减少数组的扩容次数,这是ArrayList集合比较重要的优化策略

">>":表示二进制右移一位 集合优点:

检索效率高,因为每个元素占用空间大小相同,内存地址是连续的,知道首元素的内存地址和下标,通过数学表达式计算出元素的内存地址所以检索效率高

这个集合用的最多

集合缺点:

随机增删元素效率低 但向数组末尾添加元素效率高,不受影响

数组无法存储大数据量 因为很难找到一块很大的内存空间

构造方法: Collection c = new HashSet(); List mylist = new ArrayList(c); 通过这个构造方法可以将HashSet集合转换成List集合

添加元素:

list.add();

取出元素:

list.get(下标);

遍历方式:

  1. 通过下标遍历

  2. 迭代器遍历

    Iterator<String> it = list.iterator();
    while(it.hasnext()){
        System.out.println(it.next());
    }
  3. for增强

1.2.2 LinkedList

LinkedList没有初始化容量 最初这个链表中没有任何元素 first和last都是null

构造方法:

Link list = new LinkedLink(); 基本单元是节点Node

增加、取出、遍历和ArrayList一样

链表的优点: 由于链表上的元素在空间存储上内存地址不连续 所以随机增删元素的时候不会有大量元素位移 因此随即增删 效率较高 在以后的开发中 如果遇到随即增删集合中元素的业务比较多时 使用LinkedList

链表的缺点: 不能通过数学表达式计算被查找元素的内存地址 每一次查找都是从头节点开始遍历 所以LinkedList集合检索 的效率较低

总结: 检索用ArrayList

随即增删用LinkedList ​ 注意:

ArrayList之所以检索效率较高,不是单纯因为下标的原因,是因为底层数组发挥的作用 ​ LinkedList集合照样有下标 但是检索某个元素的时候效率比较低 因为只能从头节点开始一个一个遍历

单向链表:

对于链表数据结构 基本单元是节点Node 对于单链表数据结构 每个节点Node都有两个属性:1.存储的数据 2. 是下一个节点的内存地址

优点:随机增删元素效率高 因为增删元素不涉及到大量元素位移

缺点:查询效率较低 每一次查找某个元素的时候都需要从头节点开始往下遍历

双向链表

有下一个节点和上一个节点的内存地址

public class Node{ Node pre; Object data; Node next; } ​

1.2.3 Vector

底层:数组

初始化容量:10

扩容:是原容量的2倍

特点:所有方法都是线程同步的 都有synchronized关键字 线程安全效率低 使用较少

ArrayList线程不安全转线程安全:

List my = new ArrayList(); ​ Collections.synchronizedList(my);

1.3 Set

Set集合存储元素特点:无序不可重复,存储元素没有下标。

SortedSet集合存储元素特点:由于继承了Set集合 所以无序不可重复 但是放在SortedSet集合中的元素可以自动排序,称为可排序集合 SortedMap集合的key存储元素特点:无序不可重复 放在SortedMap集合key部分的元素会自动按照大小顺序排序 称为可排序集合

实现类:

HashSet:底层是创建了HashMap集合对象,向HashSet集合中存储元素实际上存到了HashMap中 HashMap集合是一个哈希表数据结构 TreeSet:底层是创建了TreeMap集合对象,向TreeSet集合中存储元素实际上存到了TreeMap中 TreeMap集合是一个二叉树数据结构

1.3.1 HashSet

特点:无序不可重复

注意:

当向集合中添加的是自定义类型时,自定义类需要同时重写hashcode()和equals()方法

创建:

HashSet<String> set = new HashSet<>();

添加

set.add("abc");

取出:

没有下标不能通过下标取

遍历:

迭代器

Iterator<String> it = list.iterator();
while(it.hasnext()){
    System.out.println(it.next());
}

for增强

for(String s:set){
    System.out.println(s);
}

1.3.2 TreeSet

可以排序

自定义类型需要重写CompareTo方法,或者实现比较器Comparator(建议使用匿名内部类的方式)

CompareTo方法:

package game;
​
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
​
public class Treemap {
    public static void main(String[] args) {
        TreeMap<Integer,String> t = new TreeMap<>();
        t.put(1,"ll");
        t.put(6,"yy");
        t.put(4,"gg");
        Set<Map.Entry<Integer,String>> nodes = t.entrySet();
        for(Map.Entry<Integer,String> node:nodes){
            System.out.println(node.getKey()+"="+node.getValue());
        }
    }
}
​
class A implements Comparable<A>{
    int i;
    public A(int i){
        this.i = i;
    }
    @Override
    public String toString() {
        return "A{}";
    }
    @Override
    public int compareTo(A o) {
        return this.i-o.i;
    }
}

实现比较器Comparator:

package game;
​
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
​
public class Treemap {
    public static void main(String[] args) {
​
        TreeMap<Integer,String> t = new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2;
            }
        });
        t.put(1,"ll");
        t.put(6,"yy");
        t.put(4,"gg");
        Set<Map.Entry<Integer,String>> nodes = t.entrySet();
        for(Map.Entry<Integer,String> node:nodes){
            System.out.println(node.getKey()+"="+node.getValue());
        }
​
    }
}

创建:

TreeSet<Integer> t = new TreeSet<>();

添加元素:

t.add(1);

遍历:

Iterator<Integer> it = t.iterator();
while(it.hasnext()){
    System.out.println(it.next());
}

2. Map类

Map集合和Collection集合没有关系 Map集合以key-value这种键值对的方式存储元素 key和value都是存储java对象的内存地址 所有Map集合的key都是无需不可重复的

常用方法:

put(key,value); 向Map集合中添加键值对 remove(key) 根据key删除键值对 size() 获取集合中键值对的个数 values() 获取集合中所有的value返回一个Collection Set<Map.Entry<K,V>> entrySet() 将Map集合转为Set集合 Set<Map.Entry<K,V>> set = mymap.entrySet(); 注意:转换后Set集合中元素的类型是 Map.Entry<K,V>,是一种静态内部类 keySet() 获取Map集合中所有的key,所有的key是一个集合 isEmpty() 判断集合中元素个数是否为0 containsValue(value) 判断是否包含某个value containsKey(key) 判断是否包含某个key clear() 清空集合 get(key) 通过key获取value

遍历:

  1. 获取所有的key 遍历key来遍历value

  2. foreach

  3. 用Set<Map.Entry<K,V>> entrySet()

Hash表:

哈希表是一个数组和单向链表的结合体 随即增删 查询效率都很高 ,增删是在数组上完成的 查询只需要部分扫描

2.1 HashMap

创建Map集合对象: Map<Integer,String> map = new HashMap<>();

HashMap集合底层:哈希表数据结构,是非线程安全的。

在JDK8之后,如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构。当红黑树上的结点数量小于6时,会重新把红黑树变成单向链表数据结构。这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围、提高效率。

HashMap集合key的特点:

key可以为null,但是对应的value只能有一个,value也可以为null

同一个单向链表上所有节点的hash值相同因为数组下标一样,但同一个链表上k和k的equals方法肯定返回的是false

无序是因为 不一定挂在哪个单向链表上;

不可重复是因为equals方法 如果key重复value会覆盖

放在HashMap中key部分的元素其实就是放到HashSet集合中,所以HashSet集合中的元素也需要同时重写hashcode()和equals()方法;alt+insert 可以同时生成hashcode()和equals()方法

容量:

HashMap集合的默认初始化容量是16

默认加载因子是0.75,也就是说当底层数组容量达到75%时,数组开始扩容,扩容后的容量是原来的2倍 ​ HashMap集合初始化容量必须是2的倍数,是为了达到散列均匀,为了提高HashMap集合的存取效率

哈希表使用不当:

假设将所有的hashcode()方法返回值固定为某个值 那么会导致底层哈希表变成了纯单向链表,这种情况称为散列分布不均匀

假设将所有的hashcode()方法返回值都设定为不一样的值,会导致底层哈希表就成一维数组了,也叫散列分布不均匀 散列分布均匀需要重写hashcode()方法时有技巧

总结:

放在HashMap中key部分的元素 和 HashSet中的元素 需要同时重写hashcode()和equals()方法

重写之后 当元素eqauls为true那么hashcode值一定相同,这样就不会出现两个一样的元素出现在数组上两个位置

创建:

Map<Integer,String> map = new HashMap<>();

添加元素:

map.put(1,"liu")

获取元素个数:

map.size();

取出元素

map.get(key);

遍历:

  1. 拿到key遍历

    Set<Integer> keys = map.keySet();
    for(Integer k:keys){
        System.out.println(map.get(k))
    }
  1. 将Map集合转为Set集合 Set集合中每一个元素是Node,Node节点中有key和value

    Set<Map.Entry<Integer,String>> nodes = map.entrySet();
    for(Map.Entry<Integer,String> node:nodes){
        System.out.println(node.getKey+"="+node.getValue())
    }

2.2 HashTable

HashTable集合底层也是哈希表数据结构 线程安全 效率低

注意:

key不能为null,value也不能为null ​ 方法带有synchronized,线程安全 效率低 ​ 底层是哈希表数据结构 ​ 初始化容量11,默认加载因子是0.75,扩容是原来的2倍+1

2.2.1 Properties

Properties被称为属性类对象,是一个Map集合,属性类,继承HashTable

特点:

线程安全,存储元素采用键值对形式

并且key和value只支持String类型 不支持其他类型

创建Properties对象:

Properties pro = new Properties();

主要构造方法:

setProperty(key,value);

存 getProperty(key);

根据key取value

2.4 TreeMap

放到TreeSet中的元素 等同于放到TreeMap集合key部分

TreeSet集合底层是一个TreeMap TreeMap集合底层是二叉树

TreeSet集合中的元素:

无序不可重复,但是可以按照元素的大小顺序自动排序 TreeSet对于自定义的类型无法排序 放在TreeSet集合中的元素需要实现java.lang.Comparable接口,并且实现compareTo方法,equals可以不写

2.4.1 比较器接口

比较器实现java.util.Comparator接口 Comparable是java.lang包下的 Compartor是java.util包下的

实现规则:

class 比较器名 implements Comparator<>{ 重写compare方法 } 传比较器对象:

TreeSet<> set = new TreeSet<>(new 比较器名);

总结:放到TreeSet或TreeMap集合key部分的元素如果需要排序 有两种方式

  1. 放在集合中的元素实现java.lang.Comparable接口

  2. 在构造TreeSet或TreeMap集合时传一个比较器对象 如果比较规则不经常变化 用Comparable接口 如果比较规则有多个且经常变化 用Comparator接口,该接口符合OCP原则

2.4.2 二叉树

自平衡二叉树: 左小右大原则 遍历二叉树的三种方式:这里的前中后说的是根的位置 前序遍历 根左右 中序遍历 左根右 后序遍历 左右根 TreeSet集合或TreeMap集合采用中序遍历 Iterator迭代器采用的是中序遍历

泛型

JDK5.0之后推出的新特性

JDK8之后引入自动类型推断机制(钻石表达式)

定义:使用泛型List<>之后 表示List集合中只允许存储固定类型的数据 所以 使用泛型可以指定集合中存储的数据类型

优点:使集合中元素的数据类型更加统一;从集合中取出的元素类型是泛型指定的类型 不需要大量向下转型

缺点:导致集合中存储的元素缺乏多样性,但大多数业务中集合元素的类型还是统一的

注意:泛型只在编译器起作用只是给编译器参考的 运行阶段没用

自定义泛型: 在类上public class Generic<标识符随便写>{} 但在new上写清楚需要什么类型 java源代码中经常出现E和T E代表element T代表type

for增强

foreach IDK5.0之后退出增强for循环

代码规范:

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

int[] arr = [1,2,3,4,5,6];
for(int data:arr){
    system.out.println(data);    //data是数组中的元素
}

缺点:没有下标

优点:在集合中 可以直接取出元素 不需要再获取迭代器一个一个输出

集合总结

每个集合对象的创建 向集合中添加元素 取出元素 遍历集合

HashMap集合的key需要重写equals和hashcode

TreeSet传入的类型可以自定义 可以实现comparable接口 也可以编写一个比较器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值