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. windows 安装pip 及更换pip国内源

    一.官网下载压缩包并解压. 官网:https://pypi.org/project/pip/#files 文件:选择.tar.gz版本 image 解压后,进入解压文件目录,在当前路径下打开cmd窗口 ...

  2. 在C#中使用RSA进行加密和解密

    这篇文章向您展示了如何在c#.net Windows窗体应用程序中使用RSA算法对字符串进行加密和解密.RSA是由Ron Rivest,Adi Shamir和Leonard Adleman开发的非对称 ...

  3. vue实现拖动div元素

    html: <div id="app1"> <div v-drag class="drag"></div> <div ...

  4. 使用AOP+自定义注解完成spring boot的接口权限校验

    记使用AOP+自定义注解完成接口的权限校验,代码如下: pom文件添加所需依赖: 1 <dependency> 2 <groupId>org.aspectj</group ...

  5. Nginx优化与防盗链

    目录: 一.隐藏版本号 二.修改用户与组 三.缓存时间 四.日志切割 五.连接超时 六.更改进程数 七.配置网页压缩 一.隐藏版本号 可以使用 Fiddler 工具抓取数据包,查看 Nginx版本 也 ...

  6. DataGridView高度自动调整

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

  7. 计算字符串的长度.len,RuneCountInString

    内置函数len(),可以返回字符串/数组/切片/map/channel的长度. unicode/utf8包 函数:RuneCountInString(输入一个字符串),返回int类型的字符串长度.由于 ...

  8. 一文看懂String类中的常用方法

    1.int length(): 返回字符串的长度: return value.length 2.char charAt(int index): 返回某索引处的字符return value[index] ...

  9. 2.1Java基础

    2.1.9面向对象的三大特性(携程): 封装:把一个对象的属性隐藏在对象内部,外部对象不能直接访问这个对象的内部信息.但是可以提供一些可以被外界访问的方法来操作属性.就比如我们常常创建一个类,把他的属 ...

  10. Java数学函数的使用

    Java的Math类中提供了一系列关于数学运算的静态方法,常见的运算整理如下[1] 算数运算 Math.sqrt() // 平方根 Math.cbrt() // 立方根 Math.pow(a, b) ...