上一期,我们讲到集合的知识的初步了解,这次我们就来讲解稍微完整版的

目录

集合框架图

定义以及接口的讲解

详细讲解:

List集合子类特点:

Set集合概述和特点:

HashSet集合概述和特点:

哈希值:

TreeSet集合概述和特点:

TreeSet集合特点:

Comparator的使用:

泛型:

类型通配符:

Map集合概述和使用:

补充内容:

集合框架底层数据结构总结:

Collection

Map

如何选用集合?

特别注意事项:

List 和 Map 区别?(数据结构,存储特点)

Arraylist与 LinkedList 异同:

HashMap 和 Hashtable 的区别:

ArrayList 与 Vector 的区别:

HaspMap与TreeMap的区别:

HashMap 和 HashSet区别

HashMap和Hashtable的区别

ArrayList和Vector的区别(是否有序、是否重复、数据结构、底层实现)


集合框架图

定义以及接口的讲解

1、定义:Java集合类存放于java.util包,是存放对象的容器,长度可变,只能存放对象,可以存放不同的数据类型;

2、常用集合接口:

  a、Collection接口:最基本的集合接口,存储不唯一,无序的对象,List接口和Set接口的父接口;

  b、List接口:一个有序、可以重复的集合,常用实现类ArrayList和LinkedList;

1 // 底层数据结构是数组,查询快,增删慢,线程不安全,效率高
2 List arrayList = new ArrayList();
3 // 底层数据结构是数组,查询快,增删慢,线程安全,效率低,耗性能
4 List vector = new Vector();
5 // 底层数据结构是链表,查询慢,增删快,线程不安全,效率高
6 List linkedList = new LinkedList();

c、Set接口:一个无序、不可重复的集合,常用实现类HashSet、LinkedHashSet、TreeSet;

1 // 元素无序,不可重复,线程不安全,集合元素可以为 NULL
2 Set hashSet = new HashSet();
3 // 底层采用链表和哈希表的算法,保证元素有序,唯一性(即不可以重复,有序),线程不安全
4 Set linkedHashSet = new LinkedHashSet();
5 // 底层使用红黑树算法,擅长于范围查询,元素有序,不可重复,线程不安全
6 Set treeSet = new TreeSet();

d、Map接口:key-value的键值对,key不允许重复,value可以,key-value通过映射关系关联,常用实现类HashMap和TreeMap;

1 // 采用哈希表算法,key无序且不允许重复,key判断重复的标准是:key1和key2是否equals为true,并且hashCode相等
2 Map<String, String> hashMap = new HashMap<String, String>();
3 // 采用红黑树算法,key有序且不允许重复,key判断重复的标准是:compareTo或compare返回值是否为0
4 Map<String, String> treeMap = new TreeMap<String, String>();

3、Set和List的区别:

  a、Set实例存储是无序的,不重复的数据;List实例存储的是有序的,可以重复的元素;

  b、Set检索效率低下,删除和插入效率高,删除和插入不会引起元素位置改变;

  c、List可以根据存储的数据长度自动增长List长度,查找元素效率高,插入删除效率低,插入和删除时会引起其他元素位置改变;

4、Map和Set的关系:

  a、HashMap、HashSet 都采哈希表算法,TreeMap、TreeSet 都采用红黑树算法、LinkedHashMap、LinkedHashSet 都采用哈希表算法和红黑树算法;

  b、分析Set的底层源码,Set 集合就是由Map集合的Key组成;

详细讲解:

List集合我们已经在上一篇文章里面讲到了, 所以这次我们就讲深入的知识,

List集合子类特点:

上面也提到了,这个是做的导图里面的内容;

在这里我做了一个小小的测试,将上面提到的6个特有方法都写了一遍

public class LinkedListDemo {public static void main(String[] args) {LinkedList<String > LinkedList =new LinkedList<String >();LinkedList.add("hello");LinkedList.add("world");LinkedList.add("java");/*  // public void addFirst(E e):在该列表开头插入指定的元素//public void addLast(E e):将指定元素追加到列表的末尾LinkedList.addFirst("javaee");LinkedList.addLast("hhh");q87yh// public E getFirst() :返回此列表中的第一个元素// public E getLast(): 返回此列表中的最后一个元素System.out.println(LinkedList.getFirst());System.out.println(LinkedList.getLast());//public E removeFirst(); 删除并返回第一个元素//public E removeLast():删除并返回最后一个元素System.out.println(LinkedList.removeFirst());System.out.println(LinkedList.removeLast());*/System.out.println(LinkedList);}}

