Java基础回顾系列-第六天-Java集合

2024-09-08 15:32

本文主要是介绍Java基础回顾系列-第六天-Java集合,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java基础回顾系列-第六天-Java集合

    • 集合概述
      • 数组的弊端
      • 集合框架的优点
      • Java集合关系图
      • 集合框架体系图
      • java.util.Collection接口
    • List集合
      • java.util.List接口
        • java.util.ArrayList
        • java.util.LinkedList
        • java.util.Vector
    • Set集合
      • java.util.Set接口
        • java.util.HashSet
        • java.util.LinkedHashSet
        • java.util.TreeSet
    • 集合输出
      • Iterator迭代输出
      • foreach
      • ListIterator双向迭代接口
      • Enumeration
    • Map集合
      • java.util.HashMap
      • java.util.LinkedHashMap
      • java.util.HashTable
      • java.util.TreeMap
      • java.util.Map.Entry接口
    • 集合工具类
      • Stack栈
      • Queue队列
      • java.util.Properties属性操作
      • java.util.Collections工具类

集合概述

参考博文:Java集合类: Set、List、Map、Queue使用场景梳理

参考官方文档:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/doc-files/coll-reference.html

Java 集合就像一种容器,可以把多个对象的引用放入容器中。
Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。
集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。所有的集合类都位于java.util包下,后来为了处理多线程环境下的并发安全问题,java5还在java.util.concurrent包下提供了一些多线程支持的集合类。
Java 集合可分为 SetListMap 三种体系:

  • Set:无序、不可重复的集合
  • List:有序,可重复的集合
  • Map:具有映射关系的集合,每个元素都包含keyvaluekey不允许重复,value可以

注意: 在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 Java5 增加了泛型以后,Java 集合可以记住容器中对象的数据类型

数组的弊端

既然数组可以存储多个数据,为什么还需要集合类?

  1. 数组长度是不可变的,一旦初始化之后,长度是固定的;
  2. 参考以下集合框架的优点,相对应的就是数组的缺点。

集合框架的优点

  • 通过提供数据结构和算法减少编程工作,因此您不必自己编写它们。
  • 通过提供数据结构和算法的高性能实现来提高性能。由于每个接口的各种实现是可互换的,因此可以通过切换实现来调整程序。
  • 通过建立共同语言来来回传递集合,提供不相关API之间的互操作性
  • 通过要求您学习多个集合API 来减少学习API所需的工作量
  • 通过不要求您生成临时集合API,减少设计和实现API所需的工作量
  • 通过为集合和算法提供标准接口来促进软件重用,以便对其进行操作。

Java集合关系图

下图由于CSDN对图像尺寸有限制,可能有点模糊,可以点此访问 https://i-blog.csdnimg.cn/blog_migrate/3076e3a40b56f4cd5975f08a7fa08459.png。
在这里插入图片描述

集合框架体系图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

java.util.Collection接口

Collection接口是单值集合操作的最大父接口,在该接口中定义有所有单值数据的处理对象。
很少直接使用此接口操作。

方法语义
boolean add​(E e)添加单个实例元素到此集合中
boolean addAll​(Collection<? extends E> c)将指定集合中的所有元素添加到此集合中
void clear()删除所有元素
boolean contains​(Object o)是否存在指定元素的单个实例(如果存在)
boolean remove​(Object o)移除指定元素的单个实例(如果存在)
int size()返回此集合中的元素数。
Object[] toArray()将元素转换为数组返回
boolean retainAll​(Collection<?> c)是否保留交集元素
Iterator<E> iterator()返回此集合中元素的迭代器。

List集合

java.util.List接口

有序集合:public interface List<E> extends Collection<E>

方法语义
void add​(int index, E element)在指定索引位置上增加单个实例元素
E set​(int index, E element)在指定索引位置上修改单个实例元素
ListIterator<E> listIterator()返回此集合中元素的列表迭代器。
@SafeVarargs static <E> List<E> of​(E... elements)返回包含任意数量元素的不可修改列表。

三个常用子类:

  • java.util.ArrayList:大部分首选(使用比率90%),线程不安全。
  • java.util.LinkedList:8%
  • java.util.Vector:2%

①、List list1 = new ArrayList();
底层数据结构是数组,查询快,增删慢;线程不安全,效率高
②、List list2 = new Vector();
底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合
③、List list3 = new LinkedList();
底层数据结构是链表,查询慢,增删快;线程不安全,效率高

