【集合系列】- 初探java集合框架图(二)

简介: 实际开发中,经常用到java的集合框架,比如ArrayList、LinkedList、HashMap、LinkedHashMap,几乎经常接触到,虽然用的多,但是对集合的整体框架,基础知识还是不够系统,今天想和大家一起来梳理一下!

4.3、PriorityQueue

PriorityQueue也是一个队列的实现类,此实现类中存储的元素排列并不是按照元素添加的顺序进行排列,而是内部会按元素的大小顺序进行排列,是一种能够自动排序的队列。

例子

public static void main(String[] args) {
        PriorityQueue<Integer> queue1 = new PriorityQueue<>(10);
        System.out.println("处理前的数据");
        Random rand = new Random();
        for (int i = 0; i < 10; i++) {
                Integer num = rand.nextInt(90) + 10;
                System.out.print(num + ", ");
            queue1.offer(num); // 随机两位数
        }
        System.out.println("\n处理后的数据");
        for (int i = 0; i < 10; i++) { // 默认是自然排序 [升序]
            System.out.print(queue1.poll() + ", ");
        }
}

输出结果:

处理前的数据
36, 23, 24, 11, 12, 26, 79, 96, 14, 73,
处理后的数据
11, 12, 14, 23, 24, 26, 36, 73, 79, 96,

05、映射表(Map)

Map是一个双列集合,其中保存的是键值对,键要求保持唯一性,值可以重复。

Map 主要实现类:HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties。

5.1、HashMap

关于HashMap,相信大家都不陌生,继承自AbstractMap,key 不可重复,因为使用的是哈希表存储元素,所以输入的数据与输出的数据,顺序基本不一致,另外,HashMap最多只允许一条记录的 key 为 null。

5.2、LinkedHashMap

HashMap 的子类,内部使用链表数据结构来记录插入的顺序,使得输入的记录顺序和输出的记录顺序是相同的。LinkedHashMap与HashMap最大的不同处在于,LinkedHashMap输入的记录和输出的记录顺序是相同的!

5.3、TreeMap

能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历时,得到的记录是排过序的;如需使用排序的映射,建议使用 TreeMap。TreeMap实际使用的比较少!

5.4、IdentityHashMap

继承自AbstractMap,与HashMap有些不同,在获取元素的时候,通过==代替equals ()来进行判断,比较的是内存地址

get方法源码部分

public V get(Object key) {
        Object k = maskNull(key);
        Object[] tab = table;
        int len = tab.length;
        int i = hash(k, len);
        while (true) {
            Object item = tab[i];
      //用==比较k和元素是否相等
            if (item == k)
                return (V) tab[i + 1];
            if (item == null)
                return null;
            i = nextKeyIndex(i, len);
        }
}

5.5、WeakHashMap

WeakHashMap继承自AbstractMap,被称为缓存Map,向WeakHashMap中添加元素,再次通过键调用方法获取元素方法时,不一定获取到元素值,因为WeakHashMap 中的 Entry 可能随时被 GC 回收。

5.6、Hashtable

Hashtable,一个元老级的类,键值不能为空,与HashMap不同的是,方法都加了synchronized同步锁,是线程安全的,但是效率上,没有HashMap快!

同时,HashMap 是 HashTable 的轻量级实现,他们都完成了Map 接口,区别在于 HashMap 允许K和V为空,而HashTable不允许K和V为空,由于非线程安全,效率上可能高于 Hashtable。

如果需要在多线程环境下使用HashMap,可以使用如下的同步器来实现或者使用并发工具包中的ConcurrentHashMap

Map<String, Object> map =Collections.synchronizedMap(new HashMap<>());

5.7、Properties

Properties继承自HashTable,Properties新增了load()和和store()方法,可以直接导入或者将映射写入文件,另外,Properties的键和值都是String类型。

06、比较器

Comparable和Comparator接口都是用来比较大小的,一般在TreeSet、TreeMap接口中使用的比较多,主要用于解决排序问题。

6.1、Comparable

Comparable:对实现它的每个类的对象进行整体排序

package java.lang;
import java.util.*;
public interface Comparable<T> {
  public int compareTo(T o);
}

