HashMap底层
答:数组+链表+红黑树
抛开红黑树为啥是数组+链表得组合呢,首先得来说说HashMap添加元素方法,他是拿你传入得key计算得到hash值,这个hash值作为数组下标,先拿该下标去数组中查找,如果该下标没有元素,则直接在该数组下标插入元素,如果该数组下标已经存在了,那么判断该下标下面元素的key和当前key是否相等,相等就替换值,如果不相等的话,就会判断该下标元素的下一个节点,如果没有下一个节点就把该元素作为下一个节点,这样hash值相同,key不等得元素就会在数组同一个下标下面组成链表
拓展:
HashMap的红黑树在哪里体现呢?
红黑树是JDK8中对HashMap作的一个变更,在JDK7之前,HashMap采用数组+链表的形式存储数据,我们知道优秀的hash算法应避免碰撞的发生,但假如开发者使用了不合适的hash算法,O(1)级别的数组查询会退化到O(n)级链表查询,因此在JDK8中引入红黑树的,当一个结点的链表长度大于8时,链表会转换成红黑树,提高查询效率,而链表长度小于6时又会退化成链表。
可参考文章:
ConcurrentHashMap get时要不要加锁
答:不需要加锁
背景:
如下代码:之所以get不用加上,那是由于关键字volatile,它可以保证 可见性,不保证原子性,禁止指令重排
/**
* The array of bins. Lazily initialized upon first insertion.
* Size is always a power of two. Accessed directly by iterators.
*/
transient volatile Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
//这里得value用volatile
volatile V val;
volatile Node<K,V> next;
Node(int hash, K key, V val) {
this.hash = hash;
this.key = key;
this.val = val;
}
Node(int hash, K key, V val, Node<K,V> next) {
this(hash, key, val);
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return val; }
public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
public final String toString() {
return Helpers.mapEntryToString(key, val);
}
public final V setValue(V value) {
throw new UnsupportedOperationException();
}
public final boolean equals(Object o) {
Object k, v, u; Map.Entry<?,?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
(v = e.getValue()) != null &&
(k == key || k.equals(key)) &&
(v == (u = val) || v.equals(u)));
}
/**
* Virtualized support for map.get(); overridden in subclasses.
*/
Node<K,V> find(int h, Object k) {
Node<K,V> e = this;
if (k != null) {
do {
K ek;
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
} while ((e = e.next) != null);
}
return null;
}
}
参考文章:
为什么ConcurrentHashMap的读操作不需要加锁?
MySQL的底层InnoDB数据结构
B-Tree
SpringBoot的一些常用注解
- @Controller
- @Service
- @Autowired spring的自动装配
- @ResponseBody 表示该方法的返回结果直接写入HTTP response body中
- @RestController
- @PathVariable 路径变量。 参数与大括号里的名字一样要相同。
RequestMapping("/getInfo/{userId}")
public String getByMacAddress(@PathVariable String userId){
}
@SpringBootApplication是由那几个注解组成
由以下三个注解组成
SpringBoot一些配置文件
用过 Spring Boot 的都知道在 Spring Boot 中有以下两种配置文件
- bootstrap (.yml 或者 .properties)
- application (.yml 或者 .properties)
在 Spring Boot 中有两种上下文,一种是 bootstrap, 另外一种是 application, bootstrap 是应用程序的父上下文,也就是说 bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。
因此,对比 application 配置文件,bootstrap 配置文件具有以下几个特性。
- boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载
- boostrap 里面的属性不能被覆盖
bootstrap/ application 的应用场景
application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景。
- 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
- 一些固定的不能被覆盖的属性
- 一些加密/解密的场景;
微服务的框架
Java中equals是否只能判断String类型
equals是Object类中的方法,也就是说所有继承Object类的子类都是拥有equals方法的,也就是说所有继承java.lang.Object类的子类创建的对象都是可以用equals判断的,比如Integer,Boolean,Long包括集合类型List,Map等都是具有可以使用equals方法判断的