怎么记呢?我们可以想象:
  数组就像身上编了号站成一排的人,要找第10个人很容易,根据人身上的编号很快就能找到。但插入、删除慢,要望某个位置插入或删除一个人时,后面的人身上的编号都要变。当然,加入或删除的人始终末尾的也快。
  链表就像手牵着手站成一圈的人,要找第10个人不容易,必须从第一个人一个个数过去。但插入、删除快。插入时只要解开两个人的手,并重新牵上新加进来的人的手就可以。删除一样的道理。

java.util.ArrayList

public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable

ArrayList存储容量不足时,会以成倍的形式开辟存储容量,比如默认的10,20,40…

构造函数语义
public ArrayList()构造一个初始容量为10的空列表。
ArrayList​(int initialCapacity)构造一个指定初始容量的列表。
java.util.LinkedList

基于链表实现

public class LinkedList extends AbstractSequentialList implements List, Deque, Cloneable, Serializable

没有提供像ArrayList​(int initialCapacity)构造一个指定初始容量的列表。为啥?基于链表,不需要。
类型不限制,可存储为null,且元素是在最后一个元素增加。性能快。

ArrayList与LinkedList区别?

  • ArrayList是数组实现的集合操作,而LinkedList是根据双向链表实现的集合操作;
  • 在使用List集合中的get()方法根据索引获取数据时,ArrayList的时间复杂度为S(0),而LinkedList的时间复杂度为S(N),N为集合的长度。简而言之,ArrayList与LinkedList 相比,查询和修改值比较快,但是增删速度比较快。
  • ArrayList在使用默认初始化对象数组的大小长度是10,如果空间不足会采用2倍的形式进行容量的扩充,如果保存大数据量的时候有可能会造成垃圾的产生以及性能的下降,但是这个时候可以使用LinkedList的子类保存。
java.util.Vector

public class Vector extends AbstractList implements List, RandomAccess, Cloneable, Serializable

是一个原始古老的程序类。 Vector和ArrayList一样,都是通过数组实现的,但是Vector是线程安全的。和ArrayList相比,其中的很多方法都通过同步(synchronized)处理来保证线程安全。
如果你的程序不涉及到线程安全问题,那么使用ArrayList是更好的选择(因为Vector使用synchronized,必然会影响效率)。
二者之间还有一个区别,就是扩容策略不一样。在List被第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。

Set集合

java.util.Set接口

Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。

有序集合:public interface Set<E> extends Collection<E>

注意:是Set集合并不像List集合扩充了许多新的方法,所以无法使用List获取指定元素的方法public E get​(int index)

二个常用子类:

  • java.util.HashSet
  • java.util.LinkedHashSet:
  • java.util.TreeSet:
java.util.HashSet

HashSet有以下特点

  • 不能保证元素的排列顺序,顺序有可能发生变化
  • 不是同步的
  • 集合元素可以是null,但只能放入一个null

当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

java.util.LinkedHashSet

LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

java.util.TreeSet

TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法

public class TreeSet extends AbstractSet implements NavigableSet, Cloneable, Serializable

自定义类排序时,自定义类必须实现Comparable接口,实现方法
如果自定义类属性有很多呢?这种情况下首选HashSet实现,使用hashCode(对象编码)以及equals(对象比较)来比较。

集合输出

Iterator迭代输出

该方式适用于Collection的所有子类。 使用频率比重高。

方法语义
boolean hasNext()判断迭代中是否有下一个元素。
E next()返回迭代中的下一个元素。
default void remove()底层集合中移除此迭代器返回的最后一个元素。

Java 中的 Iterator 功能比较简单,并且只能单向移动:

  • 使用方法 iterator() 要求容器返回一个 Iterator。第一次调用 Iterator 的 next() 方法时,它返回序列的第一个元素。注意:iterator() 方法是 java.lang.Iterable 接口,被 Collection 继承。
  • 使用 next() 获得序列中的下一个元素。
  • 使用 hasNext() 检查序列中是否还有元素。
  • 使用 remove() 将迭代器新返回的元素删除。

foreach

该方式适用于Collection的所有子类。 使用频率比重一般。

ListIterator双向迭代接口

仅适用于List接口的子类。使用频率比重极低。
Iterator输出特点:只能够由前向后进行内容的迭代处理,而如果要想进行双向迭代,那么就必须依靠Iterator的子接口:ListIterator来实现。

hasPrevious():判断是否有上一个元素
previous():取得上一个元素
listIterator():取得ListIterator接口对象

