1、HashSet底层原理:
它实现了Set接口,由哈希表支持(实际上是一个HashMap的实例)。元素不重复;不保证set的迭代顺序;特别是它不保证顺序恒久不变。此类允许使用null元素。HashSet的存储方式是把HashMap中的Key作为Set的对应存储项。该行的value就是object类型的常量
2、为什么无重复?
HashSet的存储方式是把HashMap中的key作为Set的对应存储项。因为hashMap的key是不能有重复的
3、HashSet的实现:
对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成,(实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75)
对于HashSet中保存的对象,请注意正确重写equals和hashCode方法,以保证放入的对象的唯一性
一定要覆盖自定义类的equals和hashCode方法,hashCode方式是找到当前对象在Node数组的位置,而equals是比较当前对象与对应坐标链表中的对象是否相同
当有新的值加入的时候,底层的HashMap会判断key值是否存在,如果不存在,则会插入新值吗,同时这个插入的细节会依照HashMap插入细节;如果存在就不插入
4、HashMap底层原理:
4.1、概述:hashMap是基于哈希表的Map 接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序的恒久不变
4.2、数据结构:hashMap实际上是一个“数组+链表+红黑树”是数据结构
4.3、HashMap的存取实现:
(1.8之前):当我们往hashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(及下标),如果数组该位置上已经有存放其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素。就直接将该元素放到此数组中的该位置上。
(1.8):PUT():1、根据key计算得到key.hash值
2、根据hash.key计算得到通数组的索引index,这样就找到该key的存放位置:如果该位置没有数据,用该数据新生成一个节点保存新数据,返回null;
如果该位置有数据是一个红黑树,那么执行相应的插入/跟新操作
如果该位置有数据是一个链表,分两种情况一是该链表没有这个节点,另一个是该链表上有这个节点,注意这里判断依据是key.hash是否一样;如果该链表没有这个 节点,那么采用尾插法新增节点保存新数据,返回null;如果该链表已有这个节点了,那么找到该节点并更新新数据,返回老数据
get():计算须获得数据的hash值(计算过程跟put一样),计算存放在数组table中的位置,然后依次在数组、红黑树、链表中查找(通过equals判断),最后在判断获取的数据是否为空,若为空返回null否则返回该数据
5、树化与还原
5.1、哈希表的最小树形化容量
5.2、当哈希表中的容量大于这个值时(64),表中的桶才能进行树形化
5.3、否则桶内元素太多时会扩容,而不是树形化
5.4、为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD
5.5、一个桶的树化阈值
5.6、当桶中元素个数超过这个值时(8),需要使用红黑树节点替换链表节点
5.7、这个值必须为 8,要不然频繁转换效率也不高
5.8、一个树的链表还原阈值
5.9、当扩容时,桶中元素个数小于这个值(6),就会把树形的桶元素 还原(切分)为链表结构
5.10、这个值应该比上面那个小,至少为 6,避免频繁转换
条件1. 如果当前桶数组为null或者桶数组的长度 < MIN_TREEIFY_CAPACITY(64),则进行扩容处理 (见代码片段2:resize());
条件2. 当不满足条件1的时候则将桶中链表内的元素转换成红黑树!!!稍后再详细讨论红黑树。
6、扩容机制的实现
6.1、扩容(resize)就是重新计算容量。当向hashMap对象里不停添加元素,而hashMAP对象内部桶数组无法装载更多的元素时,hashMap对象就需要扩大桶数组的长度,以便能装入更多的元素
6.2、capacity就是数组的长度/大小,loadFactor是这个数组填满程度的最大比比例
6.3、size表示当前hashMap中已经存储的NOde的数量,包括桶数组和链表/红黑树
6.4、threshold表示扩容的临界值,如果size大于这个这个值,则必须调用resize方法进行扩容
6.5、扩容满足两个条件:1、存放新值的时候,当前已有元素的个数(size)必须大于等于阈值
2、存放新值的时候当前存放数据发生hash碰撞,且key值一样,则覆盖原值value,并返回原值value
6.6、resize()方法:2种使用情况:1、初始化哈希表、2、当前数组容量过小,需要扩容
7、ConcurrentHashMap的工作原理
7.1、概念:它的目标是实现支持高并发、吞吐量的线程安全的hashMap
8、Hashtable底层原理
概念:继承Dictionary类,实现了Map接口。大部分的操作都是通过synchronized锁保护的,是线程安全的,key、value都不可以为null,每次put方法不允许null值,如果发现是null,则直接抛出异常
官方文档也说了:如果在非线程安全的情况下使用,建议使用hashMap替换,如果在线程安全的情况下使用,建议使用Concurrenthashmap
9、IO、NIO、AIO的原理
同步:后续的任务是等待当前调用返回,才会进行下一步;
异步:其他任务不需要等待当前调用返回;
阻塞:在进行阻塞操作时,当前线程会处于阻塞状态,无法从事其他任务,只有当条件就绪才能继续
非阻塞:不管IO操作是否结束,直接返回,相应操作在后台继续处理
IO:传统的java.io包,基于流模型实现。交互方式是同步、阻塞的方式。
NIO:指新IO,核心是同步非阻塞,解决传统IO的阻塞问题。操作对象是Buffer.NIO的核心是IO线程池
AIO:也就是NIO 2 ,引入了异步非阻塞IO方式。简单理解为,应用操作直接返回,而不会阻塞在那里,当后台处理完成,操作系统会通知相应线程进行后续工作
10、equals 与 == ,hashcode()的区别
== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

