JAVA基础高频

包装类型常量池技术

Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False

如果有一个int和一个Integer他们之间可以用==比较吗?

理论上来说因为有包装类的常量池技术,Integer类型的数据如果处于[-128,127] 之间,则可以直接使用==进行判断,但是如果在这个区间之外的数据会在堆上产生,要使用equals方法进行判断

静态变量和静态代码块的执行顺序

类的加载过程分为,加载阶段,链接阶段,初始化阶段。

而链接阶段又分为:验证阶段,准备阶段,解析阶段; 其中在准备阶段是为类变量分配内存和赋初值

所以Java中静态变量和静态代码块是在类加载的过程中就执行的,实例化对象时先实例化变量再执行构造函数

代码和代码块的执行顺序和代码书写顺序一致

代码的初始化过程为:

  1. 初始化父类中的静态成员变量和静态代码块 ;

  2. 初始化子类中的静态成员变量和静态代码块

  3. 初始化父类的普通成员变量和代码块,再执行父类的构造方法;

  4. 初始化子类的普通成员变量和代码块,再执行子类的构造方法;

HashMap 的底层实现

Map结构的理解

Map中key :无序,不可重复,使用set存储, key所在的类重写equals()和hashcode()

Map中的value:无序的,可重复的,使用Collection存储所有的value, Value所在类重写equals()

key-value =Entry对象:无序的,不可重复的,使用set存储所有的entry。

HashMap 底层是 数组和链表 结合在一起使用, HashMap 通过key的hashCode经过扰动函数处理后得到hash值后判断当前元素存放的位置,若当前位置已有元素就要判断与存入元素的hash值和主键是否相同,相同的直接覆盖,不同的用拉链法解决冲突。

为什么默认初始容量为2次幂?

如果 n 为 2次幂,可以保证数据的均匀插入,降低哈希冲突的概率

putVal()原码中

// 如果没有hash碰撞则直接插入元素
    if ((p = tab[i = (n - 1) & hash]) == null) 
        tab[i] = newNode(hash, key, value, null);
    else {
    	......
	}

i = (n - 1) & hash :n是map的容量, 任何2的N次幂-1以后 二进制位上都是1,

n-1与hash做与运算,得到地位的hash值这样发生哈希碰撞的概率更低

HashMap 中的扰动函数是一个通过对 key 值类型自带的哈希函数生成的散列值进行位移计算来扰乱散列值, 以达到降低哈希碰撞的概率的方法

static final int hash(Object key) {
   int h;
   return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

因为 int 类型是 32 位, 但是很少会有数组这么大,(n-1)通常在低位上才有取值,那当(n - 1) & hash时 即使高位不同只有低位相同也会发生hash碰撞,为此 将 hash 值右移16位(hash值的高16位)与 原 hash 值做异或运算(^),从而得到一个新的散列值(同时使用高位信息和低位信息) 减少hash碰撞的概率

hash()

主要是 哈希算法 和 冲突的解决

static final int hash(Object key) {
    if (key == null){
        return 0;
    }
    int h;
    h = key.hashCode();返回散列值也就是hashcode
    // ^ :按位异或
    // >>>:无符号右移,忽略符号位,空位都以0补齐
    //其中n是数组的长度,即Map的数组部分初始化长度
    return (n-1)&(h ^ (h >>> 16));
}

JDK8相较于7中实现方面的不同:

  1. new HashMap()底层没有创建一个长度为16的数组 只赋值了负载因子

  2. jdk8底层数组是:Node[],而不是entry

  3. 首次使用put方法时底层创建长度为16的数组

  4. jdk7底层结构只有:数组+链表,8中数组+链表+红黑树

  5. 当链表形式存在个数>8且当前数组长度>64时 此索引上所有数据改为使用红黑树存储

HashMap get()源码

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(key)) == null ? null : e.value;
    }

    /**
     * Implements Map.get and related methods.
     *
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n, hash; K k;
        //table不为空 且table长度不为0且 tab[hashindex]不为空
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & (hash = hash(key))]) != null) {
            if (first.hash == hash && //检测头结点与 所求key的hash是否相等
                //且头结点的key值是否和key值相等, 或key不为空且key与头结点相等
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;//直接返回头结点
            if ((e = first.next) != null) {//头结点下有链表
                if (first instanceof TreeNode)//instanceof 左边对象是否为instanceof 右边类的实例
                    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;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值