Java基础——HashMap/ArrayList/LinkedList/反射

1、Map:只存60个键值对,需要设置初始化容量吗?设置的话设置多少初始化容量
A:需要 否则需要多次扩容 128 要考虑数组长度是2的幂次方、负载因子

HashMap有扩容机制,就是当达到扩容条件时会进行扩容。HashMap的扩容条件就是当HashMap中的元素个数(size)超过临界值(threshold)时就会自动扩容。在HashMap中,threshold = loadFactor * capacity。
    loadFactor译为装载因子。装载因子用来衡量HashMap满的程度。loadFactor的默认值为0.75f。计算HashMap的实时装载因子的方法为:size/capacity.
    capacity译为容量。capacity就是指HashMap中桶(桶,也就是这个要添加 HashMap 里的这个数据对应到数组的位置下标 )的数量。默认值为16。一般第一次扩容时会扩容到64,之后是2倍。总之,容量都是2的幂。

"容量不是2的整数次幂 还用&(length-1) 影响会怎样?"
容量是2的整数次幂,n -1 后,高位为1后的0都变为1,如 1610000, 16-1=151111, 1111 再与 hash 做 & 运算的时候,各个位置的取值取决于 hash;如果不是2的整数次幂,必然会有的0的位,0与任何数&肯定为0,会造成更多的哈希冲突
    
https://blog.csdn.net/weixin_44844089/article/details/105868599
SIZE:hashmap中键值对的数量
INITIAL_CAPACITY:默认容量16
capacity:数组长度
threshold = loadFactor * capacity
2、hashMap put get过程
1"hashmap底层是使用数组+链表+红黑树实现的",初始容量为16,默认的负载因子为0.75,每次扩容为原来的两倍。
2、hashmap线程不安全, 当存在多个线程同时写入数据时,可能会导致数据不一致。多线程使用ConcurrentHashMap
插入元素:首先将元素的hashcode值高16位与低16位异或得到hash值,之后将hash值与数组的长度-1进行与操作来得到桶的位置,如果发现hash冲突的话,那么就通过拉链来解决问题,如果没有冲突,那就new一个新的链表放进桶中,每次插入是尾插法。当链表长度大于8时,就会转化为红黑树。
查找元素:与插入相似,首先获取到hash值,然后找到桶,开始遍历链表或者红黑树,每次查找首先比较hashcode方法,如果hashcode相同,再比较equals方法。

"为什么%要换成&运算呢?"
其实是因为&运算,是位运算,而%取余不是位运算,系统底层用的是位运算,对于%取余操作需要转换后才能运算,所以**&运算比取余操作效率高**。

你也肯定会问,为什么&能替代%操作?是因为HashMap中桶数组长度length总是2的次幂,此时 (length - 1) & hash 等价于对length取余。
3、hashmap什么时候退回链表?为什么不是7
"HashMap底层链表转红黑树的阈值是>=8并且数组长度要>=64。而当红黑树的节点个数<=6个以后,又开始使用链表。"
首先出结论:和hashcode碰撞次数的泊松分布有关,主要是为了寻找一种时间和空间的平衡。
红黑树中的TreeNode是链表中的Node所占空间的2倍,虽然红黑树的查找效率为o(logN),要优于链表的o(N),但是当链表长度比较小的时候,即使全部遍历,时间复杂度也不会太高。固,要寻找一种时间和空间的平衡,即在链表长度达到一个阈值之后再转换为红黑树。

之所以是8,是因为Java的源码贡献者在进行大量实验发现,hash碰撞发生8次的概率已经降低到了0.00000006,几乎为不可能事件,如果真的碰撞发生了8次,那么这个时候说明由于元素本身和hash函数的原因,此次操作的hash碰撞的可能性非常大了,后序可能还会继续发生hash碰撞。所以,这个时候,就应该将链表转换为红黑树了,也就是为什么链表转红黑树的阈值是8。

