Java:常用的容器小记

对 Java 中的 常用容器,做一个微不足道的小小小小记

容器类概述

常见容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。

Collection

Set

Set 说明
TreeSet 基于红黑树实现,支持有序性操作;
例如:根据一个范围查找元素的操作。
但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)
HashSet 基于哈希表(HashMap)实现,支持快速查找,但不支持有序性操作。
并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的
LinkedHashSet 具有 HashSet 的查找效率,底层是链表+哈希表。
使用哈希表存储元素,再维护一个双向链表保存元素的插入信息

List

List 说明
ArrayList 基于动态数组实现,支持随机访问
Vector 和 ArrayList 类似,但它是线程安全的
LinkedList 基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。
不仅如此,LinkedList 还可以用作栈、队列和双向队列

Queue

Queue 说明
LinkedList 基于链表实现的队列,可以用它来实现双向队列
PriorityQueue 基于堆结构实现,可以用它来实现优先队列
ArrayDeque 实现了Deque(双向队列),Deque继承自Queue
使用了可变数组,可以做为队列来使用,也可以作为栈使用
ArrayDeque不支持null

Map

Map 说明
TreeMap 基于红黑树实现
HashMap 基于哈希表实现
HashTable 和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。
它是遗留类,不应该去使用它。
现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁
LinkedHashMap 使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU,Least Recently Used)顺序

List & Set & Map

List & Set & Map 之间的大致区别:

比较 LIst Set Map
继承接口 Collection Collection 是个接口
常见实现类 AbstractList
常用的子类有:
ArrayList
LinkedList
Vector
AbstractSet
常用的子类有:
HashSet
LinkedHashSet
TreeSet
实现的类:
HashMap
HashTable
LinkedHashMap
常见方法 add()
remove()
clear()
get()
contains()
size()
...
add()
remove()
clear()
get()
contains()
size()
...
put()
get()
remove()
clear()
containsKey()
containsValue()
keySet()
values()
size()
...
元素 可重复 不可重复 不可重复
顺序 有序 一般无序(由hashcode决定) 一般无序
线程安全 Vector线程安全 HashTable线程安全

Collection & Collections

Collection

是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。List,Set,Queue接口都继承Collection;直接实现该接口的类只有 AbstractCollection 类,该类也只是一个抽象类,提供了对集合类操作的一些基本实现。

Collections

是不属于 Java 的集合框架的,它是集合类的一个工具类/帮助类。此类不能被实例化, 服务于 Java 的 Collection 框架。它包含有关集合操作的静态多态方法,实现对各种集合的搜索、排序、线程安全等操作。

常用功能

  • public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中添加一些元素。
  • public static void shuffle(List<?> list) 打乱顺序 :打乱集合顺序。
  • public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。
  • public static <T> void sort(List<T> list,Comparator<? super T> ) :将集合中元素按照指定规则排序。
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
// 原来写法
// list.add(12);
// list.add(14);
// list.add(15);
// list.add(1000);
// 采用工具类 完成 往集合中添加元素
Collections.addAll(list, 5, 222, 1,2);
System.out.println(list);
//排序方法
Collections.sort(list);
System.out.println(list);
}
}
// 结果:
// [5, 222, 1, 2]
// [1, 2, 5, 222]

Collections 中的 sort 方法

Comparator比较器

排序方法:public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。

如,对字符串类型进行比较:

public class CollectionsDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法
Collections.sort(list);
System.out.println(list);
}
} // 结果:
// [aba, cba, nba, sba]

说到排序了,简单的说就是两个对象之间比较大小,那么在 Java 中提供了两种比较实现的方式,一种是比较死板的采用 java.lang.Comparable 接口去实现,一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator 接口完成。

那么我们采用的 public static <T> void sort(List<T> list) 这个方法完成的排序,实际上要求了被排序的类型需要实现 Comparable 接口完成比较的功能,在String类型上如下:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {

    // 实现了Comparable<String>的方法,该接口内有抽象方法public int compareTo(T o);
// 在String内对其进行了实现
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value; int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
}

String 类实现了这个接口,并完成了比较规则的定义,但是这样就把这种规则写死了,那比如我想要字符串按照第一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了。

