一、Java 集合框架

0、介绍:

(0)什么是集合

-集合与数组一样,可以保存一组元素,并且提供了操作元素的相关方法,使用更方便.

(1)集合框架被设计成要满足以下几个目标:

  • 该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
  • 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
  • 对一个集合的扩展和适应必须是简单的。

为此,整个集合框架就围绕一组标准接口而设计。你可以直接使用这些接口的标准实现,诸如: LinkedList, HashSet, 和 TreeSet 等,除此之外你也可以通过这些接口实现自己的集合。


从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。

(2)集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:

接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。

除了集合,该框架也定义了几个 Map 接口和类。Map 里存储的是键/值对。尽管 Map 不是集合,但是它们完全整合在集合中。

(3)集合框架体系如图所示:

(4)java集合框架中相关接口:

-java.util.Collection接口:

java.util.Collection是所有集合的顶级接口.Collection下面有多种实现类,因此我们有更多的数据结构可供选择.

-Collection类下面有两个常见的子接口:

  • java.util.List:线性表.是可重复集合,并且有序.
  • java.util.Set:不可重复的集合,大部分实现类是无序的.

-这里可重复指的是集合中的元素是否可以重复,而判定重复元素的标准是依靠元素自身equals比较的结果.为true就认为是重复元素.

1.Collection 接口:
Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。
Collection 接口存储一组不唯一,无序的对象。2.List 接口:
List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。List 接口存储一组不唯一,有序(插入顺序)的对象。3.Set:
Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。
Set 接口存储一组唯一,无序的对象。Set和List的区别:
1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。

1、ArrayList 类

是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
-ArrayList 继承了 AbstractList ,并实现了 List 接口。

ArrayList 类位于 java.util 包中,使用前需要引入它,语法格式如下:

import java.util.ArrayList; //引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>();  //初始化

E: 泛型数据类型,用于设置 objectName 的数据类型,只能为引用数据类型。
objectName: 对象名。

ArrayList 是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
-ArrayList类提供了很多有用的方法:

1:add()方法:添加元素
2:size()方法:如果要计算ArrayList中的元素数量
3:isEmpty()方法:判断当前集合是否为一个空集
4:clear()方法:删除Arraylist中的所有元素
《CollectionDemo.java》:package collection;
import java.util.ArrayList;
import java.util.Collection;
/*** JAVA集合框架* 集合和数组一样,可以保存一组元素,但是集合将元素的操作都封装成了方法,操作简便。* 并且集合提供了多种不同的实现供我们使用。** java.util.Collection是所有集合的顶级接口,里面定义了所有集合都必须具备的功能方法* 集合有两类常用的子类:* java.util.List:可重复的集合,且有序。通常我们称它为"线性表"* java.util.Set:不可重复的集合。* 上述两个都是接口,而元素是否重复取决于元素自身的equals方法,即:Set集合中不会存在* 两个元素equals比较为true的情况。**/
public class CollectionDemo {public static void main(String[] args) {//集合只能存放引用类型:Collection c = new ArrayList();/*1:添加元素ArrayList类提供了很多有用的方法,添加元素到 ArrayList 可以使用add() 方法:boolean add(E e)  E: 泛型数据类型,用于设置 objectName 的数据类型,只能为引用数据类型。向当前集合中添加一个元素,当元素成功添加则返回true,否则返回false*/c.add("one");//add:加c.add("twe");c.add("three");c.add("four");c.add("five");System.out.println(c);
//        c.add(123);//会触发自动装箱特性/*2:计算ArrayList中的元素数量可以使用size()方法:int size()返回当前集合的元素个数*/int size = c.size();//size:尺寸,大小System.out.println("size:"+size);/*3:判断当前集合是否为一个空集boolean isEmpty()判断当前集合是否为一个空集(不含有任何元素),当size为0时,返回true*/boolean isEmpty = c.isEmpty();//empty:空的System.out.println("是否为空集:"+isEmpty);/*4:删除Arraylist中的所有元素void clear()*/System.out.println(c);c.clear();System.out.println(c);System.out.println("size:"+c.size());//0System.out.println("是否为空集:"+c.isEmpty());}
}

2、集合与元素equals方法相关的方法

《Point.java》:package collection;
import java.util.Objects;
/*** 使用当前类作为集合元素测试集合相关操作*/
public class Point {private int x;private int y;public Point(int x, int y) { //alt+insert:构造方法:与类同名 没有返回值类型,连void都没有this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}//alt+insert 选择toString():@Overridepublic String toString() {return "Point{" +"x=" + x +", y=" + y +'}';}//alt+insert 选择equals() and hashCode()后,返回为true@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Point point = (Point) o;return x == point.x && y == point.y;}@Overridepublic int hashCode() {return Objects.hash(x, y);}
}《CollectionDemo2.java》:package collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/*** 元素会影响集合操作的相关方法*/
public class CollectionDemo2 {public static void main(String[] args) {//        Collection c = new ArrayList();Collection c = new HashSet();//(1)不可重复的集合c.add(new Point(1,2));c.add(new Point(3,4));c.add(new Point(5,6));c.add(new Point(7,8));c.add(new Point(9,10));c.add(new Point(1,2));//(1)因为HashSet(HashSet中的元素实际上是对象) 所以重复元素无法放入Set集合两次!/*集合重写了toString方法,格式为:[元素1.toString(), 元素2.toString(), 元素3.toString(),.......]*/System.out.println(c);//在《Point.java》中按alt+insert,选择equals() and hashCode()后,下面返回为truePoint p = new Point(1,2);/*contains()方法:来判断元素是否存在于集合当中:boolean contains(Object o)判断当前集合是否包含给定元素。元素是否包含取决于该元素是否与集合现有元素存在equals比较为true的情况*/boolean contains = c.contains(p);System.out.println("是否包含该元素:"+contains);/*remove()方法来删除集合中的元素:remove()方法删除元素时也是删除*/c.remove(p);//只会删除第一个匹配的重复元素System.out.println(c);}
}

3、集合存放的是元素的引用

-集合只能存放引用类型元素,并且存放的是元素的引用

《CollectionDemo3.java》:package collection;
import java.util.ArrayList;
import java.util.Collection;
/*** 集合只能存放引用类型元素,并且存放的是元素的引用(地址)*/
public class CollectionDemo3 {public static void main(String[] args) {Collection c = new ArrayList(); //c为局部变量Point p = new Point(1,2);c.add(p);//将p元素放入集合System.out.println("p:"+p);//(1,2)System.out.println("c:"+c);//[(1,2)]p.setX(2);//将p对象中的x属性修改为2System.out.println("p:"+p);//(2,2)System.out.println("c:"+c);//[(2,2)]}
}
  • 1、集合间的操作
    (1)判断当前集合c1是否包含给定集合c3中的所有元素:boolean containsAll(Collection c)
    (2)取交集:c1.retainAll(c3);(仅保留c1中包含c3的元素)
    (3)删除交集:c1.remove(c3);(将c1中与c3的共有元素删除(c3不受影响))