大佬们也可以自己上机测试测试,方便理解其内容。

Set集合概述和特点:

set集合特点:1.不包含重复元素的集合

2.没有带索引的方法,所以不能使用普通for循环遍历

让我们用代码来观察其特点,  不包含重复元素

public class SetDemo {public static void main(String[] args) {//创建集合对象Set<String> set=new HashSet<String>();//添加元素set.add("hello");set.add("world");set.add("java");//不包含重复元素set.add("world");//遍历for (String s:set){System.out.println(s);}}}

控制台输出截图:

讲完了Set集合,让我们来看看HashSet

HashSet集合概述和特点:

hashset集合特点:

①:底层的数据结构是哈希;

②:它对集合的迭代顺序不作任何保证;特别是它不能保证订单在一段时间内保持不变,这个类允许 null元素;

③:没有带索引的方法,所以不能使用普通for循环遍历

④:由于是set集合,所以是不包含重复元素的集合

hashset集合添加元素的过程:

如下图所示:

可能这个图的字有点小,大家委屈一下自己。

代码上机测试:

public class HashSetDemo {public static void main(String[] args) {//创建集合对象HashSet<String> hs=new HashSet<String>();//添加元素hs.add("hello");hs.add("world");hs.add("java");hs.add("world");   //就算你输入了两个,  但是 他是不能重复的for (String s:hs){System.out.println(s);}}}

从上图,我们看到的,hs.add 里面写了俩个  world, 可是set集合的特点是不重复元素,并且得需要使用增强for来实现遍历,输出结果如下图所示:

中间穿插一点小片段,上面讲到了HashSet 所以我们来讲讲 哈希值。

哈希值:

1.定义:哈希值是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值;

2. public int hashCode():返回对象的哈希值!!!  需要了解;

3.哈希值的特点:

①:同一个对象多次调用hashCode()方法返回的哈希值是相同的;

②:默认情况下,不同的对象的哈希值是不同的。而重新hashCode()方法,可以实现让不同对象的哈希值相同

下面我们将上机实际通过代码测试:

public class HashDemo {public static void main(String[] args) {
//创建学生对象Student s1=new Student("林青霞",30);System.out.println(s1.hashCode());//22307196System.out.println(s1.hashCode());//22307196
//同一个对象多次调用hashcode()方法返回的哈希值是相同的System.out.println("--------------");
//默认情况下,不同的对象的哈希值是不相同的Student s2=new Student("林青霞",30);System.out.println(s2.hashCode());//10568834System.out.println(s2.hashCode());//10568834System.out.println("-------------");//通过方法重写,可以实现不同对象的哈希值是相同的;System.out.println("hello".hashCode());//99162322System.out.println("world".hashCode());//113318802System.out.println("java".hashCode());//3254818System.out.println("world".hashCode());//113318802System.out.println("重地".hashCode());//1179395System.out.println("通话".hashCode());//1179395}}

控制台打印输出:

哈希值这个东西,大家可以多了解了解,蛮有趣的一个东西。

TreeSet集合概述和特点:

TreeSet集合特点:

①:元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体的排序方式取决于构造方法;

两个方法:1.TreeSet():根据其元素的自然排序

2.TreeSet( Comparator  comparator): 根据指定的比较器进行排序

②:没有带索引的方法,所以不能使用普通for循环遍历,但是可以用增强for进行遍历;

③:由于是set集合,所以不包含重复元素的集合;

Comparator的使用:

1.自然排序Comparable的使用:

①:TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的

②:自然排序,就是让元素所属的类实现Comparable接口,重新compareTo(T o)方法

③:重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

2.比较器排序Comparator的使用:

①:用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的

②:比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,  To2) 方法

代码上机测试:

public class TreeSetDemo {public static void main(String[] args) {//通过创建TreeSet集合对象, 通过比较器排序进行排序TreeSet<Student> ts=new TreeSet<Student>(new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {//主要条件!!!int num=(s2.getSum()-s1.getSum());//次要条件int num2=num==0?s1.getChinese()-s2.getChinese():num;return num2;}});//创建学生对象Student s1=new Student("林青霞",25,95,82);Student s2=new Student("张曼玉",28,88,92);Student s3=new Student("令狐冲",26,97,91);Student s4=new Student("风清扬",29,95,96);Student s5=new Student("东方不败",24,85,92);Student s6=new Student("煮了吃",31,94,97);Student s7=new Student("煮了吃",31,94,97);ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);ts.add(s6);ts.add(s7);for (Student s: ts){System.out.println(s.getName()+","+s.getAge()+","+s.getChinese()+","+s.getMath()+","+s.getSum());}}}

代码测试结果如下:

泛型:

泛型概述:它的本质是参数化类型,   顾名思义,就是将类型由原来的具体的类型参数化, 然后在使用/调用时传入具体的类型;

泛型定义格式:

1.<类型>:指定一种类型的格式,这里的类型可以看成是形参;

2.<类型1, 类型2>:指定多种类型的格式, 多种类型直接用逗号隔开。 这里的类型可以看成是形参;

3.将来具体调用时候给定的类型可以看成是形参,并且实参的类型只能是引用数据类型

泛型的好处:1.把运行时期的问题提前到了编译期间,2.避免了强制类型转换;

类型通配符:

不作具体的说,放上截图

好捏看完了上面,接下来需要看一点小重点知识MAP!!!

Map集合概述和使用:

Map集合概述:Interface Map<K, V>    K:键的类型; V: 值的类型;  将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值

创建Map集合的对象(两种方法):①多态的方式;②具体的实现类HashMap;

Map集合的基本功能:

Map集合的获取功能:

代码上机测试:

public class MapDemo03 {public static void main(String[] args) {Map<String ,String> map=new HashMap<String, String>();//在map集合中,  前面的叫做键,后面的叫做值map.put("张无忌","赵敏");map.put("郭靖","黄蓉");map.put("杨过","小龙女");/*  // v get(Object key):根据键获取值System.out.println(map.get("张无忌"));//如果键里面不存在那个值,则返回nullSystem.out.println(map.get("张三丰"));*//*   //Set<K> keySet():获取所有键的集合Set<String> keySet=map.keySet();for (String key: keySet) {System.out.println(key);}*///Collection<V> values(): 获取所有值的集合Collection<String > values=map.values();for (String key:values){System.out.println(key);}}}

这里我们只展示,最后输出值的结果:

通过Set<Map.Entry<String ,String>> entrySet=map.entrySet();来获取所有的键值的对象!!!

public class MapDemo05 {public static void main(String[] args) {Map<String ,String> map=new HashMap<String, String>();//添加元素map.put("张无忌","赵敏");map.put("郭靖","黄蓉");map.put("杨过","小龙女");//获取所有键值对对象的集合Set<Map.Entry<String ,String>> entrySet=map.entrySet();//遍历键值对对象的集合,得到每一个键值对对象for (Map.Entry<String ,String> me:entrySet){String key=me.getKey();String value=me.getValue();System.out.println(key+","+value);}}}

补充内容:

集合框架底层数据结构总结:

Collection

1. List