// 重写排序的规则
@Override
public int compareTo(Person o) {
//return 0; //认为元素都是相同的
//自定义比较的规则, 比较两个人的年龄(this,参数Person)
//return this.getAge() - o.getAge();//年龄升序排序
return o.getAge() - this.getAge();//年龄升序排序
}

那么这个时候我们可以使用 public static <T> void sort(List<T> list,Comparator<? super T> ) 方法灵活的完成,这个里面就涉及到了 Comparator这个接口,位于位于 java.util 包下,排序是 comparator 能实现的功能之一,该接口代表一个比较器,比较器具有可比性!顾名思义就是做排序的,通俗地讲需要比较两个对象谁排在前谁排在后,那么比较的方法就是:public int compare(String o1, String o2) :比较其两个参数的顺序。

两个对象比较的结果有三种:大于,等于,小于。

如果要按照升序排序,则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数);

如果要按照降序排序,则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

总结 Comparator 的排序规则: o1-o2 为升序;o2-o1 为降序

操作如下:

public class CollectionsDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法 按照第一个单词的降序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.charAt(0) ‐ o1.charAt(0);
}
});
System.out.println(list);
}
} // 结果如下:
// [sba, nba, cba, aba]

Comparable 与 Comparator 两个接口的区别

Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。只能在类中实现 compareTo() 一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和 Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

Comparator:强行对某个对象进行整体排序。可以将 Comparator 传递给 sort 方法(如Collections.sortArrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator 来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。

案例说明:

创建一个学生类,存储到ArrayList集合中完成指定排序操作。

  • Student 初始类
public class Student{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
  • 测试类:
public class Demo {
public static void main(String[] args) {
// 创建四个学生对象 存储到集合中
ArrayList<Student> list = new ArrayList<Student>();
list.add(new Student("rose",18));
list.add(new Student("jack",16));
list.add(new Student("abc",16));
list.add(new Student("ace",17));
list.add(new Student("mark",16));
/*
让学生 按照年龄排序 升序
*/
Collections.sort(list); //要求 该list中元素类型 必须实现比较器Comparable接口
for (Student student : list) {
System.out.println(student);
}
}
}

发现,当我们调用 Collections.sort() 方法的时候 程序报错了。

原因:如果想要集合中的元素完成排序,那么必须要实现比较器 Comparable 接口。

于是我们就完成了Student类的一个实现,如下:

public class Student implements Comparable<Student>{
....
@Override
public int compareTo(Student o) {
return this.age‐o.age;//升序
}
}

再次测试,代码就OK 了效果如下:

Student{name='jack', age=16}
Student{name='abc', age=16}
Student{name='mark', age=16}
Student{name='ace', age=17}
Student{name='rose', age=18}

如果在使用的时候,想要独立的定义规则去使用 可以采用 Collections.sort(List list,Comparetor c) 方式,自己定义规则:

Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge()‐o1.getAge();//以学生的年龄降序
}
});

效果:

Student{name='rose', age=18}
Student{name='ace', age=17}
Student{name='jack', age=16}
Student{name='abc', age=16}
Student{name='mark', age=16}

如果想要规则更多一些,可以参考下面代码:

Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 年龄降序
int result = o2.getAge()‐o1.getAge();//年龄降序
if(result==0){//第一个规则判断完了 下一个规则 姓名的首字母 升序
result = o1.getName().charAt(0)‐o2.getName().charAt(0);
}
return result;
}
});

效果如下:

Student{name='rose', age=18}
Student{name='ace', age=17}
Student{name='abc', age=16}
Student{name='jack', age=16}
Student{name='mark', age=16}

参考

https://mp.weixin.qq.com/s/q1r9Pno6ANUzZ9wMzA-JSg

https://blog.csdn.net/qq_41701956/article/details/103223461