  • 2、HashMap遍历(集合的遍历):-------Iterator迭代器
    (1)创建一个集合
    (2)获取迭代器,通过iterator方法。
    (3)使用具体的迭代器对象获取集合中的元素。参阅迭代器的方法:

  • 3、增强型for循环遍历集合:

  • 4、Java LinkedList:

  • 4.1、接口 List集
    (1)List集
    ①java.util.ArrayList:内部使用数组实现,查询性能更好。
    ②java.util.LinkedList:内部使用链表实现,增删
    (2)List集合常见方法--------get()与set():

  • 5、List重载了一对add、remove方法:
    (1)将给定元素插入到指定位置:void add(int index,E e)
    (2)删除并返回指定位置上的元素:E remove(int index)

  • 6、List集合提供的方法之---------subList()方法
    (1)获取子集[3-7] 注意:含头不含尾
    (2)将子集每个元素扩大十倍
    (3)清除集合中1-8这部分元素----clear()

  • 7、集合与数组的转换
    (1)集合转换为数组:

  • 8、变长参数

  • 9、数组转换为List集合-----asList()

  • 10、集合的排序-------sort
    (1)对List集合进行自然排序。
    (2)排序自定义类型元素
    (3)对字符串进行排序

  • 11、补充------redis是作用持久层的缓存型数据库 (非关系型数据库)
    (1)redis的五种数据类型以及应用场景:

1、集合间的操作

补充:
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。
————————————————
(0)addall()方法:
①addAll() 方法将给定集合中的所有元素添加到 arraylist 中
②语法:arraylist.addAll(int index, Collection c)
注:arraylist 是 ArrayList 类的一个对象。
③参数说明:
-index(可选参数)表示集合元素插入处的索引值
-c要插入的集合元素
----------如果 index 没有传入实际参数,元素将追加至数组的最末尾。
④返回值:
如果成功插入元素,返回 true。
如果给定的集合为 null,则超出 NullPointerException 异常。
注意:如果 index 超出范围,则该方法抛出 IndexOutOfBoundsException 异常。