两个对象的 hashCode() 相同,equals() 不一定 true。(因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。)
1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的

11、如何解决跨域问题呢?
1)CORS 全称为 Cross Origin Resource Sharing(跨域资源共享) 浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,但用户不会有感觉。因此,实现CORS通信的关键是服务端。服务端只需添加相关响应头信息,即可实现客户端发出 AJAX 跨域请求。 值得注意的是,浏览器必须先以 OPTIONS 请求方式发送一个预请求,从而获知服务器端对跨源请求所支持 HTTP 方法。 不幸的是,CORS不支持IE8、IE9
2)搭建中间转发层
跨域问题的核心是什么?不同源访问。是啊,如果我们转换成同源请求,就不存在这个问题啦。 通过将服务端的请求进行转发
3)Nginx反向代理(常用)
首先,产品需要搭建一个中转nginx服务器,用于转发请求。当然,我们都是基于Nginx作为反向代理,所以当然是水到渠成。
那么,Nginx的思路,就是通过Nginx解析URL地址的时候进行判断,将请求转发的具体的服务器上。
12、常见的异常类
NullPointerException 空指针异常
ClassNotFoundException 指定类不存在
NumberFormatException 字符串转换为数字异常
IndexOutOfBoundsException 数组下标越界异常
ClassCastException 数据类型转换异常
FileNotFoundException 文件未找到异常
NoSuchMethodException 方法不存在异常
IOException IO 异常
SocketException Socket 异常
13、Servlet生命周期
Web 容器加载 Servlet 并将其实例化后, Servlet 生命周期开始,容器运行其 init 方法进行
Servlet 的初始化,请求到达时运行其 service 方法, service 方法自动派遣,运行请求的
doXXX 方法(doGet、 doPost),当服务器决定将实例销毁的时候调用其 Destroy 方法。
Servlet的生命周期包含了下面4个阶段:
①实例化阶段:服务器对Servlet进行实例化,调用Servlet的构造方法
②初始化阶段:服务器调用Servlet的init方法进行初始化(只在第一次请求时调用)。
③请求处理阶段:服务器调用Servlet的service方法,然后根据请求方式调用相应的doXXX方法。
④服务终止阶段:服务器调用Servlet的destroy方法销毁Servlet实例
1.
Servlet 生命周期:Servlet 加载—>实例化—>服务—>销毁。
2.
init():在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet 对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行 init()。
3.
service():它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的 Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应” (ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法 相应的do功能。
4.
destroy(): 仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资 源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。

原文链接:https://blog.csdn.net/Butterfly_resting/article/details/89668402