Java:常用的容器小记的更多相关文章

  1. <转>Java 常用排序算法小记

    排序算法很多地方都会用到,近期又重新看了一遍算法,并自己简单地实现了一遍,特此记录下来,为以后复习留点材料. 废话不多说,下面逐一看看经典的排序算法: 1. 选择排序 选择排序的基本思想是遍历数组的过 ...

  2. Java:TreeMap类小记

    Java:TreeMap类小记 对 Java 中的 TreeMap类,做一个微不足道的小小小小记 概述 前言:之前已经小小分析了一波 HashMap类.HashTable类.ConcurrentHas ...

  3. Java 文件句柄泄露问题解决小记(转)

    转:Java 文件句柄泄露问题解决小记 维护 WebIDE 免不了要管理很多的文件, 自从我们线上系统增加了资源回收功能,便一直受一个问题困扰:后台线程解绑目录时偶尔报错,看症状因为是某些文件被占用了 ...

  4. Java:HashMap类小记

    Java:HashMap类小记 对 Java 中的 HashMap类,做一个微不足道的小小小小记 概述 HashMap:存储数据采用的哈希表结构,元素的存取顺序不能保证一致.由于要保证键的唯一.不重复 ...

  5. java常用英文解释

    java常用名词解释: OO: object-oriented ,面向对象 OOP:object-oriented programming,面向对象编程 Author:JCC Object:对象JDK ...

  6. Java常用jar包用途

    Java常用jar包用途: USAGE INDEX JAR NAME USAGE 1 ASM asm-2.2.3.jar ASM字节码库 2 ASM asm-commons-2.2.3.jar ASM ...

  7. JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...

  8. java中的容器问题

    小小的总结一下java中的容器问题. 一.三个知识点 1.迭代器 1).java.util.Interator + hasnext(); next(); remove(); 2).java.lang. ...

  9. JAVA常用知识点及面试题总结

    1. String.StringBuffer.StringBuilder三者区别? (1)三者在执行速率上的比较: String<StringBuffer<StringBuilder 原因 ...

随机推荐

  1. Robot Framework(8)- Collections 测试库常用的关键字列表

    如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 所有关键字 ...

  2. DataGridView高度自动调整

    AutoResizeGrid.cs代码 /// <summary> /// 根据行数据,自动调整DataGridView高度 /// </summary> public sea ...

  3. (5)java Spring Cloud+Spring boot+mybatis企业快速开发架构之SpringCloud-Spring Boot简介

    ​Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是简化新 Spring 应用的初始搭建以及开发过程.该框架使用了特定的方式进行配置,从而使开发人员不再需要定义样板化的配置 ...

  4. 简单操作:10分钟实现在kubernetes(k8s)里面部署服务器集群并访问项目(docker三)

    前言 经过docker安装.k8s开启并登录,我们终于到 "部署k8s服务器集群并访问项目" 这一步了,实现的过程中有太多坑,好在都填平了,普天同庆. 在进行当前课题之前,我们需要 ...

  5. 关于在.H文件中定义变量

    KEIL中,在".H"文件定义变量. 如果该".H"文件同时被两个".C"文件调用,则会出现重复定义错误(*** ERROR L104: M ...

  6. PHP获取目录中的全部内容RecursiveDirectoryIterator

    这次我们来介绍一个SPL库中的目录迭代器,它的作用其实非常简单,从名字就可以看出来,就是获取指定目录下的所有内容.之前我们要遍历目录获取目录及目录下的所有文件一般是需要进行递归遍历的,自己写这个代码说 ...

  7. js相同的正则多次调用test()返回的值却不同的问题

    js代码: var name = '测试中文';// 姓名 var nameRgexp = new RegExp("[a-zA-Z\u4e00-\u9fa5]{2,}"," ...

  8. 解决wampserver无法启动问题

    如果无法启动,找不到原因.直接依次点击打开到:控制面板--管理工具--事件查看器--windows日志--应用程序,查看对应进程错误信息对症下药即可. 我这个错误就是8099端口错误,运行cmd命令, ...

  9. svn的应用

    SVN 如何来进行多人协作开发? 在实际工作中,通常是一个小组或者一个团队一起开发同一个项目,不同的人开发不同的功能模块,有一个公共的地方存放项目代码. 如果多个人同时对同一个文件做了修改,比如按照分 ...

  10. Jmeter通过正则表达式提取器提取响应结果数据

    Jmeter进行接口测试常常会运到一个问题:就是第二个请求如何接收上一个请求响应中的参数.比如,现在个学生金币充值的接口,得先调用登录接口然后从返回里面复制一下sign的值,放到cookie里这样才能 ...