java集合

一、 集合框架

Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、Vector、HashSet、LinkedHashSet、HashMap、LinkedHashMap …

1.集合和数组的区别

  • 数组声明了它容纳的元素的类型,而集合不声明。
  • 数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。
  • 数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。
  • 数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。
    参考文献
    集合中只能存储引用数据类型,想要存储8种基本数据类型(byte、int、short、long、float、double、boolean、char),需要将其装换成基本数据类型所对应的包装类(Byte、Integer、Short、Long、Double、Boolean、Character)

2.Collection集合的公共方法

3.常用集合的分类

Collection 接口的接口
|——List 接口:元素按进入先后有序保存,可重复
|——————├ LinkedList,实现类,适应于写多的场景,线程不安全
|——————├ ArrayList ,实现类, 适应于读多的场景, 线程不安全
|——————├ Vector,实现类,数组 ,线程安全
|————————├Stack extends Vector
|——Set 接口:不可重复
|——————├HashSet 使用hash表(Node数组)存储元素 ,无序
|————————├ LinkedHashSet 链表维护元素的插入次序 ,extends HashSet
|——————├TreeSet 底层实现为二叉树,元素排好序

Map 接口
|——————├Hashtable 接口实现类, 同步, 线程安全
|——————├HashMap 接口实现类 ,没有同步, 线程不安全-
|————————├ LinkedHashMap 双向链表和哈希表实现
|——————├TreeMap 红黑树对所有的key进行排序

4.集合遍历方式

  • forEach(Consumer action)
  • Iterator迭代器
  • 增强for循环

二、常见集合类详解

2.1 ArrayList

原理解析

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制。ArrayList 继承了 AbstractList ,并实现了 List 接口。
ArrayList 底层的数据结构是数组,长度可以根据初始容量以及加载因子动态改变,有序,可重复,线程不安全,由于有序以及索引的存在,访问快,插入或者删除慢,适合读多写少的场景。

重要方法

//1.数字排序
ArrayList<Integer> myNumbers = new ArrayList<Integer>();
Collections.sort(myNumbers); 

        for (int i : myNumbers) {
            System.out.println(i);
        }
//2.字母排序
ArrayList<String> sites = new ArrayList<String>();   
 Collections.sort(sites);  // 字母排序
        for (String i : sites) {
            System.out.println(i);
        }     

2.2 LinkedList

原理解析

有序,可重复,线程不安全
在实现中采用链表数据结构。插入和删除速度快,访问速度慢。

2.3 Vector

在这里插入图片描述

Vector是JDK1.2出现集合框架之前的就存在的一种古老集合,不推荐使用,集合框架出现之后,将其作为List接口的实现之一。
Vector相比于ArrarList,是线程安全的,相对的来说性能较低。Stack是Vector的子类,用于模拟栈这种数据结构,同理也是线程安全的,同时也是一种比较古老的集合,不推荐使用。
解决多线程并发访问集合时的线程安全问题通常使用Collections集合工具类提供的方法,Collections提供了基本每种集合类型的同步方法: synchronizedXxx() 方法,以解决多个线程同时操作一个集合的并发问题:

//通过如下的方法保证List的线程安全性
List list2 = Collections.synchronizedList(list1);
System.out.println(list2);

2.4 HashSet

HashSet的特点:无序,不可重复,值可以为null且只能有一个,线程不安全;
HashSet类按照哈希算法来存取集合中的对象。ArrayList底层基于数组这种数据结构,查找速度快,存储删除慢;LinkedList底层是基于链表这种数据结构,存储删除快,查找慢;HashSet是数组和链表两种数据结构的组合,同时综合了两者的优点。

原理解析
HashSet是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75的HashMap。封装了一个HashMap对象来存储所有的集合元素,所有放在 HashSet中的集合元素实际上由 HashMap的key来保存,而 HashSet中的 HashMap的 value则存储了一个static、final类型的空对象。

参考文献

HashSet添加元素

当把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值(hashcode() ->java.lang.Object类中的固有方法,计算对象的散列码,这个散列码标识了对象在内存中位置)来判断对象加入的位置,同时也会与其他加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现,直接将对象添加到相应位置;但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同,如果两者相同,则覆盖旧元素。自定义的对象添加到hashset集合中时,要重写hashcode()以及equals()方法,自定义元素相等的规则。

添加自定义对象到hashset集合测试:

package myproject.collection;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.Objects;
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //认为只要username相同就是同一个对象
    private String username;
    private String nickname;
}
package myproject.collection;
import java.util.HashSet;