最后,红黑树转链表的阈值为6,主要是因为,如果也将该阈值设置于8,那么当hash碰撞在8时,会反生链表和红黑树的不停相互激荡转换,白白浪费资源。
4、jdk1.8引入红黑树后,如果单链表节点个数超过8个,是否一定会树化?
不一定,它会先去判断是否需要扩容(即判断当前节点个数是否大于扩容的阈值),如果满足扩容条件,直接扩容,不会树化,因为扩容不仅能增加容量,还能缩短单链表的节点数,一举两得。
5、HashMap扩容的原因?
提升HashMap的get、put等方法的效率,因为如果不扩容,链表就会越来越长,导致插入和查询效率都会变低。
6、hashmap扩容时每个entry需要再计算一次hash吗?
1)在jdk7中是需要进行重新hash的,但是在jdk8中做了一定的优化
2)只需要看原来的hash值在扩容后新增的那一位是1还是0,如果是0的话索引没变,是1的话索引变成“原索引+oldcapacity“ 
3)具体优化细节在下面有讲解
https://blog.csdn.net/weixin_44844089/article/details/105868599
4、ArrayList与LinkedList的区别

https://blog.csdn.net/weixin_44844089/article/details/105856813

两者都继承了list,collection接口,但Linkedlist还继承了Queue接口

两者都是线程不安全的

扩容机制:
1.Arraylist是动态扩容机制,初始容量为10,扩容机制为1.5倍。初始最大容量为Integer.MAX_VALUE - 8,原因是防止内存溢出,增加容错率。但是实际最大容量还是可以达到Integer.MAX_VALUE

2.Linkedlist的扩容就是新建节点进行指针指向即可

增加元素:
1.Arraylist在尾部增加元素很快,时间复杂度为O1),但是在中间增加元素需要移动大量的元素,时间复杂度为O(n)

2.Linkedlist在尾部和中间增加元素的时间复杂度都是O1),但是在中间添加元素需要先遍历找到插入位置

删除元素机制和增加元素基本类似

查询元素
1.Arraylist中的get方法直接通过index去获取元素,时间复杂度为O12.Linkedlist中的就需要遍历链表,时间复杂度为O(n)

总的来说,Arraylist支持高效的随机元素访问,LinkedList在插入和删除元素方面比较高效!
5、JAVA类加载过程
"加载" "验证" "准备" "解析(可以在初始化的后面)" "初始化"
加载:将jvm字节码文件加载到内存中,jvm使用双亲委派机制保护jvm内部的安全,以及防止类的重复加载加载class文件,将其转化为某种静态的数据结构存放在方法区内,并在堆中生成一个Java.lang.Class类型的对象,表示堆方法区中类的引用
验证:文件格式验证(加载时) 元数据验证|字节码验证、(对class的静态结构进行语法和语义上的分析,保证其不会危害虚拟机)、符号引用验证(解析时验证),验证遍布在各个阶段,主要验证加载的文件是否符合jvm规范
准备:为该类型定义的静态变量设置为默认值
解析:将类中的符号引用转化为直接引用(将符号(代表地址)直接替换成实际地址)
初始化:初始化静态常量和成员变量
6、哈希表的作用 哈希表使用的数据结构 哈希内部解决哈希冲突的方式有哪几种
1、哈希表(Hash Table,又叫散列表),是存储键值对(Key-value)的表,之所以不叫它Map(键值对一起存储一般叫做Map),是因为它下面的特性:它能把关键码(key)映射到表中的一个位置来直接访问,这样访问速度就非常快。其中的映射函数称为散列函数(Hash function)2、哈希表是基于数组实现的,因为只有数组才可以直接通过下标获取对应的元素
3、解决这个冲突,我们一般有两种方式:开放地址法和链地址法
开放地址法:寻找数组中空白位置,有三种方法:线性探测,二次探测和再哈希探测。
    线性探测:线性探测是每次以1的步长去查找空白位置
    二次探测:二次探测就是每次探测的步长是步数的平方,像x+1^2, x + 2 ^2, x + 3^2等等这样,这样就可以避免局部聚集的情况了。
    再哈希探测:
链地址法:数组中不在存放真实的值,而是一个链表。查找的时候,就是先通过哈希化得到的下标,找到数组对应下标存放的链表,然后再遍历链表。
7、反射

反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象, 都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所 有信息。

Java高级特性——反射 - 简书 (jianshu.com)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值