若一个类实现了Comparable 接口,实现 Comparable 接口的类的对象的 List 列表 ( 或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。

此外,实现 Comparable 接口的类的对象 可以用作 “有序映射 ( 如 TreeMap)” 中的键或 “有序集合 (TreeSet)” 中的元素,而不需要指定比较器。

使用例子:

/**
  * 实体类Person实现Comparable接口
  */
public class Person implements Comparable<Person>{
    private int age;
    private String name;
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public int compareTo(Person o){
        return this.age-o.age;
    }
    @Override
    public String toString(){
        return name+":"+age;
    }
}

测试

public static void main(String[] args) {
    Person person1 = new Person("张三",18);
    Person person2 = new Person("李四",17);
    Person person3 = new Person("王五",19);
    List<Person> list = new ArrayList<>();
    list.add(person1);
    list.add(person2);
    list.add(person3);
    System.out.println(list);
    Collections.sort(list);
    System.out.println(list);
}

输出:

[张三:18, 李四:17, 王五:19]
[李四:17, 张三:18, 王五:19]

6.2、Comparator

Comparator:也是对实现它的每个类的对象进行排序

package java.util;
import ***;
public interface Comparator<T> {
  int compare(T o1, T o2);
  ......
}

如果我们的这个类Person无法修改或者没有继承Comparable接口,我们又要对其进行排序,Comparator就可以派上用场了。

将类Person实现的Comparable接口去掉

/**
  * 实体类Person
  */
public class Person {
    private int age;
    private String name;
  public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString(){
        return name+":"+age;
    }
}

测试类:

public static void main(String[] args) {
    Person person1 = new Person("张三",18);
    Person person2 = new Person("李四",17);
    Person person3 = new Person("王五",19);
    List<Person> list = new ArrayList<>();
    list.add(person1);
    list.add(person2);
    list.add(person3);
    System.out.println(list);
    Collections.sort(list, new Comparator<Person>() {
      @Override
      public int compare(Person o1, Person o2) {
        if(o1 == null || o2 == null){
          return 0;
        }
        //o1比o2小,返回负数
        //o1等于o2,等于0
        //o1大于o2,返回正数
        return o1.getAge()-o2.getAge();
      }
    });
    System.out.println(list);
}

输出:

[张三:18, 李四:17, 王五:19]
[李四:17, 张三:18, 王五:19]

07、常用工具类

7.1、Collections类

java.util.Collections工具类为集合框架提供了很多有用的方法,这些方法都是静态的,在编程中可以直接调用。整个Collections工具类源码差不多有4000行,这里只针对一些典型的方法进行阐述。

7.1.1、addAll

addAll:向指定的集合c中加入特定的一些元素elements

public static <T> boolean addAll(Collection<? super T> c, T… elements)
7.1.2、binarySearch

binarySearch:利用二分法在指定的集合中查找元素

#集合元素T实现Comparable接口的方式,进行查询
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
#元素以外部实现Comparator接口的方式,进行查询
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
7.1.3、sort
#集合元素T实现Comparable接口的方式,进行排序
public static <T extends Comparable<? super T>> void sort(List<T> list)
#元素以外部实现Comparator接口的方式,进行排序
public static <T> void sort(List<T> list, Comparator<? super T> c)
7.1.4、shuffle

shuffle:混排,随机打乱原来的顺序,它打乱在一个List中可能有的任何排列的踪迹。

#方法一
public static void shuffle(List<?> list)
#方法二,指定随机数访问
public static void shuffle(List<?> list, Random rnd)
7.1.5、reverse

reverse:集合排列反转

#直接反转集合的元素
public static void reverse(List<?> list)
#返回可以使集合反转的比较器Comparator
public static <T> Comparator<T> reverseOrder()
#集合的反转的反转,如果cmp不为null,返回cmp的反转的比较器,如果cmp为null,效果等同于第二个方法.
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
7.1.6、synchronized系列

synchronized系列:确保所封装的集合线程安全(强同步)

#同步Collection接口下的实现类
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
#同步SortedSet接口下的实现类
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
#同步List接口下的实现类
public static <T> List<T> synchronizedList(List<T> list)
#同步Map接口下的实现类
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
#同步SortedMap接口下的实现类
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

7.2、Arrays类

java.util.Arrays工具类也为集合框架提供了很多有用的方法,这些方法都是静态的,在编程中可以直接调用。整个Arrays工具类源码有3000多行,这里只针对一些典型的方法进行阐述。

7.2.1、asList

asList:将一个数组转变成一个List,准确来说是ArrayList

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
}

注意:这个List是定长的,企图添加或者删除数据都会报错java.lang.UnsupportedOperationException

7.2.2、sort

sort:对数组进行排序,适合byte,char,double,float,int,long,short等基本类型,还有Object类型

#基本数据类型,例子int类型数组
public static void sort(int[] a)
#Object类型数组
#如果使用Comparable进行排序,Object需要实现Comparable
#如果使用Comparator进行排序,可以使用外部比较方法实现
public static void sort(Object[] a)
7.2.3、binarySearch