  • 例:c1.addAll(c2); //把c2的所有元素添加到c1中;因为该方法没有传入可选参数 index,所以元素将追加至数组的最末尾。

(1)判断包含子集:boolean containsAll(Collection c)
(2)取交集:c1.retainAll(c3);(仅保留c1中包含c3的元素)
(3)删除交集:c1.remove(c3);(将c1中与c3的共有元素删除(c3不受影响))

package collection;
import java.util.ArrayList;
import java.util.Collection;
/*** 集合间的操作*/
public class CollectionDemo04 {public static void main(String[] args) {Collection c1 = new ArrayList();c1.add("java");c1.add("c++");c1.add(".net");System.out.println("c1:"+c1);//c1:[java, c++, .net]Collection c2 = new ArrayList();c1.add("android");c1.add("ios");c1.add("java");System.out.println("c2:"+c2);//c2:[]/*0、addAll()方法:将给定集合中(c2)的所有元素添加到 arraylist(c1) 中。*/c1.addAll(c2);System.out.println("c1:"+c1);//c1:[java, c++, .net, android, ios, java]System.out.println("c2:"+c2);//c2:[]Collection c3 = new ArrayList();c3.add("c++");c3.add("ios");
//        c3.add("php");System.out.println("c3:"+c3);//c3:[c++, ios]/*1、判断当前集合c1是否包含给定集合c3中的所有元素:boolean containsAll(Collection c)*/boolean containsAll = c1.containsAll(c3);System.out.println("包含所有:"+containsAll);//包含所有:true/*/2、取交集:c1.retainAll(c3);(仅保留c1中包含c3的元素)*/c1.retainAll(c3);System.out.println("c1:"+c1);//c1:[c++, ios]System.out.println("c3:"+c3);//c3:[c++, ios]/*3、删除交集:c1.remove(c3);将c1中与c3的共有元素删除(c3不受影响)*/c1.remove(c3);System.out.println("c1:"+c1);//c1:[c++, ios]System.out.println("c3:"+c3);//c3:[c++, ios]}
}

2、HashMap遍历(集合的遍历):-------Iterator迭代器

java中提供了很多个集合,它们在存储元素时,采用的存储方式不同。我们要取出这些集合中的元素,可通过一种通用的获取方式来完成。

Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

-Iterator 迭代器有:
-①hasNext()方法:用来判断集合中是否有下一个元素可以迭代。如果返回true,说明可以迭代。

-②Next()方法:用来返回迭代的下一个元素,并把指针向后移动一位。

图解:

-Collection接口描述了一个抽象方法iterator方法,所有Collection子类都实现了这个方法,并且有自己的迭代形式。

(1):Collection提供了统一的遍历集合方式:迭代器模式Iterator iterator():该方法会获取一个用于遍历当前集合元素的迭代器.(2):java.util.Iterator接口
1)迭代器接口,定义了迭代器遍历集合的相关操作.
2)不同的集合都实现了一个用于遍历自身元素的迭代器实现类,我们无需记住它们的名字,用多态的角度把他们看做为Iterator即可.
3)迭代器遍历集合遵循的步骤为:问,取,删.其中删除元素不是必要操作

!例:迭代器遍历过程中不得通过集合的方法增删元素!
因此迭代器提供了remove()方法

《IteratorDemo.java》:package collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*** 集合的遍历:* Collection层面上不支持随机访问操作(根据指定的位置获取对应元素)。* 但是集合支持遍历操作,我们可以通过遍历最终拿到每一个元素。* 集合提供了统一的遍历方式:迭代器模式* * Iterator iterator():* 该方法会返回一个用于遍历当前集合元素的迭代器** java.util.Iterator是迭代器接口,规定了迭代器遍历集合的基本操作,不同的集合都提供* 了一个用于遍历自身元素的迭代器实现类,我们无需记住他们的名字,用多态的方式当成Iterator使用即可。* * 迭代器遍历集合遵循的步骤:问->取->删。* 其中删除不是必须操作。*/
public class IteratorDemo {public static void main(String[] args) {//1.创建一个集合Collection c = new ArrayList();c.add("one");c.add("#");c.add("two");c.add("#");c.add("three");c.add("#");c.add("four");c.add("#");c.add("five");System.out.println(c);//[one, two, three, four, five]//2.获取迭代器,通过iterator方法Iterator it = c.iterator();//3.使用具体的迭代器对象获取集合中的元素。参阅迭代器的方法:/*迭代器提供的相关方法:(1)boolean hasNext():判断集合是否还有“下一个”元素可以遍历。迭代期的起始位置可以理解为是集合第一个元素位置之前。因此第一次调用hasNext()就是判断集合是否有第一个元素。(2)E next():获取集合中“下一个元素”。获取后迭代器的位置会向后移动一个元素位置。*/while(it.hasNext()){ //it.hasNext();:有没有下一个    调用hasNext()方法不会往下走String e = (String) it.next();System.out.println(e);//one two three four fiveif("#".equals(e)){/*(1)迭代器在遍历的过程中不能通过集合的方法增删元素,否则会抛出 并发修改异常:ConcurrentModificationException(2)但迭代器提供了remove()方法:可以将本次通过next方法获取的元素从集合中删除*/
//                c.remove(e);//remove():集合的删除元素方法it.remove();}}System.out.println(c);}
}

3、增强型for循环遍历集合:

Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素。

JDK5之后推出了一个特性:增强型for循环:
---------------也称为新循环,使得我们可以使用相同的语法遍历集合或数组.

(1)-语法格式:

for(元素的数据类型 变量名 : 需要遍历的Collection集合or数组){循环体
}

(2)增强for循环和老式的for循环有什么区别?
注意:新for循环必须有被遍历的目标。目标只能是Collection集合或者是数组。
建议:遍历数组时,如果仅为遍历,可以使用增强for循环。如果要对数组的元素进行操作,使用老式for循环可以通过角标操作。

(1)JDK5之后推出了一个特性:增强型for循环,
也称为新循环,使得我们可以使用相同的语法遍历集合或数组。
--语法格式:
for(元素的数据类型 变量名 : Collection集合or数组){循环体
}(2)JDK5之后推出的另一个特性:泛型
泛型也称为参数化类型,允许我们在使用一个类时指定它当中属性,方法参数或返回值的类型.
---泛型在集合中被广泛使用,用来指定集合中的元素类型.
---有泛型支持的类在使用时若不指定泛型的具体类型则默认为原型Object
《NewForDemo.java》:package collection;
import java.sql.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*** JDK5推出时,推出了一个新的特性:增强型for循环* 通常也称它为新循环。* 新循环不取代传统for循环的工作,它可以用相同的语法遍历集合或数组。* 语法:for(元素类型 e : 集合或数组){....}** 新循环是java编译器认可的,并非虚拟机。*/
public class NewForDemo {public static void main(String[] args) {String[] array = {"one","two","three","four","five"};for(int i=0;i<array.length;i++){String s = array[i];System.out.println(s);}//新循环在遍历数组时,会被编译器改回成传统for循环for(String s : array){ //冒号(:)后面是要遍历的数组System.out.println(s);}/*JDK5之后推出的另一个特性:泛型泛型也称为参数化类型,它的原型就是Object,泛型的目的是让我们将定义的Object类型当做什么看待。例如下面的集合中保存的每个元素都是用Object接收的,但是集合将它改成了E类型这样一来,我们在使用集合时可以告知集合应当将E当做什么类型看待。例如:下面的集合中保存的每个元素都是用Object接收的,但是集合将它改成了E类型这样一来,我们在使用集合时可以告知集合应当将E当做什么类型看待。public class XXX{public Object xx;}XXX o = new XXX();o.xx = 任何类型的值;泛型的写法://E: 泛型数据类型,用于设置 objectName 的数据类型,只能为引用数据类型。public class XXX<E>{public E xx;}XXX<String> o = new XXX<>();o.xx = "abc";*//**1.创建集合对象。:*/Collection<String> c = new ArrayList<>();c.add("一");//编译器会检查传入的E对应的实参是否为E指定的实际类型c.add("二");c.add("三");c.add("四");c.add("五");
//        c.add(1);//当实参不符合 E指定的实际类型(此处1为E指定的实际类型) 时,编译不通过//新循环遍历集合本身就是迭代器,编译器会将其改回成迭代器遍历:for(String str : c){变量str 代表被遍历到的数组元素System.out.println(str);}/**2.获取容器的迭代器对象。通过iterator方法。*///由上面的for循环被编译器改回成下面的样子:Iterator<String> it = c.iterator();/**3.想要用迭代器删除元素不能使用集合的方式(remove();),--要使用具体的迭代器对象获取集合中的元素。-参阅迭代器的方法要写成下面迭代器的样子再用(it.remove())删:*/while(it.hasNext()){String str = it.next();//当使用Iterator<String>控制元素类型后,就不需要强转了。-//-获取到的元素直接就是String类型System.out.println(str);}}
}

4、Java LinkedList:

(1)链表(Linked list):
是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是**在每一个节点里存到下一个节点的地址**

(2)链表可分为单向链表和双向链表:
①一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接。

②一个双向链表有三个整数值: 数值、向后的节点链接、向前的节点链接。

-Java LinkedList(链表) 类似于 ArrayList,是一种常用的数据容器。
-与 ArrayList 相比,LinkedList 的增加和删除的操作效率更高,而查找和修改的操作效率较低。

(3)何时使用ArrayList 或 LinkedList:
1)以下情况使用 ArrayList :

①频繁访问列表中的某一个元素。
②只需要在列表末尾进行添加和删除元素操作。

2)以下情况使用 LinkedList :
①需要通过循环迭代来访问列表中的某些元素。
②需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。

(4)LinkedList 继承了什么?
LinkedList 继承了 AbstractSequentialList 类。
LinkedList 实现了 Queue 接口,可作为队列使用。
LinkedList 实现了 List 接口,可进行列表的相关操作。
LinkedList 实现了 Deque 接口,可作为队列使用。
LinkedList 实现了 Cloneable 接口,可实现克隆。
LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

4.1、接口 List集

(1)List集-java.util.List接口,继承自Collection.
-List集合是可重复集,并且有序,提供了一套可以通过下标操作元素的方法。
-常用实现类:
1)java.util.ArrayList:内部使用数组实现,查询性能更好。

2)java.util.LinkedList:内部使用链表实现,增删性能更好,首尾增删性能最佳。
-语法格式:

