标签:blank java8 string string类 log als entry 试题 hashmap
力争清晰完整准确(逐步完善,持续更新)
1、String类为什么是final的
首先分析String的源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
private 限定符,保证String字符串数组的值不可在类外被修改。由于未对外暴露可修改的接口,所以String的值一旦被创建,即不可被修改。
因为字符串是不可修改的(只能读不能写),多个线程可以共享同一个字符串实例。
字符串常量池,详见 https://segmentfault.com/a/1190000009888357
2、JDK8的HashMap的源码,实现原理,底层结构
HashMap的Hash冲突解决,后面单独会写一篇博客。
ConcurrentHashMap的锁分段,大厂很喜欢问(最近华为电话面试问过我),简单说一句,就是hashMap的数据是一个数组,用多个锁来锁,一个锁锁一部分数据。
不像以前一个锁锁住整个数组,多个线程可分段访问这些数据,自然效率就高了。后面单独写一篇博客,系统论述这个问题。
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) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
HashMap用 transient Node<K,V>[] table 存值,本质上是链表数组(哈希数组+链表+红黑树),是Hash散列的,即数组不是紧密排列的,详见下图
图01
为什么有红黑树,看put(新增元素)的源码片段,如下:
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
TreeNode定义的源码片段,如下:
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
默认容量-16。resize时,newCap = oldCap << 1( 2进制,左移1位,即*2,旧的容量翻倍,容量可能不是2的幂)
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
1)如果以前这个key有值,put 操作会用新值替换旧值。
2)Hash冲突怎么解决
hash(散列),就是key和存储位置有个映射关系f,我们称之为hash函数。hash冲突,就是不同的key,根据hash函数算出来的存储位置相同,后面添加的元素就和原来的hashCode冲突了,所以要重新按照一定规则计算存储位置。普通HashMap(java 8的HashMap结构如“图1”,有红黑树)结构如下图:
java8 中的HashMap为了提高查找效率,当链表冲突过高,大于阈值时,会将链表转化成红黑树
static final float DEFAULT_LOAD_FACTOR = 0.75f;
load factor默认0.75 ,这个和概率统计有关,详见 http://en.wikipedia.org/wiki/Poisson_distribution
为了减少冲突,当hashMap的数组长度 > 临界值 就会触发扩容,所有元素rehash(重新计算hashCode和存储位置)再放到扩容后的容器中,因为涉及到计算、数据查找、内存拷贝、移动等操作,非常耗时。
临界值 = current capacity * current load factor。默认临界值 = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR = 16 x 0.75 = 12时,就会触发扩容操作。
*****************************************************************************************************
精力有限,欲望太多,专注做好一件事就行
*****************************************************************************************************
阿里《JAVA实习生入职测试题—2019最新》之答案详解(连载一)
标签:blank java8 string string类 log als entry 试题 hashmap
原文地址:https://www.cnblogs.com/NaughtyCat/p/alibaba-java-interview-serial-1.html