JAVA容器详解

2023年8月14日11:08:34

系列文章目录



前言

这篇文章主要是介绍java容器的分类和一些用法。


一、为什么引入Java容器?

为什么要引入Java容器?
我们知道,如果定义一个int数组,需要一开始就要制定它的大小。在一些情况下,我们根本不知道它的长度是多少,开辟很大的长度会导致空间浪费。
此外,数组还有很多缺点,例如数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。获取数据中实际元素的个数的需求,数组没有现成的属性或方法可用。数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
为了数组能够更灵活的应用,提出了Java容器的概念。

二、Java容器分类

JAVA容器详解
Java的容器主要分为2个大类,即Collection和Map。Collection代表着集合,类似数组,只保存一个数字。而Map则是映射,保留键值对两个值。
根据图,首先提一下List Queue Set Map 这四个的区别。

  • List(对付顺序的好帮手): 存储的元素是有序的、可重复的。
  • Set (注重独一无二的性质):存储的元素是无序的、不可重复的。
  • Queue (实现排队功能的叫号机):按特定的排队规则来确定先后顺序,存储的元素是有序的、可重复的。
  • Map (用 key 来搜索的专家) :使用键值对(key-value)存储,类似于数学上的函数 y=f(x),“x” 代表 key,“y” 代表 value,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。

接下来我们就来深入探究一下吧。

1.Collection

(1).List

名称 底层 线程安全性 优点 扩容机制
ArrayList 数组 线程不安全 查找快,增删慢 首次创建长度为10,扩为1.5倍
Vector 数组 线程同步线程安全 查找快,增删慢 首次创建长度为10,*2
LinkedList 双向链表(JDK1.6 之前为循环链表,JDK1.7 取消了循环) 线程不安全 增删快,查找慢 不主动扩容

(2).Set

名称 底层 线程安全性 备注
HashSet HashMap(数组+链表) 线程不安全 注意hashcode和equals()
LinkedHashSet 链表和哈希表 线程不安全 HashSet的子类,元素的插入和取出顺序满足 FIFO
TreeSet 红黑树 线程不安全 支持对元素自定义排序规则

TreeSet中的自然排序和定制排序
(1)自然排序:在所属的类中加上排序

实现类

package TreeSet;

//1.自然排序
public class Person implements Comparable{
    private int age;
    private String name;
    private int score;

    public Person(int age,String name,int score){
        this.age=age;
        this.name=name;
        this.score=score;
    }
    
    @Override
    public int compareTo(Object o) {
        //强制转换对象
        //按年龄和分数排序 都是从大到小
        if(o instanceof Person){
            Person O=(Person) o;//强转类型
            if(this.age!=O.age)
            return this.age-O.age;//this是当前的主体,此时返回的应该是升序
            else return O.score-this.score;
        }else throw new RuntimeException("不属于此类型");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

测试类

package TreeSet;

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        Person[] person=new Person[3];
        person[0]=new Person(5,"guolu",99);
        person[1]=new Person(3,"cherry",98);
        person[2]=new Person(5,"cherry",98);
        Arrays.sort(person);//别忘了这句话;
        for(int i=0;i<3;i++){
            System.out.println(person[i].toString());
        }
    }
}

(2)定制排序:向其中传入已经重写Comparator中方法的对象。

public class Test {
    public static void main(String[] args) {
        Person[] person=new Person[3];
        person[0]=new Person(5,"guolu",99);
        person[1]=new Person(3,"cherry",98);
        person[2]=new Person(2,"cherry",98);

        Comparator com=new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Person p1=(Person)o1;
                Person p2=(Person)o2;
                return p1.getAge()-p2.getAge();//得确保有get和set接口,这边好像不太好用compareTo,暂时不知道为啥
            }
        };
        Arrays.sort(person,com);
        for(int i=0;i<3;i++){
            System.out.println(person[i].toString());
        }
    }
}

(3).Queue

queue:单向队列
deque:双向队列
PriorityQueue 是非线程安全的,默认小顶堆,但可以接收一个 Comparator 作为构造参数,从而来自定义元素优先级的先后。

2.Map

名称 底层 线程安全性 备注 扩容机制
HashMap 数组+链表(jdk7) 数组+链表+红黑树 (jdk8) 线程不安全 能存储null的key和value 首次创建长度16,扩容2倍,jdk8中当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前的数组长度>64时,此索引位置上的所有数据改为使用红黑树存储
LinkedHashMap 同hashmap 线程不安全 比hashmap多了指向前驱和后继的两个指针
ConcurrentHashMap 同hashmap 线程安全 使用16个锁来控制segments,分段锁
HashTable 数组+链表 线程安全,全表锁 不能存储null的key和value 首次创建时长度为11,后来变为2n+1
TreeMap 红黑树 线程不安全 定制排序

补漏查缺小知识

1.集合转换为数组

Collection coll=new ArrayList();
Object arr[]=coll.toArray();
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}

2.数组转换为集合
asList后面的必须接引用类型

List<String> list=Arrays.asList(new String[]{"AA","BB","CC"});
System.out.println(list);

3.红黑树
参考:红黑树

参考

javaguide、尚硅谷

  • 作者:诗酒趁年华527
  • 原文链接:https://blog.csdn.net/qq_36787616/article/details/123604120
    更新时间:2023年8月14日11:08:34 ,共 3105 字。