  • Arraylist: Object数组
  • Vector: Object数组
  • LinkedList: 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)

2. Set

  • HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素
  • LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
  • TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树。)

Map

  • HashMap: JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
  • LinkedHashMap: LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。详细可以查看:《LinkedHashMap 源码详细分析(JDK1.8)》
  • Hashtable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
  • TreeMap: 红黑树(自平衡的排序二叉树)

如何选用集合?

主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用Map接口下的集合,需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选用ConcurrentHashMap.当我们只需要存放元素值时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,不需要就选择实现List接口的比如ArrayList或LinkedList,然后再根据实现这些接口的集合的特点来选用。

特别注意事项:

List 和 Map 区别?(数据结构,存储特点)

这个要从两个方面来回答,一方面是List和Map的数据结构,另一方面是存储数据的特点。在数据结构方面,List存储的是单列数据的集合,而Map存储的是key、value类型的数据集合。在数据存储方面,List存储的数据是有序且可以重复的,而Map中存储的数据是无序且key值不能重复(value值可以重复)。

 Arraylist与 LinkedList 异同:

  1. Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向循环链表数据结构;
  2. ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。插入末尾还好,如果是中间,则(add(int index, E element))接近O(n);LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。
  3. LinkedList 不支持高效的随机元素访问,而ArrayList 实现了RandmoAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。所以ArrayList随机访问快,插入慢;LinkedList随机访问慢,插入快。
  4. ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。

