前言
提示:这里为每天自己的学习内容心情总结;
Learn By Doing,Now or Never,Writing is organized thinking.
目前的想法是,根据 Java Guide 和 JavaLearning 和 小林coding进行第一轮复习,之后根据 Tiger 和 CS-Notes 进行最后的重点复习。
先多,后少。
提示:以下是本篇文章正文内容
一、今天学习了什么?
- 复习JavaSE;
- Redis的数据结构
二、关于问题的答案
1.SE
Q:接口和抽象类有什么共同点和区别?
接口和抽象类都可以有抽象方法,都不能被实例化,都可以有默认的方法。
「接口」更注重的是过程,约束的是行为,「抽象类」强调的是代码复用,类的所属关系。
「接口」中所有的方法默认是的 public static final 类型,「抽象类」则是 default 。
Q:深拷贝和浅拷贝区别了解吗?什么是引用拷贝?
深拷贝,是指拷贝出一份新的对象,并且里面的属性也进行拷贝。
浅拷贝,创建新的对象,但是新对象引用原来的对象。
引用拷贝就是引用原来的内存地址上的对象。
Q:Object 类的常见方法有哪些?
getClass() 、 hashCode、wait、notify、toString、equals;
Q:==和equals()的区别?
== 既可以比较基本数据类型,也可以比较引用类型;
equals 只能比较引用类型。
2.Redis
Q:SDS?
这个是 String 类型的底层数据结构,Redis 自己设计了字符串的数据结构,是为了解决 C 语言的字符串的三个缺点:
- 获取字符串的长度,时间复杂度为 O(N);
- 不能存储二进制数据;
- 可能会有数据缓冲区溢出;
SDS 的数据结构有四个重要的属性:
- 字符串长度,通过这个,获取字符串长度的时间复杂度为O(1),存储二进制;
- 字符串数组;
- 字符串所占内存空间大小,可以快速得知字符串剩余空间大小;
- 字符串的数据类型,确定了数组每个元素占的空间大小,目的是节省内存空间;
字符串扩容,首先会检查数组剩余空间,如果够用,就不需要扩容,扩容也需要根据 newLen 的内存大小进行不同的扩容策略。
- newLen 和 1MB 的大小关系;
目的是减少下次的内存分配次数。
Q:链表?
其实就是双向链表,有指针指向前一个和后一个节点,空间内存不连续,无法利用 CPU 缓存,获取元素的时间复杂度 O(N),现在都是用 压缩列表。
Q:压缩列表?
采用的是一片连续的内存空间,有三个重要的属性:
- 起始位置;
- 尾部位置;
- 元素个数;
列表中的每个节点,也有三个重要的属性:
- 前一个结点的内存空间大小;
- 这个节点的编码方式;
- 这个节点存储的数据;
采用压缩列表,可以使用 CPU 缓存,根据存储的数据大小和类型不同,采用不同的编码方式,但是不能存储很多的元素。
新增或者修改元素的时候,可能导致连锁更新的问题。
Q:哈希表?
哈希数组、哈希节点。
通过链表方式解决哈希冲突;
哈希扩容是采用渐进式rehash。
Q:整数集合?
一片连续的内存空间,本质是数组。
新加入元素到数组时,可能出现数组升级,但是不会出现数组降级。
Q:跳表?
多层的有序链表,查找速度 O(logN)。
查询过程,需要判断当前结点的权重和目标节点的权重关系:
- 当前节点的权重 小于 目标节点,就去这层结点的下一个节点;
- 当前结点的权重 等于 目标节点,但是当前节点的数据小于目标数据,也要去这层节点的下个节点;
如果既不是这两种情况,或者下个节点为 null 就需要去这层节点的下一层,重新判断。
不适用平衡树和红黑树,主要从三个角度:内存空间、查找效率、算法实现难度。
如何保证结点的层数呢?采用随机数。
总结
提示:这里对文章进行总结:
终于学完了 Redis 的底层数据结构,明天需要复习完 Redis 的其它基础知识,继续全部复习完 SE。
加油啊!!!