0%

静态代码块 VS 实例代码块

静态代码块在类加载时顺序执行,并且只执行一次。

实例代码块在构造方法之前执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class CodeOrder{
//静态代码块1
static{
System.out.println("static-01");
}

//程序入口
public static void main(String[] args) {
System.out.println("main begin");
new CodeOrder();
System.out.println("main end");
}

//构造方法
public CodeOrder(){
System.out.println("new CodeOrder();");
}

//实例代码块
{
System.out.println("{....}");
}

//静态代码块2
static{
System.out.println("static-02");
}
}

执行顺序:

static-01
static-02
main begin
{….}
new CodeOrder();
main end

I/O流

字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

1. Redis是什么

概述

Redis 是一个使用 C 语言开发开源数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。

用途

  • 高速缓存
  • 消息队列
  • 支持事务、持久化、集群

2. 数据类型

String

String数据结构是简单的key-value类型。

基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> set key value #设置 key-value 类型的值
OK
127.0.0.1:6379> get key # 根据 key 获得对应的 value
"value"
127.0.0.1:6379> exists key # 判断某个 key 是否存在
(integer) 1
127.0.0.1:6379> strlen key # 返回 key 所储存的字符串值的长度。
(integer) 5
127.0.0.1:6379> del key # 删除某个 key 对应的值
(integer) 1
127.0.0.1:6379> get key
(nil)

计数器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
127.0.0.1:6379> set number 1
OK
127.0.0.1:6379> incr number # 将 key 中储存的数字值增一
(integer) 2
127.0.0.1:6379> get number
"2"
127.0.0.1:6379> decr number # 将 key 中储存的数字值减一
(integer) 1
127.0.0.1:6379> get number
"1"

127.0.0.1:6379> expire key 60 # 数据在 60s 后过期
(integer) 1
127.0.0.1:6379> setex key 60 value # 数据在 60s 后过期 (setex:[set] + [ex]pire)
OK
127.0.0.1:6379> ttl key # 查看数据还有多久过期
(integer) 56

List

Redis 的 list 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。

基本操作:rpush,lpop,lpush,rpop,lrange,llen

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> rpush myList value1 # 向 list 的头部(右边)添加元素
(integer) 1
127.0.0.1:6379> rpush myList value2 value3 # 向list的头部(最右边)添加多个元素
(integer) 3
127.0.0.1:6379> lpop myList # 将 list的尾部(最左边)元素取出
"value1"
127.0.0.1:6379> lrange myList 0 1 # 查看对应下标的list列表, 0 为 start,1为 end
1) "value2"
2) "value3"
127.0.0.1:6379> lrange myList 0 -1 # 查看列表中的所有元素,-1表示倒数第一
1) "value2"
2) "value3"
  • 消息队列 lpush/rpop
  • lpush/lpop

Set

Redis 中的 set 类型是一种无序集合,集合中的元素没有先后顺序。当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,可以基于 set 轻易实现交集、并集、差集的操作。比如:你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1:6379> sadd mySet value1 value2 # 添加元素进去
(integer) 2
127.0.0.1:6379> sadd mySet value1 # 不允许有重复元素
(integer) 0
127.0.0.1:6379> smembers mySet # 查看 set 中所有的元素
1) "value1"
2) "value2"
127.0.0.1:6379> scard mySet # 查看 set 的长度
(integer) 2
127.0.0.1:6379> sismember mySet value1 # 检查某个元素是否存在set 中,只能接收单个元素
(integer) 1
127.0.0.1:6379> sadd mySet2 value2 value3
(integer) 2
127.0.0.1:6379> sinterstore mySet3 mySet mySet2 # 获取 mySet 和 mySet2 的交集并存放在 mySet3 中
(integer) 1
127.0.0.1:6379> smembers mySet3
1) "value2"
  • 交集 sinter
  • 并集 suion
  • 差集 sdiff

Hash