public class TestHashSet {
    public static void main(String[] args) {
        HashSet<User> hashSet = new HashSet<User>();
        User user1 = new User("a","hh");
        User user2 = new User("a","ww");
        User user3 = new User("b","zs");
        User user4 = new User("c","ls");
        hashSet.add(user1);
        hashSet.add(user2);
        hashSet.add(user3);
        hashSet.add(user4);
        System.out.println("集合中总共有"+hashSet.size()+"个对象:");//hashset的size->3
        System.out.println(hashSet);
        System.out.println("user1的hashcode:"+user1.hashCode());
        System.out.println("user2的hashcode:"+user2.hashCode());
    }
}

测试结果:

集合中总共有4个对象:
[User(username=c, nickname=ls), User(username=a, nickname=hh), User(username=a, nickname=ww), User(username=b, nickname=zs)]
user1的hashcode:12532
user2的hashcode:13012

测试结果并不符合我们的预期,我们想把username相同看成是同一个人,所以需要修改hashcode()以及equals()方法,如下所示:

package myproject.collection;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.Objects;

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //认为只要username相同就是同一个对象
    private String username;
    private String nickname;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(username, user.username);
    }
    @Override
    public int hashCode() {
        return Objects.hash(username);
    }
}

测试结果:

集合中总共有3个对象:
[User(username=a, nickname=hh), User(username=b, nickname=zs), User(username=c, nickname=ls)]
user1的hashcode:128
user2的hashcode:128

Hashset不能存储重复的对象,这里hashSet中要存储的是自定义的User对象,我们需要重写User中的hashcode以及equals方法,定义User对象的相等条件,否则按照默认的方式进行判断的话,只有地址相等,两个user才相等,显然不符合我们定义的相等规则User对象的名字相等即相等。
参考文献

HashSet查询元素
调用对象的hashcode()方法,找到对象的存在的桶,如果存在多个对象,对链表中的元素逐个遍历。

2.5 LinkedHashSet

原理解析
LinkedHashSet 继承自 HashSet, 唯一的区别是 LinkedHashSet 内部使用的是 LinkHashMap。 这样做的意义或者好处就是 LinkedHashSet 中的元素顺序是可以保证的, 也就是说遍历序和插入序是一致的。

2.6 TreeSet

基于TreeMap实现, 支持排序(自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序),非线程安全的。

2.7 HashMap

HashMap特点:无序,不可重复,key和value值都可以为空,HashMap 根据key的值进行数据的检索,所以key不能重复,也就是key值只能有一个是空,线性不安全。

原理解析
HashMap 的主干是Node类型的数组,Node类包含的属性包含key,value,hash,next等,其中key,value属性保存键值对的值,hash值是对key进行hash后的结果,通过对HashMap 集合的size取模得到当前键值对在Node数组中的位置,方便元素的查找;当hash值发生碰撞时,将会把数组中的Node节点当做头结点维护一个链表,next属性指向下一个Node节点。
HashMap底层实现原理

2.8 LinkedHashMap

  • LinkedHashMap继承HashMap,是HashMap的子类;
  • LinkedHashMap的特点:有序,不可重复,线程不安全。HashMap 是无序的,LinkedHashMap通过维护一个额外的双向链表保证了迭代顺序,LinkedHashMap是HashMap+LinkedList的结合 。

原理解析
将所有 Entry 节点链入一个双向链表的 HashMap。 在 LinkedHashMap 中, 所有 put 进来的
Entry 都保存在哈希表中, 但由于它又额外定义了一个以 head 为头结点的双向链表, 因此
对于每次 put 进来 Entry, 除了将其保存到哈希表上外, 还会将其插入到双向链表的尾部。

2.9 Hashtable

HashTable的特点:无序,不能重复,key和value值都不能是null,线程安全,相当于Vector与ArrayList之间的关系,同样是一个古老的类,不推荐使用。

原理解析
HashTable底层与HashMap一样通过Hash表实现,关键的put、get等方法都是加了synchronized锁,线程安全,相对效率较低。

2.10 TreeMap

TreeMap的特点:相对于HashMap,TreeMap是有序的,不可重复,线程非安全;TreeMap 的查询、 插入、 删除效率均没有 HashMap 高, 一般只有要对 key 排序时才使用TreeMap;TreeMap 的 key 不能为 null, 而 HashMap 的 key 可以为 null。

原理解析
TreeMap底层是一个红黑树数据结构,每一个节点即是一个key-value键值对,需要根据key对节点进行排序。红黑树数据结构可以使得TreeMap中的所有键值对处于有序状态。排序包含自然排序和定制排序两种,自然排序中的key必须是同一个类的对象,同时实现Comparable接口;定制排序创建TreeMap时,需要传入Comparator对象,自己定义排序的规则。

三、参考文献

1.java集合框架|菜鸟教程
2.java集合超详解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值