binarySearch:通过二分查找法对已排序的数组进行查找。如果数组没有经过Arrays.sort排序,那么检索结果未知。

适合byte,char,double,float,int,long,short等基本类型,还有Object类型和泛型。

#基本数据类型,例子int类型数组,key为要查询的参数
public static int binarySearch(int[] a, int key)
#Object类型数组,key为要查询的参数
#如果使用Comparable进行排序,Object需要实现Comparable
#如果使用Comparator进行排序,可以使用外部比较方法实现
public static int binarySearch(Object[] a, Object key)
7.2.4、copyOf

copyOf:数组拷贝,底层采用System.arrayCopy(native方法)实现。

适合byte,char,double,float,int,long,short等基本类型,还有泛型数组。

#基本数据类型,例子int类型数组,newLength新数组长度
public static int[] copyOf(int[] original, int newLength)
#T为泛型数组,newLength新数组长度
public static <T> T[] copyOf(T[] original, int newLength)
7.2.5、copyOfRange

copyOfRange:数组拷贝,指定一定的范围,底层采用System.arrayCopy(native方法)实现。

适合byte,char,double,float,int,long,short等基本类型,还有泛型数组。

#基本数据类型,例子int类型数组,from:开始位置,to:结束位置
public static int[] copyOfRange(int[] original, int from, int to)
#T为泛型数组,from:开始位置,to:结束位置
public static <T> T[] copyOfRange(T[] original, int from, int to)
7.2.6、equals和deepEquals

equals:判断两个数组的每一个对应的元素是否相等(equals, 对于两个数组的元素a和a2有a==null ? a2==null : a.equals(a2)

#基本数据类型,例子int类型数组,a为原数组,a2为目标数组
public static boolean equals(int[] a, int[] a2)
#Object数组,a为原数组,a2为目标数组
public static boolean equals(Object[] a, Object[] a2)

deepEquals:主要针对一个数组中的元素还是数组的情况(多维数组比较)

#Object数组,a1为原数组,a2为目标数组
public static boolean deepEquals(Object[] a1, Object[] a2)
7.2.7、toString和deepToString

toString:将数组转换成字符串,中间用逗号隔开

#基本数据类型,例子int类型数组,a为数组
public static String toString(int[] a)
#Object数组,a为数组
public static String toString(Object[] a)

deepToString:当数组中又包含数组,就不能单纯的利用Arrays.toString()了,使用此方法将数组转换成字符串

#Object数组,a为数组
public static String deepToString(Object[] a)

08、迭代器

JCF的迭代器(Iterator)为我们提供了遍历容器中元素的方法。只有容器本身清楚容器里元素的组织方式,因此迭代器只能通过容器本身得到。每个容器都会通过内部类的形式实现自己的迭代器。

ArrayList<String> list = new ArrayList<String>();
list.add(new String("a1"));
list.add(new String("a2"));
list.add(new String("a3"));
Iterator<String> it = list.iterator();//得到迭代器
while(it.hasNext()){
    String obj = it.next();//访问元素
    System.out.println(obj);
}

JDK 1.5 引入了增强的for循环,简化了迭代容器时的写法

//使用增强for迭代
ArrayList<String> list = new ArrayList<String>();
list.add(new String("a1"));
list.add(new String("a2"));
list.add(new String("a3"));
for(String obj : list){
  //enhanced for statement
    System.out.println(obj);
}

09、总结

以上,主要是对java集合的整体架构进行简单的介绍,如果有理解不当之处,欢迎指正。

10、参考

1、JDK1.7&JDK1.8 源码

2、Otokaze's Blog - Java Collection框架

3、CSDN - 朱小厮 - Comparable与Comparator浅析


欢迎加入我们的知识星球,一起成长,交流经验。加入方式,长按下方二维码噢

最后,我想重复一句话:选择和一群优秀的人一起成长,你成长的速度绝对会不一样!

相关文章
|
27天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
103 3
|
1月前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
1月前
|
消息中间件 Java 数据库连接
Java 反射最全详解 ,框架设计必掌握!
本文详细解析Java反射机制,包括反射的概念、用途、实现原理及应用场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 反射最全详解 ,框架设计必掌握!
|
27天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
27 2
|
1月前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
26天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
1月前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
1月前
|
Java 开发者
|
2月前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
1月前
|
缓存 Java 数据库连接
Hibernate:Java持久层框架的高效应用
通过上述步骤,可以在Java项目中高效应用Hibernate框架,实现对关系数据库的透明持久化管理。Hibernate提供的强大功能和灵活配置,使得开发者能够专注于业务逻辑的实现,而不必过多关注底层数据库操作。
18 1