 HashMap 和 Hashtable 的区别:

相同点: 都是实现来Map接口(hashTable还实现了Dictionary 抽象类)。

不同点:

  1. 历史原因:Hashtable 是基于陈旧的 Dictionary 类的,HashMap 是 Java 1.2 引进的 Map 接口 的一个实现,HashMap把Hashtable 的contains方法去掉了,改成containsvalue 和containsKey。因为contains方法容易让人引起误解。
  2. 同步性:Hashtable 的方法是 Synchronize 的,线程安全;而 HashMap 是线程不安全的,不是同步的。所以只有一个线程的时候使用hashMap效率要高。
  3. 值:HashMap对象的key、value值均可为null。HahTable对象的key、value值均不可为null。
  4. 容量:HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。
  5. HashMap扩容时是当前容量翻倍即:capacity * 2,Hashtable扩容时是容量翻倍+1 即:capacity * 2+1。

ArrayList 与 Vector 的区别:

共同点: 都实现了List接口,都是有序的集合,我们可以按位置的索引号取出元素,其中数据都是可以重复的,这是与hashSet最不同的,hashSet不可以按照索引号去检索其中的元素,也不允许有重复的元素。

区别:

  1. 同步性:Vector是线程安全的,即线程同步,ArrayList是不安全的,如果有多个线程访问到集合,最好使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码;如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些。
  2. 数据增长:ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的 1.5 倍)。ArrayList 与 Vector 都可以设置初始的空间大小,Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。

HaspMap与TreeMap的区别:

  1. HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
  2. 在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。

HashMap 和 HashSet区别

如果你看过 HashSet 源码的话就应该知道:HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 clone() writeObject()readObject()是 HashSet 自己不得不实现之外,其他方法都是直接调用 HashMap 中的方法。

HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,并且都是key-value的数据结构。它们的不同点主要在三个方面:

第一,Hashtable是Java1.1的一个类,它基于陈旧的Dictionary类。而HashMap是Java1.2引进的Map接口的一个实现。

第二,Hashtable是线程安全的,也就是说是线程同步的,而HashMap是线程不安全的。也就是说在单线程环境下应该用HashMap,这样效率更高。

第三,HashMap允许将null值作为key或value,但Hashtable不允许(会抛出NullPointerException)。

ArrayList和Vector的区别(是否有序、是否重复、数据结构、底层实现)

ArrayList和Vector都实现了List接口,他们都是有序集合,并且存放的元素是允许重复的。它们的底层都是通过数组来实现的,因此列表这种数据结构检索数据速度快,但增删改速度慢。

而ArrayList和Vector的区别主要在两个方面:

第一,线程安全。Vector是线程安全的,而ArrayList是线程不安全的。因此在如果集合数据只有单线程访问,那么使用ArrayList可以提高效率。而如果有多线程访问你的集合数据,那么就必须要用Vector,因为要保证数据安全。

第二,数据增长。ArrayList和Vector都有一个初始的容量大小,当存储进它们里面的元素超过了容量时,就需要增加它们的存储容量。ArrayList每次增长原来的0.5倍,而Vector增长原来的一倍。ArrayList和Vector都可以设置初始空间的大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。

Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。

感谢各位大佬的收看 谢谢各位大佬!!!

集合全套以及知识点整合相关推荐

  1. 前端笔记知识点整合之JavaScript(五)关于数组和字符串那点事

    前端笔记知识点整合之JavaScript(五)关于数组和字符串那点事 一.数组 1.1数组概念 数组(array)是一个有序的数据集合.说白了,数组就是一组数.数组内部可以存放一个或多个单独的数据,整 ...

  2. 计算机组装与拆解中容易混淆的知识点,教资干货 | 教资笔试中易混淆的知识点整合...

    原标题:教资干货 | 教资笔试中易混淆的知识点整合 教师资格笔试越来越近, 同学们要会进行归纳整理和总结, 很多同学复习的很好, 但一看到题目的时候就不确定具体答案是哪个了, 今天小编就来归纳整理教资 ...

  3. 前端笔记知识点整合之服务器Ajax(上)服务器PHP数据交互HTTP

    前端笔记知识点整合之服务器&Ajax(上)服务器&PHP&数据交互&HTTP 一.服务器 1.1 什么是服务器,做什么的? 服务器,就是放在机房中的电脑,和我们的电脑的 ...

