管理多个ssh key

一、生成key

1.命令行执行

ssh-keygen -t rsa -C "yourmail@gmail.com"

2.接着提示存储文件名字

我的命名规则为id_rsa_xxx
ssh-keygen

3.之后可以一直回车结束

二、配置key

1.命令行执行

ssh-add ~/.ssh/id_rsa_xxx
id_rsa_xxx是指你在上述步骤生成的密钥文件名。

2.创建config文件

  • 进入.ssh文件夹,创建一个文本文件,命名为config。
  • 每一个key可以按照一下格式加到config文件,#号代表注释。
1
2
3
4
5
# github
Host github
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_github

三、测试key

1.远程仓库配置ssh key

这个请自行搜索。

2.本地测试是否连通

  • 命令行执行ssh -T github
  • github是在config文件中定义的Host字段。
  • 测试成功会出现以下提示:
    ssh -T

四、补充

  • 如何在finder中查看.ssh,请搜索mac如何显示隐藏文件。
  • 查看ssh版本ssh -V

Java集合容器之HashMap

1.继承关系

1
2
3
4
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
...
}

继承自AbstractMap。AbstractMap实现了Map接口的方法,如增删改查方法。

2.Entry类

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
29
30
31
32
33
34
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
...
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
...
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
  • final int hash;这个变量代表这个Entry的key的hash结果。
  • Node next;这个变量表明这是一个单链表。

3.图像理解数据结构

HashMap

  • 左侧是一个一位数组,Hash表。Entry中的hash指的的就是这个数组的下标,用于快速查找或插入。
  • 从数组的每个节点开始延伸一条单链表。Entry中的next构成这条单链表。

4.重要方法

put(key,value)

大致流程是:
1.判断是否要扩容(resize方法);
2.根据key的hash值找到一维数组的下标从而找到链表的头,当然key为null时要特殊处理;
3.遍历单链表,判断是否有Entry的key与参数key一摸一样,如果一样直接更新Entry,返回旧的value值,否则遍历到链尾追加节点;
4.更新成员变量如size,调用resize方法,返回null,说明时增加了新节点,而不是更新节点。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

get(key)

大致流程是:
1.根据key的hash结果查找Hash表;
2.遍历单链表,如果找到,返回Entry的value值,否则返回null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}

5.补充

  • Java8之后,HashMap追加了红黑树实现的Entry(代码中的TreeNode类),当链长超过8之后自动转换为红黑树。有兴趣的读者请自行查阅。

Java集合容器之LinkedHashMap

1.继承关系

1
2
3
4
5
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V> {
...
}

LinkedHashMap是HashMap的子类,从面向对象设计思想上讲,LinkedHashMap更多的是增加或改写HashMap的方法。

2.Entry类

1
2
3
4
5
6
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
LinkedHashMapEntry<K,V> before, after;
LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}

LinkedHashMapEntry是HashMap.Node的子类,构造方法直接调用父类构造方法,额外加多两个前后引用。

  • next引用是提供给父类HashMap.Node构建HashMap的单链表的!
  • before, after是构建一个双向回环链表!
  • 两者并无关联,也不冲突!

3.图像理解数据结构

  • 上一节提及到,双链表和HashMap并不冲突,所以HashMap部分可以参考HashMap。
  • 以下为双向回环链表部分。
    双向回环链表

4.与HashMap比较

  • 遍历集合时,LinkedHashMap保留元素进入顺序,HashMap则无法保证元素进入顺序。当然要耗费一点性能。
  • LinkedHashMap每次都将元素加入至双向链表的尾部,利用这个特性实现LruCache,并不是因为LruCache的需要而实现了LinkedHashMap。

5.参考资料

http://www.cnblogs.com/xrq730/p/5052323.html