如果要想由后向前遍历,只能先执行由前向后遍历。


List<String> list = new ArrayList<>();
list.add("Hello");
list.add("HaHa");
list.add("HeHe");
ListIterator<String> listIterator = list.listIterator();
System.out.println("从后往前输出");
while (listIterator.hasNext()) {//判断是否有下一个元素System.out.println(listIterator.next()+"、");//取得下一个元素
}
System.out.println("\r\n从后往前输出");
while (listIterator.hasPrevious()) {//判断是否有上一个元素System.out.println(listIterator.previous()+"、");//取得上一个元素
}

Enumeration

仅适用于Vector类。

hasMoreElements():判断是否有下一个元素
nextElement():取得下一个元素
elements():取得Enumeration的接口对象

Map集合

特点:

  • Map用于保存具有"映射关系"的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value
  • key和value都可以是任何引用类型的数据。
  • Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较结果总是返回false。

关于Map,我们要从代码复用的角度去理解,java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合。
Map的这些实现类和子接口中key集的存储形式和Set集合完全相同(即key不能重复)
Map的这些实现类和子接口中value集的存储形式和List非常类似(即value可以重复、根据索引来查找)

1.HashMap和Hashtable的效率大致相同,因为它们的实现机制几乎完全一样。但HashMap通常比Hashtable要快一点,因为Hashtable是线程同步的,不过该类(Hashtable)是个古老类,建议使用ConcurrentHashMap代替 Hashtable
2. TreeMap通常比HashMap、Hashtable要慢(尤其是在插入、删除key-value对时更慢),因为TreeMap底层采用红黑树来管理key-value对
3. 使用TreeMap的一个好处就是: TreeMap中的key-value对总是处于有序状态,无须专门进行排序操作。

方法语义
V put​(K key, V value)将指定的值与此映射中的指定键相关联
V get​(Object key)返回指定键映射到的值,或者null此映射是否不包含键的映射。
Set<Map.Entry<K,​V>> entrySet()返回Set此映射中包含的映射的视图。
boolean containsKey​(Object key)是否存在指定key。
boolean containsValue​(Object value)是否存在指定value
Set<K> keySet()集合的key转为Set。
V remove​(Object key)移除指定key项的值

java.util.HashMap

和HashSet集合不能保证元素的顺序一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准也是: 两个key通过equals()方法比较返回true、同时两个key的hashCode值也必须相等。
任何null对象都可以用作键或值,不论key或value都可以为null。

put的使用
put(“A”, 1);//key不重复返回null。
put(“A”, 2);//key重复返回1旧值。

初始化容量为16个,容量扩充是(当前容量*0.75),初始化即12时进行成倍扩充容量数。

java.util.LinkedHashMap

LinkedHashMap也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序进行区
分)

java.util.HashTable

是一个古老的Map实现类。Hashtable是同步的。如果不需要线程安全的实现,建议使用它来 HashMap代替Hashtable。如果需要线程安全的高度并发实现,则建议使用ConcurrentHashMap代替 Hashtable。
任何非null对象都可以用作键或值,即不允许null对象的数据,不论key或value。

java.util.TreeMap

TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。同样,TreeMap也有两种排序方式: 自然排序定制排序
key不允许为null,因为需要依赖于接口对象中的compareTo(或compare)方法执行比较

java.util.Map.Entry接口

集合工具类

Stack栈

Stack是Vector提供的一个子类,用于模拟"栈"这种数据结构(LIFO后进先出)

public class Stack extends Vector
Deques也可以用作LIFO(后进先出)堆栈。应优先使用此接口,而不是遗留Stack类。当deque用作堆栈时,元素将从双端队列的开头推出并弹出。

方法语义
public boolean empty()测试此堆栈是否为空。
public E peek()查看此堆栈顶部的对象,而不将其从堆栈中删除。
public E pop()移除此堆栈顶部的对象,并将该对象作为此函数的值返回。
public E push​(E item)将项目推到此堆栈的顶部。
public int search​(Object o)返回对象在此堆栈上的从1开始的位置。

Queue队列