// 引入 LinkedList 类
import java.util.LinkedList; LinkedList<E> list = new LinkedList<E>();//普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c);//使用集合创建链表

(2)List集合常见方法--------get()与set():
例子:

《ListDemo.java》:package collection;
import java.util.*;
/*** java.util.List接口* List继承自Collection,是最常用的一类集合。特点:可以存放重复元素且有序。* List里提供了一套可以通过下标操作元素的方法。** 常用实现类:* java.util.ArrayList:内部使用数组实现,查询性能更好。* java.util.LinkedList:内部使用链表实现,增删性能更好,首尾增删性能最佳。* 对性能没有特别苛刻的要求下,通常使用ArrayList即可。*/
public class ListDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();//对性能没有特别苛刻的要求下,通常使用ArrayList即可。
//        List<String> list = new LinkedList<>();list.add("one");list.add("two");list.add("three");list.add("four");list.add("five");System.out.println(list);//[one, two, three, four, five]/*1、(1)获取指定下标处对应的元素:E get(int index)*///获取集合中第三个元素:String str = list.get(2);//与数组获取元素功能一致→ String str = arr[2];System.out.println(str);//three//(2)List也可以通过循环下标的方式遍历:for(int i=0;i<list.size();i++){str = list.get(i);System.out.println(str);}/*2、替换元素操作:E set(int index,E e)将给定元素设置到指定位置上,返回值为该位置原来的元素*/String old = list.set(1,"six");//将第二个下标位置原来的two返回为sixSystem.out.println(list);//[one, six, three, four, five]System.out.println(old);//two//3、(1)在不创建新集合的前提下,将集合元素翻转:for(int i=0;i<list.size()/2;i++){ //i:0/*分解动作:和下面一句相同//获取正数位置上的元素String e = list.get(i);//one//将正数位置上的元素来替换倒数位置上的元素:e = list.set(list.size()-1-i,e);//five//将原倒数位置上的元素设置到正数位置上list.set(i,e);*/list.set(i,list.set(list.size()-1-i,list.get(i)));}System.out.println(list);//3、(2)颠倒数组中元素的顺序://还可以用 【Collections.reverse();】方法来翻转集合:(与上面for循环功能相同!)//reverse()方法用于颠倒数组中元素的顺序。Collections.reverse(list);//Collection是最基本的集合接口  reverse:翻转System.out.println(list);}
}

5、List重载了一对add、remove方法:

(1)将给定元素插入到指定位置:void add(int index,E e)
(2)删除并返回指定位置上的元素:E remove(int index)