hash 是一个 string 类型的 field 和 value 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以 hash 数据结构来存储用户信息,商品信息等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
127.0.0.1:6379> hmset userInfoKey name "guide" description "dev" age "24"
OK
127.0.0.1:6379> hexists userInfoKey name # 查看 key 对应的 value中指定的字段是否存在。
(integer) 1
127.0.0.1:6379> hget userInfoKey name # 获取存储在哈希表中指定字段的值。
"guide"
127.0.0.1:6379> hget userInfoKey age
"24"
127.0.0.1:6379> hgetall userInfoKey # 获取在哈希表中指定 key 的所有字段和值
1) "name"
2) "guide"
3) "description"
4) "dev"
5) "age"
6) "24"
127.0.0.1:6379> hkeys userInfoKey # 获取 key 列表
1) "name"
2) "description"
3) "age"
127.0.0.1:6379> hvals userInfoKey # 获取 value 列表
1) "guide"
2) "dev"
3) "24"
127.0.0.1:6379> hset userInfoKey name "GuideGeGe" # 修改某个字段对应的值
127.0.0.1:6379> hget userInfoKey name
"GuideGeGe"

Zset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> zadd myZset 3.0 value1 # 添加元素到 sorted set 中 3.0 为权重
(integer) 1
127.0.0.1:6379> zadd myZset 2.0 value2 1.0 value3 # 一次添加多个元素
(integer) 2
127.0.0.1:6379> zcard myZset # 查看 sorted set 中的元素数量
(integer) 3
127.0.0.1:6379> zscore myZset value1 # 查看某个 value 的权重
"3"
127.0.0.1:6379> zrange myZset 0 -1 # 顺序输出某个范围区间的元素,0 -1 表示输出所有元素
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> zrange myZset 0 1 # 顺序输出某个范围区间的元素,0 为 start 1 为 stop
1) "value3"
2) "value2"
127.0.0.1:6379> zrevrange myZset 0 1 # 逆序输出某个范围区间的元素,0 为 start 1 为 stop
1) "value1"
2) "value2"

3.事务

1
2
3
4
5
6
7
8
9
10
> MULTI
OK
> SET USER "Guide哥"
QUEUED
> GET USER
QUEUED
> EXEC
1) OK
2) "Guide哥"

  1. 开始事务(MULTI)。
  2. 命令入队(批量操作 Redis 的命令,先进先出(FIFO)的顺序执行)。
  3. 执行事务(EXEC)。

Redis的事务和我们平时理解的关系型数据库的事务不同。

