mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-07-28 12:22:17 +08:00
Compare commits
10 Commits
58696c742b
...
1ba08ab91f
Author | SHA1 | Date | |
---|---|---|---|
|
1ba08ab91f | ||
|
0a0021c97c | ||
|
dcf63ae84d | ||
|
4b34db7018 | ||
|
d6905064b7 | ||
|
f168d723ac | ||
|
1dd05db8d2 | ||
|
8cd0f88307 | ||
|
8391c9b93e | ||
|
9145feec50 |
@ -599,6 +599,12 @@ Node{data=21, maxLevel=3}
|
||||
Node{data=23, maxLevel=1}
|
||||
```
|
||||
|
||||
**Redis 跳表的特点**:
|
||||
|
||||
1. 采用**双向链表**,不同于上面的示例,存在一个回退指针。主要用于简化操作,例如删除某个元素时,还需要找到该元素的前驱节点,使用回退指针会非常方便。
|
||||
2. `score` 值可以重复,如果 `score` 值一样,则按照 ele(节点存储的值,为 sds)字典排序
|
||||
3. Redis 跳跃表默认允许最大的层数是32,被源码中 `ZSKIPLIST_MAXLEVEL` 定义。
|
||||
|
||||
## 和其余三种数据结构的比较
|
||||
|
||||
最后,我们再来回答一下文章开头的那道面试题: “Redis 的有序集合底层为什么要用跳表,而不用平衡树、红黑树或者 B+树?”。
|
||||
|
@ -24,7 +24,7 @@ head:
|
||||
|
||||
负载均衡可以简单分为 **服务端负载均衡** 和 **客户端负载均衡** 这两种。
|
||||
|
||||
服务端负载均衡涉及到的知识点更多,工作中遇到的也比较多,因为,我会花更多时间来介绍。
|
||||
服务端负载均衡涉及到的知识点更多,工作中遇到的也比较多,因此,我会花更多时间来介绍。
|
||||
|
||||
### 服务端负载均衡
|
||||
|
||||
|
@ -379,6 +379,84 @@ public class OutterClass
|
||||
}
|
||||
```
|
||||
|
||||
**为什么内部类可以使用外部类的private属性**:
|
||||
|
||||
我们在InnerClass中增加一个方法,打印外部类的userName属性
|
||||
|
||||
```java
|
||||
//省略其他属性
|
||||
public class OutterClass {
|
||||
private String userName;
|
||||
......
|
||||
class InnerClass{
|
||||
......
|
||||
public void printOut(){
|
||||
System.out.println("Username from OutterClass:"+userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 此时,使用javap -p命令对OutterClass反编译结果:
|
||||
public classOutterClass {
|
||||
private String userName;
|
||||
......
|
||||
static String access$000(OutterClass);
|
||||
}
|
||||
// 此时,InnerClass的反编译结果:
|
||||
class OutterClass$InnerClass {
|
||||
final OutterClass this$0;
|
||||
......
|
||||
public void printOut();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
实际上,在编译完成之后,inner实例内部会有指向outer实例的引用`this$0`,但是简单的`outer.name`是无法访问private属性的。从反编译的结果可以看到,outer中会有一个桥方法`static String access$000(OutterClass)`,恰好返回String类型,即userName属性。正是通过这个方法实现内部类访问外部类私有属性。所以反编译后的`printOut()`方法大致如下:
|
||||
|
||||
```java
|
||||
public void printOut() {
|
||||
System.out.println("Username from OutterClass:" + OutterClass.access$000(this.this$0));
|
||||
}
|
||||
```
|
||||
|
||||
补充:
|
||||
|
||||
1. 匿名内部类、局部内部类、静态内部类也是通过桥方法来获取private属性。
|
||||
2. 静态内部类没有`this$0`的引用
|
||||
3. 匿名内部类、局部内部类通过复制使用局部变量,该变量初始化之后就不能被修改。以下是一个案例:
|
||||
|
||||
```java
|
||||
public class OutterClass {
|
||||
private String userName;
|
||||
|
||||
public void test(){
|
||||
//这里i初始化为1后就不能再被修改
|
||||
int i=1;
|
||||
class Inner{
|
||||
public void printName(){
|
||||
System.out.println(userName);
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
反编译后:
|
||||
|
||||
```java
|
||||
//javap命令反编译Inner的结果
|
||||
//i被复制进内部类,且为final
|
||||
class OutterClass$1Inner {
|
||||
final int val$i;
|
||||
final OutterClass this$0;
|
||||
OutterClass$1Inner();
|
||||
public void printName();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### 条件编译
|
||||
|
||||
—般情况下,程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译。
|
||||
|
@ -258,7 +258,7 @@ public V get(Object key) {
|
||||
```java
|
||||
void afterNodeAccess(Node < K, V > e) { // move node to last
|
||||
LinkedHashMap.Entry < K, V > last;
|
||||
//如果accessOrder 且当前节点不未链表尾节点
|
||||
//如果accessOrder 且当前节点不为链表尾节点
|
||||
if (accessOrder && (last = tail) != e) {
|
||||
|
||||
//获取当前节点、以及前驱节点和后继节点
|
||||
|
@ -162,7 +162,7 @@ HMACSHA256(
|
||||
3. JWT 存放在 localStorage 中而不是 Cookie 中,避免 CSRF 风险。
|
||||
4. 一定不要将隐私信息存放在 Payload 当中。
|
||||
5. 密钥一定保管好,一定不要泄露出去。JWT 安全的核心在于签名,签名安全的核心在密钥。
|
||||
6. Payload 要加入 `exp` (JWT 的过期时间),永久有效的 JWT 不合理。并且,JWT 的过期时间不易过长。
|
||||
6. Payload 要加入 `exp` (JWT 的过期时间),永久有效的 JWT 不合理。并且,JWT 的过期时间不宜过长。
|
||||
7. ……
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user