《ListDemo2.java》:package collection;
import java.util.ArrayList;
import java.util.List;/*** List重载了一对add,remove方法** 重载:* 发生在同一类中,方法名相同,参数不同,* 是完全不同的方法,只是方法名相同而已,* 对于返回值类型并没有要求。*/
public class ListDemo2 {public static void main(String[] args) {List<String> list = new ArrayList<>();//对性能没有特别苛刻的要求下,通常使用ArrayList即可。
//        List<String> list = new LinkedList<>();list.add("one");list.add("two");list.add("three");list.add("four");list.add("five");System.out.println(list);//[one, two, three, four, five]/*1、将给定元素插入到指定位置:void add(int index,E e)*///[one, two, three, six, four, five]list.add(3,"six");System.out.println(list);/*2、删除并返回指定位置上的元素:E remove(int index)*/String old = list.remove(2);System.out.println(list);//[one, two, six, four, five]System.out.println(old);//three}
}

6、List集合提供的方法之---------subList()方法

-----------获取当前集合中指定范围内的子集:List subList(int start,int end)
(1)获取子集[3-7] 注意:含头不含尾
(2)将子集每个元素扩大十倍
(3)清除集合中1-8这部分元素----clear()

《ListDemo3.java》:package collection;
import java.util.ArrayList;
import java.util.List;
/*** List集合提供的方法之:* 获取当前集合中指定范围内的子集:* List subList(int start,int end)**/
public class ListDemo3 {public static void main(String[] args) {//<E>:泛型 智能指定引用型数据 不能为int(为基本数据类型) 所以写IntegerList<Integer> list = new ArrayList<>();for(int i=0;i<10;i++){list.add(i);}System.out.println(list);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]//1、获取子集[3-7] 注意:含头不含尾List<Integer> subList = list.subList(3,8);System.out.println("sub:"+subList);//sub:[3, 4, 5, 6, 7]//2、将子集每个元素扩大十倍for(int i=0;i<subList.size();i++){/*对子集的操作就是对原集合对应元素的操作*//*第一种方法:int num = subList.get(i);num = num * 10;subList.set(i,num);*///第二种方法:subList.set(i,subList.get(i)*10);System.out.println("sub:"+subList);}System.out.println(list);//3、清除集合中1-8这部分元素----clear()list.subList(1,9).clear();//.clear();:清空集合System.out.println(list);}
}

7、集合与数组的转换

(1)集合转换为数组:

Collection提供了一个方法:toArray,可以将当前集合转换为一个数组:

《CollectionToArrayDemo.java》:package collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/*** 集合都可以转换为数组* Collection定义了方法toArray可以将一个集合转换为一个数组*/
public class CollectionToArrayDemo {public static void main(String[] args) {Collection<String> c = new ArrayList<>();c.add("one");c.add("two");c.add("three");c.add("four");c.add("five");System.out.println(c);//        Object[] array = c.toArray();//不常用了/*重载的toArray方法要求传入一个数组,内部会将集合所有元素存入该数组后将其返回(前提是该数组长度>=集合的size)。如果给定的数组长度不足,则方法内部会自行根据给定数组类型创建一个与集合size一致长度的数组并将集合元素存入后返回。*/String[] array = c.toArray(new String[c.size()]);//获取数组的长度System.out.println(array.length);System.out.println(Arrays.toString(array));//Arrays:数组的工具类 打印的时候把地址转换为数组}
}

8、变长参数

JDK5时推出的另一个特性:变长参数

一个方法中只能声明一个变长参数,并且必须是最后一个参数

《ArgDemo.java》:package collection;
import java.util.Arrays;
public class ArgDemo {public static void main(String[] args) {dosome(1,"a");dosome(1,"a","b");dosome(1,"a","b","a","b","a","b","a","b","a","b");dosome(1,new String[]{"1","2","3"});}public static void dosome(int i,String... s){/*变长参数在方法中实际上就是一个数组.给变长参数传入了几个实参,该数组长度与实参个数一致.*/System.out.println(s.length);System.out.println("s:"+ Arrays.toString(s));}
}

9、数组转换为List集合-----asList()

----------数组的工具类Arrays提供了一个静态方法asList,可以将一个数组转换为一个List集合

《ArrayToListDemo.java》:package collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/*** 数组转换为List集合* 数组的工具类Arrays提供了一个静态方法asList,可以将一个数组转换为一个List集合*/
public class ArrayToListDemo {public static void main(String[] args) {String[] array = {"one","two","three","four","five"};System.out.println("Array:"+Arrays.toString(array));//Array:[one, two, three, four, five]List<String> list = Arrays.asList(array);//asList:将数组转换为集合System.out.println("List:"+list);//List:[one, two, three, four, five]/*1、数组跟着改变了。 !注意:对该集合的操作就是对原数组对应的操作:*/list.set(1,"six");//在list集合中设置下标为1的位置为six。System.out.println("修改后的集合List:"+list);//List:[one, six, three, four, five]System.out.println("修改后的数组Array:"+ Arrays.toString(array));//Array:[one, six, three, four, five]/*例://list.add("seven");//会报不支持操作的异常由于数组是定长的,因此对该集合进行增删元素会导致对数组进行同等操作,这时会抛出异常:UnsupportedOperationExceptionUnsupported:不支持的Operation:操作*//*2、若有增删需求,则需另创一个集合,并先将数组转换的集合内容导入后方可进行。addAll():将数组中的所有元素添加到新创建的集合中。该方法没有传入可选参数--index。因此,所有元素都添加在动新创建的集合的末尾。*/
//        List<String> list2 = new ArrayList<>();//创建一个集合
//        list2.addAll(list);/*3、所有集合都支持一个参数为Collection的构造器,作用是在创建当前集合的同时包含给定集合中的所有元素*/List<String> list2 = new ArrayList<>(list);System.out.println("list2:"+list2);//list2:[one, six, three, four, five]list2.add("seven");System.out.println("list2:"+list2);//list2:[one, six, three, four, five, seven]}
}

10、集合的排序-------sort

(1)对List集合进行自然排序。