我们知道事务具有四大特性: 1. 原子性2. 隔离性3. 持久性4. 一致性

  1. 原子性(Atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
  2. 隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
  3. 持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
  4. 一致性(Consistency): 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;

Redis 是不支持 roll back 的,因而不满足原子性的(而且不满足持久性)。

Verilog可以从五个层次对电路(系统)进行描述,包括:系统级、算法级、寄存器传输级(即RTL级)、门级、开关级。我们平时用的最多的为RTL级,故Verilog代码也经常被称为RTL代码。

基础语法

1
2
Always@(posedge clk)
Always@(negedge clk)

凡是带有posedge或negedge的always块,都会被综合成时序逻辑电路。

reg :除wire类型外,另外一种常用的数据类型,一般表示寄存器类型数据,不过并不绝对,记住一条原则:在always块内被赋值的信号应定义成reg型,用assign语句赋值的信号应定义成wire型

always/assign:两者都不可嵌套

  • assign语句只能实现组合逻辑赋值,且一个assign语句后面只能跟一条赋值表达式。

  • always即能实现组合逻辑赋值,又能实现时序逻辑赋值操作,且可以包含多条赋值表达式,多条赋值表达式,则应位于begin/end对中间。

设计规则:

i:在组合逻辑电路中,使用阻塞式赋值方式”=”;

ii: 在时序逻辑电路中,使用非阻塞式赋值方式”<=”

iii:在同一个always块内,只能存在一种赋值方式。

iv:一个信号,只能在一个always或一个assign语句下赋值。

v:原则上来说,一个always块内只处理一个或一类信号,不同的信号可在不同的always块内处理。

vi: always块内只能对reg型信号进行处理,不能对wire型数据赋值,也不能实例化模块

1
2
reg [7:0] mem [255:0];   // 256 unpacked elements, each of which is a 8-bit packed vector of reg.
reg mem2 [28:0]; // 29 unpacked elements, each of which is a 1-bit reg.

1-bit全加器

1
2
3
4
5
6
7
8
9
10
// Full adder module here
module add1 (
input a, input b, input cin,
output sum, output cout
);

assign sum = a^b^cin;
assign cout = (a&b)|(cin&a)|(cin&b);

endmodule

1.概述

特点:

  • 任一时刻的输出不仅取决于该时刻的输入,还与电路原来的状态有关。

  • 电路结构上

  • 包含存储电路和组合电路

  • 存储器状态和输入变量共同决定输出

Snipaste_2022-05-04_19-18-27.jpg

同步时序电路与异步时序电路

  • 同步:存储电路中所有触发器的时钟使用统一的clk状态变化发生在同一时刻

  • 异步:没有统一的clk,触发器状态的变化有先有后

* 同步时序电路的分析方法

  • 从给定电路写出存储电路中每个触发器的驱动方程(输入的逻辑式),得到整个电路的驱动方程
  • 将驱动方程代入触发器的特性方程,得到状态方程
  • 从给定电路写出输出方程

Mealy 型 — Z = F(X,Q)

Moore 型 — Z = F(Q)

2.常用的时序逻辑电路

寄存器

  • 用于寄存一组二值代码,N位寄存器由N个触发器组成,可存放一组N位二值代码。
  • 只要求其中每个触发器可置1,置0。

移位寄存器

移位寄存器可以用来寄存代码,还可以用来实现数据的串行—并行转换、数值的运算以及数据的处理等。

计数器(模)

用于计数、分频、定时、产生节拍脉冲等。

同步二进制加法计数器

原理:在多位二进制数末位加1,若第i位一下皆为1时,则第i位应该翻转。

Ti = (Qi-1)(Qi-2)…(Q0)

相反,减法器原理为

Ti = (Qi-1)‘(Qi-2)’…(Q0)‘

3.时序电路的设计

基本步骤:

  1. 逻辑抽象
    A. 确定输入、输出变量以及电路的状态数
    B. 定义输入、输出逻辑状态和每个电路状态的含义
    C. 得出电路的状态转换图(表)
  2. 状态化简和状态分配
  3. 触发器选型,求出电路的状态方程、驱动方程和输出方程
  4. 根据得到的方程画出逻辑图
  5. 检查设计的电路能否自启动

4.常用集成时序电路

74161(模16)

实现模为7的计数器

因为该器件为异步清零,需要一个过渡态S7来置零。

74163

实现模为7的计数器

因为该器件为同步清零,只需要从S0-S6,等待时钟信号从S6->S0来置零。

1.概述

存储电路的基本功能:存储各种数据和信息

  • 寄存器

    1. 存储一组数据的电路

    2. 结构为一组具有公共时钟信号输入端的触发器

  • 存储器

    1. 存储大量数据的电路

    2. 基本结构由存储矩阵和读/写控制电路组成

2.触发器

SR锁存器

image-20220503181245423.png

Sd Rd Q Q’
0 0 0 0
0 0 1 1
1 0 0 1
1 0 1 1
0 1 0 0
0 1 1 0

电平触发的触发器

输入控制门+基本SR触发器

只有触发信号CLK到达,S和R才起作用。

Snipaste_2022-05-04_10-53-13.jpg

脉冲触发的触发器

主从SR触发器

  • CLK = 1时,主 按S,R翻转,从 保持
  • CLK下降沿到达时,主 保持,从 根据主 的状态翻转

注意:每个CLK周期,输出状态只可能改变一次。

Snipaste_2022-05-04_11-06-28.jpg

主从JK触发器

为了解除约束,可以出现S=R=1的情况。

  • Q=0时,只允许J=1的信号进入主触发器
  • Q=1时,只允许K=1的信号进入主触发器

***主从JK在CLK高电平期间,主只可能翻转一次。**

逻辑功能及其描述方法

SR触发器

特性方程:

𝑄∗ = 𝑆′𝑅′𝑄 + 𝑆𝑅′𝑄′ + 𝑆𝑅′𝑄 = 𝑆′𝑅′𝑄 + 𝑆𝑅′ = 𝑆 + 𝑅′𝑄

𝑆𝑅=0

S R Q Q*
0 0 0 0
0 0 1 1
1 0 0 1
1 0 1 1
0 1 0 0
0 1 1 0
1 1 0 1*
1 1 1 1*

JK触发器

特性方程:

𝑄∗ = 𝐽𝑄′ + 𝐾′𝑄

J K Q Q*
0 0 0 0
0 0 1 1
1 0 0 1
1 0 1 1
0 1 0 0
0 1 1 0
1 1 0 1
1 1 1 0

T触发器

将JK触发器的输入端J、K连接在一起,作为输入端T,就构成了T触发器。

即当T=0时能保持状态不变,T=1时一定翻转的电路,都称为T触发器。

特性方程:

𝑄∗ = 𝑇𝑄′ + 𝑇′𝑄

T Q Q*
0 0 0
0 1 0
1 0 1
1 1 0

D触发器

D触发器可以用作寄存器和分频器。

特性方程:

𝑄∗ = D

1.编码器(coder)

编码:将输入的每个高/低电平信号变成一个对应的二进制代码

普通编码器

只允许一个输入信号有效

I0 I1 I2 I3 I4 I5 I6 I7 Y2 Y1 Y0
1 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 1
0 0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 0 1 1
0 0 0 0 1 0 0 0 1 0 0
0 0 0 0 0 1 0 0 1 0 1
0 0 0 0 0 0 1 0 1 1 0
0 0 0 0 0 0 0 1 1 1 1

优先编码器

允许多个输入信号同时有效,但只按优先级最高的有效输入信号编码。

I0 I1 I2 I3 I4 I5 I6 I7 Y2 Y1 Y0
X X X X X X X 1 1 1 1
X X X X X X 1 0 1 1 0
X X X X X 1 0 0 1 0 1
X X X X 1 0 0 0 1 0 0
X X X 1 0 0 0 0 0 1 1
X X 1 0 0 0 0 0 0 1 0
X 1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0

2.译码器(decoder)

译码:将每个输入的二进制代码译成对应的输出高/低电平信号。

A2 A1 A0 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
0 0 0 0 0 0 0 0 0 0 1
0 0 1 0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0 1 0 0
0 1 1 0 0 0 0 1 0 0 0
1 0 0 0 0 0 1 0 0 0 0
1 0 1 0 0 1 0 0 0 0 0
1 1 0 0 1 0 0 0 0 0 0
1 1 1 1 0 0 0 0 0 0 0

Y0 = A2’A1’A0’ = m0

Y7 = A2A1A0 = m7

3.数据选择器(MUX)

二选一数据选择器

Y = SEL·A + SEL‘·B

SEL A B Y
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 0
1 1 0 1
1 1 1 1

具有n位地址输入的数据选择器,至少可产生输入变量不大于n+1的组合函数

eg:Y1 = D0(A1’A0’) + D1(A1’A0) + D2(A1A0’) + D3(A1A0)

4.竞争—冒险

Y=AB+A’C

在B=C=1的条件下,Y=A+A′⇒稳态下Y=1
当A改变状态时存在竞争-冒险

1.三种基本运算

与(AND)

Y = A&B = A·B = AB

A B Y
0 0 0
0 1 0
1 0 0
1 1 1

Snipaste_2022-04-26_17-59-46.jpg

或(OR)

Y = A | B = A + B

A B Y
0 0 0
0 1 1
1 0 1
1 1 1

Snipaste_2022-04-26_17-59-57.jpg

非(NOT)

Y = A’ = NOT A

A Y
0 1
1 0

Snipaste_2022-04-26_18-00-06.jpg

2.常用的复合逻辑运算

异或(XOR)

A B Y
0 0 0
0 1 1
1 0 1
1 1 0

Snipaste_2022-04-26_18-06-28.jpg

同或(XNOR)

A B Y
0 0 1
0 1 0
1 0 0
1 1 1

Snipaste_2022-04-26_18-06-39.jpg

可以仅用 或非/与非 单独实现 与/或/非

A’ = (A·A)’

A·B = ((AB)’)’

A+B = ((A+B)’)’ = (A’B’)’

3.基本公式和常用公式

基本公式

AA = A A+A = A
AA’ = 0 A+A’ = 1
AB = BA A+B = B+A
(AB)’ = A’+B’ (A+B)’ = A’B’
A(B+C) = AB+AC A+BC = (A+B)(A+C)

常用公式

A B + A′ C + B C = A B + A′ C
A B+ A′ C + B C D = A B + A′ C

4.基本定理

  • 代入定理
  • 反演定理

5.逻辑函数的描述方法

  • 真值表
  • 逻辑式
  • 逻辑图
  • 波形图
  • 卡诺图

真值表 一> 逻辑式

A B C Y
0 0 0 0
0 0 1 0
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 0
  • A=0,B=1,C=1使A‘BC=1
  • A=1,B=0,C=1使AB’C=1
  • A=1,B=1,C=0使ABC′ =1

Y = A‘BC + AB‘C + ABC’

逻辑函数的两种标准形式

  • 最小项之和
  • 最大项之积
最小项 取值 对应 编号
A’B’C’ 0 0 0 0 m0
A’B’C 0 0 1 1 m1
AB’C 0 1 0 2 m2
A’BC 0 1 1 3 m3
AB’C’ 1 0 0 4 m4
AB’C 1 0 1 5 m5
ABC’ 1 1 0 6 m6
ABC 1 1 1 7 m7

最小项的性质

  • 在输入变量任一取值下,有且仅有一个最小项的值为1。
  • 全体最小项之和为1 。
  • 任何两个最小项之积为0 。
  • 两个相邻的最小项之和可以合并,消去一对因子,只留下公共因子。
  • 相邻:仅一个变量不同的最小项

最大项的性质

  • 在输入变量任一取值下,有且仅有一个最大项的值为0;
  • 全体最大项之积为0;
  • 任何两个最大项之和为1;
  • 只有一个变量不同的最大项的乘积等于各相同变量之和。

1. 值传递 VS 引用传递

1
2
int a = 1101; 
String b = "hello";

image-01.png

基本数据类型的变量里直接存放引用类型的变量存放的是实际对象的地址

1
2
3
4
5
6
7
8
9
10
11
void fun(int a){
a = 0;
}
fun(a);
//实际上是实参a的值传递给形参a,不会改变原a的值

void fun(String b){
b = "world";
}
fun(b);
//实际上是实参b的地址传递给形参b,形参b改变其指向的地址,实参b的指向不会发生变化

JAVA只有值传递,没有引用传递。

2. == VS equals

  • 对于基本数据类型,==比较的是两个变量的值是否相等。
1
2
3
int a = 10;
int b = 10;
System.out.println(a == b); //true
  • 对于引用类型,==比较的是两个变量是否指向同一地址。
1
2
3
String a = "hello";
String b = new String("hello");
System.out.println(a==b); //false

JAVA中所有对象都继承自object类,equals是object类的方法之一。

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

但是对于我们常用的String类来说,它重写了equals方法。

1
2
3
String a = "hello";
String b = new String("hello");
System.out.println( a.equals(b) ); //true

String类的equals方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

并不是说 == 比较的就是引用是否相等,equals 比较的就是值,具体情况具体分析。

3. 为什么重写equals()时必须重写hashCode()方法?

  • 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。
  • 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。
  • 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等。

如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。

4. String/StringBuffer/StringBuilder

  • 操作少量的数据: 适用 String (不可变)

  • 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder

  • 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

5. String s1 = new String(“abc”) 创建了几个字符串对象?

  • 如果字符串常量池中不存在字符串对象“abc”的引用,那么会在堆中创建 2 个字符串对象“abc“

  • 如果字符串常量池中已存在字符串对象“abc”的引用,则只会在堆中创建 1 个字符串对象“abc”