  4. C++知识点 —— 整合(持续更新中)

    本文记录自己在自学C++过程中不同于C的一些知识点,适合于有C语言基础的同学阅读.如果纰漏,欢迎回复指正 目录 第一部分 基础知识 一.HelloWorld与命名空间 二.引用和引用参数 2.1引用的 ...

  5. C++知识点 —— 整合

    本文记录自己在自学C++过程中不同于C的一些知识点,适合于有C语言基础的同学阅读.如果纰漏,欢迎回复指正 目录 第一部分 基础知识 一.HelloWorld与命名空间 二.引用和引用参数 2.1引用的 ...

  6. Java 集合Collection常见知识点汇总~

    看了一些所谓大公司的JAVA面试问题,发现对于JAVA集合类的使用都比较看重似的,而自己在这方面还真的是所真甚少,抽空也学习学习吧. java.util包中包含了一系列重要的集合类,而对于集合类,主要 ...

  7. 【Angular 基础入门】——知识点整合

    文章目录 快速入门 一.Angular 环境搭建 二.基本概念 模块简介 组件简介 服务与依赖注入 路由 三.基础教程 使用路由 自定义组件 常用结构型指令 事件绑定 模板引用 模板表达式中的运算符 ...

  8. 关于集合的一些知识点

    集合 ArrayList HashSet (它与ArrayList集合非常相似) HashMap 集合类Properties 集合 集合,它也是一种数组,它称为:动态数组 特点: 声明集合的时候,不需 ...

  9. 2020 AI 算法工程师常见知识点整合

    算法工程师基础理论 0.写在前面 机器学习流程 基本概念 数据 从数据到答案 将原始数据映射到特征 模型:数据关系的近似描述 高屋建瓴 1. 特征工程 预处理:将原始数据变为特征向量 1.数值变量:归 ...

  10. 前端笔记知识点整合之JavaScript(四)关于函数、作用域、闭包那点事

    一.自定义函数function 函数就是功能.方法的封装.函数能够帮我们封装一段程序代码,这一段代码会具备某一项功能,函数在执行时,封装的这一段代码都会执行一次,实现某种功能.而且,函数可以多次调用. ...

最新文章

  1. PowerDesigner连接SqlServer数据库导出表结构
  2. 归并排序(二路、递归)
  3. 迷你计算机笔记本,迷你笔记本电脑我选择了它,性能不错还超轻便携
  4. 已知若干点求圆心_【求精干货】高中数学知识点总结归纳高一学生必须掌握
  5. 一个斐波那契数列题 HDU 2041
  6. oracle ola_Ola HallengrenSQL Server维护解决方案–索引和统计信息维护
  7. android显示网络gif图片
  8. Lucene和Solr版本对应关系
  9. iOS UI-团购案例(通过xib文件自定义UITableViewCell)
  10. ssq历史红蓝冷热号回归测试各个期与若干分析周期的中奖率(红号出现3个以上再输出)
  11. 自定义View之Layout方法详解
  12. html页面出现504,web生产环境故障页面提示504错误
  13. Python xldr 读取xls 文件中时间格式处理
  14. 实验02-微信公众号编辑模式应用
  15. vagrant Linux虚拟机与win共享目录时的大小写及共享失败问题(vagrant share folder/synced_folder case sensitivity)
  16. 如何进行Sublime Text插件的升级和卸载?
  17. 关于前后台部署打包时需要修改的ip位置
  18. css多行文本溢出显示省略号
  19. 中学计算机课外小组活动计划,课外活动计划实施方案
  20. 数据通信基础 - 调制技术

热门文章

  1. 鸿蒙申请邮箱格式是什么,手机邮箱格式怎么写
  2. 深度学习【23】图像风格化总结
  3. OpenGL学习小结
  4. 有一种神奇的性格叫——INTJ
  5. 【微信小程序】快进来弹钢琴啦~钢琴小程序源码分享
  6. 50个最受欢迎的大数据面试问题
  7. mysql脏写_图解脏写、脏读、不可重复读、幻读
  8. linux syslinux u盘,如何使用syslinux做一个启动U盘?
  9. 优步司机如何联系客服?uber客服渠道,Uber优步司机客服渠道
  10. shader篇-纹理-凹凸映射