  • 集合的工具类java.util.Collections提供了一个静态方法sort,**只能对List集合**进行自然排序。
《SortListDemo.java》:package collection;
import java.util.*;
/*** 集合的排序:* 集合的工具类java.util.Collections提供了一个静态方法sort,* 可以对List集合进行自然排序。*/
public class SortListDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();Random random = new Random();for(int i=0;i<10;i++){list.add(random.nextInt(100));//输出100以内10个随机数}System.out.println(list);Collections.sort(list);//sort():可以对List集合进行自然排序。System.out.println(list);}
}

(2)排序自定义类型元素

1)Collections.sort(List list)在排序List集合时要求集合元素必须实现了Comparable(比较)接口。
实现了该接口的类必须重写一个方法:compareTo,用于定义比较大小的规则,从而进行元素间的比较后顺序。否则编译不通过。
例:Collections.sort(list);//编译不能通过侵入性:
当我们调用某个API时,其反过来要求我们为其修改其他额外的代码,这种现象就
成为侵入性。侵入性不利于程序后期的维护,尽可能避免。2)2、匿名内部类的形式创建一个比较器:注意:Comparator后要写泛型:<Point>有三种写法:着重Lambda!

-java的比较器有两类,分别是Comparable接口和Comparator接口。
-在为对象数组进行排序时,比较器的作用非常明显,首先来讲解Comparable接口。
-让需要进行排序的对象实现Comparable接口,重写其中的compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用java.util.Arrays.sort()来排序对象数组.

《SortListDemo2.java》:package collection;
import java.util.*;
/*** 排序自定义类型元素*/
public class SortListDemo2 {public static void main(String[] args) {List<Point> list = new ArrayList<>();list.add(new Point(1,2));list.add(new Point(97,88));list.add(new Point(7,6));list.add(new Point(9,9));list.add(new Point(5,4));list.add(new Point(2,3));System.out.println(list);/*1、Collections.sort(List list)在排序List集合时要求集合元素必须实现了Comparable(比较)接口。实现了该接口的类必须重写一个方法:compareTo,用于定义比较大小的规则,从而进行元素间的比较后顺序。否则编译不通过。侵入性:当我们调用某个API时,其反过来要求我们为其修改其他额外的代码,这种现象就成为侵入性。侵入性不利于程序后期的维护,尽可能避免。*/
//        Collections.sort(list);//编译不能通过/*2、匿名内部类的形式创建一个比较器:注意:Comparator后要写泛型:<Point>有三种写法:*//*第一种:Comparator<Point> com = new Comparator<Point>() {@Override//实现比较器接口后必须重写Compare()方法://该方法用来定义参数o1与参数o2的比较大小规则//返回值(return)用来表示o1与wo2的大小关系:public int compare(Point o1, Point o2) { //重写Compare()方法int len1 = o1.getX() * o1.getX() + o1.getY() * o1.getY();//x的平方加y的平方int len2 = o2.getX() * o2.getX() * o2.getY() * o2.getY();return len1 - len2;}};Collections.sort(list,com);//回调模式System.out.println(list);*//*第二种:Collections.sort(list,new Comparator<Point>() {public int compare(Point o1, Point o2) {int len1 = o1.getX() * o1.getX() + o1.getY() * o1.getY();int len2 = o2.getX() * o2.getX() * o2.getY() * o2.getY();return len1 - len2;}});Collections.sort(list,com);//回调模式System.out.println(list);*//*第三种:Lambda表达式方式。*/Collections.sort(list,(o1,o2)->o1.getX() * o1.getX() + o1.getX() * o1.getY() -o2.getX() * o2.getX() * o2.getY() * o2.getY());System.out.println(list);}
}

(3)对字符串进行排序-----大到小,小到大
-第二种:用Lambda表达式来写:
例:Collections.sort(list,(o1,o2) -> o1.length() - o2.length());

《SortListDemo3.java》:package collection;
import java.util.*;
/*** 排序字符串*/
public class SortListDemo3 {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("苍老师");list.add("小泽老师");list.add("范老师");list.add("大哥老师");list.add("大大大大老师");System.out.println(list);
//        Collections.sort(list);/**定义一个比较器,按照字多字少排序*//*//第一种方式:Comparator<String> com = new Comparator<String>() {@Override//实现比较器接口后必须重写Compare()方法://该方法用来定义参数o1与参数o2的比较大小规则//返回值(return)用来表示o1与o2的大小关系:public int compare(String o1, String o2) {if(o1.length() > o2.length()){return 1;}else if(o1.length() < o2.length()){return -1;}else{return 0;}}};Collections.sort(list,com);//回调模式*///!!!第二种:用Lambda表达式来写:Collections.sort(list,(o1,o2) -> o1.length() - o2.length());/*//第二种扩展:从大往小排(sort只能从小到大排):但是可以改变用来比较字符串值的顺序来完成Collections.sort(list,(o1,o2) -> o2.length() - o1.length());*//*//第三种:  注意:接口里边可以有方法!!Collections.sort(list,Comparator.comparingInt(String::length));//两个(::)的意思是:方法引用*/System.out.println(list);}
}

11、补充------redis是作用持久层的缓存型数据库 (非关系型数据库)

(1)redis的五种数据类型以及应用场景:

redis是作用持久层的缓存型数据库 -- 非关系型数据库
redis保存数据以key-value的形式保存数据
五种数据类型是指键值对中value的数据类型,key的类型就是String1)String:可以保存字符串数据,也可以实现高热度数据计数(统计)通过redis的命令可以操作字符串的value值,详情见文档需要知道的命令: incr key - 让key的value值增一可以用于高热度数据统计               2)hash:用于保存对象数据,特点是可以直接操作属性3)list:是字符串列表,元素有序 应用场景:微信点赞4)set:是String类型的无需集合,元素唯一存在应用场景:黑名单5)sortedSet:实现了排序的String类型的set集合,元素唯一存在,且排序如何实现排序的:为每个元素绑定分数,根据分数排序比如:" 2 tom "存入后,再次存入"3 tom" ,则集合中最终保存的是" 3 tom"应用场景:排行榜  -- 电影排行榜

list类型:

set类型:

一、Map接口—查找表

  • 1、HashMap :

  • 2、java.util.Map接口 查找表
    (1)创建一个HashMap对象map
    (2)向当前Map中保存一组键值对:v put(K k,V v)
    (3)根据指定的Key获取对应的value,如果给定的Key不存在,则返回值为null
    (4)返回当前Map中的元素个数
    (5)删除给定的key对应的这组键值对,返回值为这个key对应的value

  • 3、Map的3种遍历方式
    (1)
    ①遍历key:将当前Map中所有的key以一个Set集合形式返回:Set kaySet()
    ②遍历每一组键值对:Set entrySet()
    ③遍历value:将所有的value以一个集合的形式返回:Collection values()
    (2)Lambda-------forEach