Queue用于模拟"队列"这种数据结构(先进先出FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。结合生活中常见的排队就会很好理解这个概念。
注意:LinkedList也实现了Queue。
优先级队列:PriorityQueue 优先级队列的元素根据其 自然顺序排序,或者根据使用的Comparator 构造函数在队列构造时提供。请注意,此实现不同步。PriorityQueue 如果任何线程修改队列,则 多个线程不应同时访问实例。相反,使用线程安全PriorityBlockingQueue类。
java队列——queue详细分析:https://www.cnblogs.com/lemon-flm/p/7877898.html

Deque接口及其实现提供了更完整和一致的LIFO堆栈操作集,应该优先使用该类。例如:
Deque stack = new ArrayDeque();

java.util.Properties属性操作

Properties 继承于 Hashtable.表示一个持久的属性集.属性列表中每个键及其对应值都是一个字符串,且该类是线程安全的
Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。主要用于读取配置信息。

类结构:
public class Properties extends Hashtable<Object,​Object>
注意:因为Properties继承自Hashtable,所以 put和putAll方法可以应用于 Properties对象。强烈建议不要使用它们,因为它们允许调用者插入其键或值不是的条目 Strings。

方法语义
public void load​(InputStream inStream) throws IOException从输入字节流中读取属性列表(键和元素对)。
public void loadFromXML​(InputStream in) throws IOException, InvalidPropertiesFormatException将指定输入流上的XML文档表示的所有属性加载到此属性表中。
public void storeToXML​(OutputStream os, String comment) throws IOException发出表示此表中包含的所有属性的XML文档。
public String getProperty​(String key, String defaultValue)搜索具有指定键的属性。
public Object setProperty​(String key, String value)设置指定键的属性,调用Hashtable方法put。

Java关于Properties用法的总结(一):https://www.cnblogs.com/bakari/p/3562244.html
java读取properties文件总结:http://www.cnblogs.com/xdp-gacl/p/3640211.html

java.util.Collections工具类

Java中Collection和Collections的区别 https://www.cnblogs.com/cathyqq/p/5279859.html
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

public class CollectionsTest {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>();list.add(34);list.add(55);list.add(56);list.add(89);list.add(12);list.add(23);list.add(126);System.out.println(list);//对集合进行排序Collections.sort(list);System.out.println(list);//对集合进行随机排序Collections.shuffle(list);System.out.println(list);//获取集合最大值、最小值int max = Collections.max(list);int min = Collections.min(list);System.out.println("Max:" + max + " Min: " + min);List<String> list2 = Arrays.asList("Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday".split(","));System.out.println(list2);//查找集合指定元素,返回元素所在索引//若元素不存在,n表示该元素最有可能存在的位置索引int index1 = Collections.binarySearch(list2, "Thursday");int index2 = Collections.binarySearch(list2, "TTTTTT");System.out.println(index1);int n = -index2 - 1;//查找子串在集合中首次出现的位置List<String> subList = Arrays.asList("Friday,Saturday".split(","));int index3 = Collections.indexOfSubList(list2, subList);System.out.println(index3);int index4 = Collections.lastIndexOfSubList(list2, subList);System.out.println(index4);//替换集合中指定的元素,若元素存在返回true,否则返回falseboolean flag = Collections.replaceAll(list2, "Sunday", "tttttt");System.out.println(flag);System.out.println(list2);//反转集合中的元素的顺序Collections.reverse(list2);System.out.println(list2);//集合中的元素向后移动k位置,后面的元素出现在集合开始的位置Collections.rotate(list2, 3);System.out.println(list2);//将集合list3中的元素复制到list2中,并覆盖相应索引位置的元素List<String> list3 = Arrays.asList("copy1,copy2,copy3".split(","));Collections.copy(list2, list3);System.out.println(list2);//交换集合中指定元素的位置Collections.swap(list2, 0, 3);System.out.println(list2);//替换集合中的所有元素,用对象objectCollections.fill(list2, "替换");System.out.println(list2);//生成一个指定大小与内容的集合List<String> list4 = Collections.nCopies(5, "哈哈");System.out.println(list4);//为集合生成一个EnumerationList<String> list5 = Arrays.asList("I love my country!".split(" "));System.out.println(list5);Enumeration<String> e = Collections.enumeration(list5);while (e.hasMoreElements()) {System.out.println(e.nextElement());}}
}
方法语义
Collections.sort(list) //list: 1 2 4 5 6 7 8list升序。
Collections.sort(list,Collections.reverseOrder())//list:8 7 6 5 4 2 1list降序。
Collections.reverse(list)//list:4 1 8 6 2 7 5list逆序。
Arrays.sort(a)//a: 1 2 4 5 6 7 8数组升序。
Arrays.sort(a,Collections.reverseOrder())//a: 8 7 6 5 4 2 1数组降序。

这篇关于Java基础回顾系列-第六天-Java集合的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1148487

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]