————————————————

一、Map接口—查找表

1、HashMap :

  • 是一个散列表,它存储的内容是键值对(key-value)映射。
  • Map体现的结构是一个多行两列的表格,其中左列称为“Key”,优列称为“value”

(1)hashmap的底层实现是什么样的?

先根据key调用hashcode方法得到一个整数,再对该整数使用散列算法,生成的整数值为保存在数组(哈希桶)中下标,键值对数据会存入该位置,存入之前会先判断是否有值:
-1)若该数组位置没有值,则直接将键值对数据存入数组;
-2)若有值,则对key使用equlas进行判断,判断key是否相等:
----------若相等,此时将新的value覆盖旧的value;
----------若不相等,此时在数组这个位置形成链表,将新的键值对数据保存到链表上,从JDK1.8开始,若链表的长度大于8,此时形成红黑树

(2)特点:
-①HashMap 实现了 Map 接口,根据键(Key)的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。

-②HashMap 是无序的,即不会记录插入的顺序。

-③HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。

2、java.util.Map接口 查找表

  • (1)创建一个HashMap对象map
  • (2)向当前Map中保存一组键值对:v put(K k,V v)
  • (3)根据指定的Key获取对应的value,如果给定的Key不存在,则返回值为null
  • (4)返回当前Map中的元素个数
  • (5)删除给定的key对应的这组键值对,返回值为这个key对应的value

HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(String)类型的 key 和 value,也可以是整型(Integer)的 key 和字符串(String)类型的 value。
例:
-//创建一个HashMap对象map,字符串(String)类型的key和整型(Integer)的value:
-Map<String,Integer> map = new HashMap();

《MapDemo.java》:package map;
import java.util.HashMap;
import java.util.Map;
/*** java.util.Map接口 查找表* Map体现的结构是一个多行两列的表格,其中左列称为“Key”,优列称为“value”* Map总是以Key-value对的形式保存一组数据。并且可以根据key获取对应的value。* Map有一个要求,Key不允许重复(equals比较)*  * 常用实现类:* java.util.HashMap,我们称他为“散列表”,当今查询速度最快的数据结构。*/
public class MapDemo {public static void main(String[] args) {//1、创建一个HashMap对象map,字符串(String)类型的key和整型(Integer)的value:Map<String,Integer> map = new HashMap();/*2、向当前Map中保存一组键值对:v put(K k,V v)-添加元素:HashMap类提供了很多有用的方法,添加键值对(key-value)可以使用put()方法:-会以:“key=value”的形式打印。  例:“语文=99”*/map.put("语文",99);/*如果Map的value是包装类类型,获取时不要用基本类型(int)接收,避免自动拆箱引发空指针例:int value = map.put("化学",80);//会报空指针异常自动拆箱成:int value = map.put("化学",80).intValue();系统默认在后边加上".intValue()"。*/Integer value = map.put("数学",98);//Key不存在时,put方法返回值为nullmap.put("物理",97);map.put("化学",99);System.out.println(map);//{物理=97, 数学=98, 化学=99, 语文=99}value = map.put("数学",77);//Key已经存在则替换value,但是返回值为Key原来对应的value(98)System.out.println("value:"+value);//value:98System.out.println(map);//{物理=97, 数学=77, 化学=99, 语文=99}/*3、根据指定的Key获取对应的value,如果给定的Key不存在,则返回值为null:v get(Object Key)*/value = map.get("语文");System.out.println("语文:"+value);//语文:99value = map.get("体育");System.out.println("体育:"+value);//体育:null//4、返回当前Map中的元素个数int size = map.size();System.out.println("size:"+size);//size:4/*5、删除给定的key对应的这组键值对,返回值为这个key对应的value*/value = map.remove("数学");System.out.println(map);//{物理=97, 化学=99, 语文=99}System.out.println("value:"+value);//value:77//6、可以分别判定Map是否包含给定的key或value。判定依据仍然是equals方法。boolean ck = map.containsKey("物理");System.out.println("包含key:"+ck);//包含key:trueboolean cv = map.containsValue(97);System.out.println("包含cv:"+cv);//包含cv:true}
}

3、Map的3种遍历方式

(1)3种遍历方式

  • ①遍历key:将当前Map中所有的key以一个Set集合形式返回:Set kaySet()

  • ②遍历每一组键值对:Set entrySet()

  • ③遍历value:将所有的value以一个集合的形式返回:Collection values()

(2)Lambda-------forEach

《MapDemo2.java》:package map;
import java.util.*;
/*** Map的3种遍历方式:*/
public class MapDemo2 {public static void main(String[] args) {Map<String,Integer> map = new HashMap<>();map.put("语文",99);map.put("数学",98);map.put("英语",99);map.put("物理",96);map.put("化学",99);System.out.println(map);//{物理=96, 数学=98, 化学=99, 语文=99, 英语=99}/*1、将当前Map中所有的key以一个Set集合形式返回:Set kaySet()*/Set<String> keySet = map.keySet();for(String key : keySet){System.out.println("key:"+key);//key:物理 key:数学 .....}/*2、遍历每一组键值对:Set entrySet()将当前Map中每一组键值对以Entry实例形式表示并存入集合后将其返回。java.util.Map.Entry它的每一个实例用于表示一组键值对*/Set<Map.Entry<String,Integer>> entrySet = map.entrySet();for(Map.Entry<String,Integer> e : entrySet){String key = e.getKey();Integer value = e.getValue();System.out.println(key+":"+value);//物理:96 数学:98 化学:99 ....}/*3、将所有的value以一个集合的形式返回:Collection values()*/Collection<Integer> values = map.values();for(Integer value : values){System.out.println("value:"+value);//value:96 value:98 value:99 ...}/*!!还可以用lambda表达式形式遍历!!!-----forEachJDK8之后集合和Map都支持了基于lambda表达式形式遍历Map会将每一组键值对作为参数传给lambda表达式:*/map.forEach((k,v)-> System.out.println(k+":"+v) //物理:96 数学:98 化学:99 ...);Collection<String> c = new ArrayList<>();c.add("one");c.add("two");c.add("three");c.add("four");c.add("five");//        c.forEach(
//                e -> System.out.println(e)
//        );c.forEach(System.out::println //one two three four ...);}
}

SE API第10/11天:集合 ——>ArrayListals、Iterator遍历迭代器、增强for、List集→subList、集合间转换asList、排序sort | Map相关相关推荐

  1. Java14-day05【集合(Collection常用方法-遍历、List特有方法、List集合子类特点、LinkedList集合的特有功能、ListIterator)】

    视频+资料(工程源码.笔记)[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg   提取码:zjxs] Java基础--学习笔记(零起点打开java ...

  2. 1.10 Iterator(迭代器)遍历集合元素

    Iterator(迭代器)遍历Collection集合元素 Iterator(迭代器)是一个接口,它的作用就是遍历容器的所有元素,也是 Java 集合框架的成员,但它与 Collection 和 Ma ...

  3. java list 两个集合比较 不存在则新增 存在修改_Java之集合

    在许多应用场合,一组数据的长度不是固定的,比如一个单位的员工数目是变化的,有老员工跳槽,也有新员工进来. 为了使程序能够方便的存储和操纵数目不固定的一组数据,JDK类库提供了Java集合,位于java ...

  4. 2021-06-19复习java Collection集合 Iterator接口_迭代器 增强for循环 泛型

    2021-06-19复习java Collection集合 Iterator接口_迭代器 增强for循环 泛型 Collection集合 java.util.coLlection接口 所有单列集合的最 ...

  5. java9特性_96.java基础10(java9/10/11新特性)

    126.java 9 新特性1(模块化功能): 1.java模块化 2.java 交互式环境jshell 3.泛型 package com.atguigu.java; import org.junit ...

  6. java10_JAVA10 64位下载|java se development kit 10(JDK10)下载 v10.0 官方版 - 比克尔下载

    java se development kit 10是JAVA最新的开发环境,你可以通过下载JAVA10 64位来体验最新版JDK的新特性,最重要的一个特性就是本地变量类型推断,让程序员们可以更便捷的 ...

  7. 从零开始学黑苹果-基础安装教程(10.11.6)

    [本文转载自]蒋古申 本文目录: 1. Hackintosh 简介与心得 2. U盘安装原版 OS X 10.11.6步骤 安装U盘的制作 Clover 引导安装 3. macOS 的安装 4. 驱动 ...

  8. osx java 6_OSX 10.11 java 6不兼容怎么办?OSX 10.11 java 6不兼容解决办法

    OSX 10.11 java 6不兼容怎么办?有很多用户在使用最新的OSX 10.11系统时会发现java SE 6不兼容的问题,其实要解决 这个问题比较简单,用户需要下载安装最新的Java SE 8 ...

  9. Interview:算法岗位面试—10.11下午—上海某公司算法岗位(偏机器学习,互联网数字行业)技术面试考点之XGBoost的特点、python的可变不可变的数据类型、赋值浅拷贝深拷贝区别

    ML岗位面试:10.11下午-上海某公司算法岗位(偏机器学习,互联网数字行业)技术面试考点之XGBoost的特点.python的可变不可变的数据类型.赋值浅拷贝深拷贝区别 Interview:算法岗位 ...

最新文章

  1. ACL Fellow 2021名单出炉!华为刘群、中科院自动化所宗成庆当选!
  2. easyre-153 testre寒假逆向生涯(13/100)
  3. 透视大数据,未来市场谁主沉浮?这个4月,3W企服大数据OpenForm等你报名!
  4. 解决python中遇到的乱码问题
  5. MTK:文件操作接口详解
  6. stl非变易算法(一)
  7. overflow鼠标拖拽显示_[翻译] 从零开始的 .Net Shell 扩展教程 (四) - Shell 拖拽处理程序
  8. Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 上篇
  9. 阶段3 1.Mybatis_03.自定义Mybatis框架_3.自定义mybatis的编码-根据测试类中缺少的创建接口和类...
  10. 随机过程之马尔科夫链
  11. [ 成为架构师系列 ] 2. 深入理解 Cookie 与 Session ,Facade 设计模式, 分布式 Session...
  12. 考研前夕 — 成人的世界里没有那么多童话
  13. Bulma的简单使用
  14. 挚爱身影渐隐。素绞无意世情狠
  15. Accuracy and precision 意义
  16. 【2017 BSUIR Semifinal G】Digital characteristic 题解
  17. python去掉开头不想要的字符
  18. python人机大战小游戏代码
  19. 豆瓣电影多个作品里的海报、剧照图片怎样快速复制保存
  20. Docker 基本操作 数据卷 -- docker 数据卷基本操作、挂载数据卷

热门文章

  1. 三星s7 android8.0,不抛弃不放弃:三星正为S7系列打造Android 8.0
  2. 保弘实业|家庭理财存款如何分配比例才好
  3. 一个3升的桶和一个5升的桶,怎么得到4升的水。
  4. 怎么样获取小米手机8 SE的root权限
  5. win10专业版 安装 docker
  6. 333-SQL实现网页的插入更新登录
  7. UE4 安卓开发 如何接入PicoVR设备,
  8. zookeeper从入门到入土
  9. 谷歌手机升级android10,Android10.0都准备发布了,你的手机升级到Android9.0了
  10. redis进阶持久化、事务、主从复制、集群高可用