Java常问面试题概要答案

news/2024/11/28 23:56:46/

文章目录

  • 1.JDK、JRE、JVM的区别
  • 2.hashcode()与equals()之间的关系
  • 3.String、StringBuffer、StringBuilder的区别
  • 4.Java泛型
  • 5.ArrayList和LinkedList区别
  • 6.ConcurrentHashMap
  • 7. B树和B+树
  • 8.负载均衡常见策略

1.JDK、JRE、JVM的区别

JDK:java标准开发包,包含java编译器、java运行时环境
JRE:java运行环境,用于运行java字节码文件,包含jvm及jvm所需类库
JVM:java虚拟机,负责运行字节码文件
简而言之,就是JDK包含JRE、JRE又包含了JVM

2.hashcode()与equals()之间的关系

java中,每个对象都可以通过hashcode()方法获取到自己的hash值,除了一些java提供的类中,自己重写了hashcode()以及equals()外,在我们新建对象时,有时候也需要重写这两个方法。

备注:对于基本数据类型而言使用==比较的是两者的值,
而对于对象类型而言则是比较的是对象的地址,所有类都是Object类的子类,不重写hashcode()方法时,使用是Object默认的hashCode()方法,导致对象内容一致但是地址不一样

Java API文档中关于hashCode方法有以下几点规定:
(1)在java应用程序执行期间,如果在equals方法比较中所用的信息没有被修改,那么在同一个对象上多次调用hashCode方法时必须一致地返回相同的整数。如果多次执行同一个应用时,不要求该整数必须相同。
(2)如果两个对象通过调用equals方法是相等的,那么这两个对象调用hashCode方法必须返回相同的整数。
(3)如果两个对象通过调用equals方法是不相等的,不要求这两个对象调用hashCode方法必须返回不同的整数。但是程序员应该意识到对不同的对象产生不同的hash值可以提供哈希表的性能。

重写以后我们可以通过该对象作为map的key做数据的存取、可以在集合、java8 stream等集合操作总进行比较、去重

3.String、StringBuffer、StringBuilder的区别

(1)String为常量字符串,修改时会生成新的字符串对象,StringBuffer和StringBuilder是可变的
(2)StringBuffer线程安全的(方法被synchronized修饰),StringBuilder是线程不安全的,单线程时StringBuilder的效率更高

4.Java泛型

(1)无限制类型擦除
当在类的定义时没有进行任何限制,那么在类型擦除后将会被替换成Object,例如、<?>都会被替换成Object
(2)有限制类型擦除
当类定义中的参数类型存在上下限(上下界),那么在类型擦除后就会被替换成类型参数所定义的上界或者下界,例如<? extend Person>会被替换成Person,而<? super Person>则会被替换成Object

5.ArrayList和LinkedList区别

(1)底层数据结构不同,ArrayList是基于数组实现的,LinkedList是基于链表实现的
(2)由于底层数据结构不同,ArrayList更适合随机查找,LinkedList更适合元素修改
(3)ArrayList和LinkedList都实现了List接口,但是LinkedList还实现了Deque接口,还可以当做队列使用
(4)由于底层数据结构不同,其物理存储空间不同,数组元素是连续空间,而链表则是通过指针指向来实现元素连接,其空间不一定连续

6.ConcurrentHashMap

(1)存储 :调用map.put(k, v)方法。
第一步:先将k, v封装成Node节点对象。

第二步:底层调用k类重写之后的hashCode()方法,得出k的int型哈希值。

第三步:拿到k的哈希值,通过哈希函数算法,将k的哈希值转换成数组的下标(如有16个槽位,根据算法得到下标为3,此时应该将这个key放在下标3的元素下,而这个元素可以是链表、树结构)。

第四步:拿到下标后,如果数组下标位置上没有链表,就把Node对象添加到这个位置上。
如果下标处有链表,此时会拿着Node对象的k和链表中的每一个节点的key,用equals()方法进行比对,如果发现key有相同的,直接用Node对象的v覆盖掉原来旧的value。如果比完了该链表,发现没有key相同的节点,直接存储在该链表的末尾位置。
在这里插入图片描述
jdk8版本之后
当HashMap底层数组中每个单向链表的元素超过8之后,底层会把该链表变成红黑树结构。
当红黑树节点小于6之后,会重新变成单向链表结构

(2)并发(线程安全)
JDK1.7版本:
ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成,即 ConcurrentHashMap 把哈希桶数组切分成小数组(Segment ),每个小数组有 n 个 HashEntry 组成。
如下图所示,首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据时,其他段的数据也能被其他线程访问,实现了真正的并发访问。
在这里插入图片描述

Segment 是 ConcurrentHashMap 的一个内部类,Segment 继承了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。Segment 默认为 16,也就是并发度为 16。volatile 修饰了 HashEntry 的数据 value 和 下一个节点 next,保证了多线程环境下数据获取时的可见性

JDK1.8版本
Node数组(Node、TreeNode)+链表+红黑树结构;在锁的实现上,采用CAS + synchronized实现更加细粒度的锁。
在这里插入图片描述

TreeBin
TreeBin从字面含义中可以理解为存储树形结构的容器,而树形结构就是指TreeNode,所以TreeBin就是封装TreeNode的容器,它提供转换黑红树的一些条件和锁的控制.

存储元素流程如下:
1.根据 key 计算出 hash 值;
2.判断是否需要进行初始化;
3.定位到 Node,拿到首节点 f,判断首节点 f:
4.如果为 null ,则通过 CAS 的方式尝试添加;
5.如果为 f.hash = MOVED = -1 ,说明其他线程在扩容,参与一起扩容;
6.如果都不满足 ,synchronized 锁住 f 节点,判断是链表还是红黑树,遍历插入;

常问面试题:
HashMap、HashTable、ConcurrentHashMap的区别、扩容机制、线程安全实现原理

7. B树和B+树

(1)B树(balance tree)多路平衡查找树
在这里插入图片描述
类似于普通的二叉树,允许1每个阶段有更多的叶子节点。
B树的特点:
1.所有键值分布在整颗树中(索引值和具体data都在每个节点里);
2.任何一个关键字出现且只出现在一个结点中;
3.搜索有可能在非叶子结点结束(最好情况O(1)就能找到数据);
4.在关键字全集内做一次查找,性能逼近二分查找;

B+树:
B+树是B-树的变体,也是一种多路搜索树, 它与 B- 树的不同之处在于:

所有关键字存储在叶子节点出现,内部节点(非叶子节点并不存储真正的 data)
为所有叶子结点增加了一个链指针

在这里插入图片描述

因为非叶子节点并不存储 data,所以一般B+树的叶节点和非叶子节点大小不同,而B-树的每个节点大小一般是相同的,为一页
在这里插入图片描述

为了增加 区间访问性,一般会对B+树做一些优化。
如下图带顺序访问的B+树, 带顺序可以提升检索的效率
在这里插入图片描述

** B-树和B+树的区别**
1.B+树内节点不存储数据,所有 data 存储在叶节点导致查询时间复杂度固定为 log n。而B-树查询时间复杂度不固定,与 key 在树中的位置有关,最好为O(1)。

如下所示B-树/B+树查询节点 key 为 50 的 data。

B-树:
在这里插入图片描述

从上图可以看出,key 为 50 的节点就在第一层,B-树只需要一次磁盘 IO 即可完成查找。所以说B-树的查询最好时间复杂度是 O(1)。

B+树:
在这里插入图片描述

由于B+树所有的 data 域都在根节点,所以查询 key 为 50的节点必须从根节点索引到叶节点,时间复杂度固定为 O(log n)。

总结:B树的由于每个节点都有key和data,所以查询的时候可能不需要O(logn)的复杂度,甚至最好的情况是O(1)就可以找到数据,而B+树由于只有叶子节点保存了data,所以必须经历O(logn)复杂度才能找到数据

  1. B+树叶节点两两相连(添加指针)可大大增加区间访问性,可使用在范围查询等(这就是为什么面试时有时会问为什么用b+树而不用hash作为索引的数据结构的原因之一),而B-树每个节点 key 和 data 在一起,则无法区间查找。
    在这里插入图片描述

根据空间局部性原理:如果一个存储器的某个位置被访问,那么将它附近的位置也会被访问。

B+树可以很好的利用局部性原理,若我们访问节点 key为 50,则 key 为 55、60、62 的节点将来也可能被访问,我们可以利用磁盘预读原理提前将这些数据读入内存,减少了磁盘 IO 的次数。
当然B+树也能够很好的完成范围查询。比如查询 key 值在 50-70 之间的节点。

总结:由于B+树的叶子节点的数据都是使用链表连接起来的,而且他们在磁盘里是顺序存储的,所以当读到某个值的时候,磁盘预读原理就会提前把这些数据都读进内存,使得范围查询和排序都很快

3.B+树更适合外部存储。由于内节点无 data 域,每个节点能索引的范围更大更精确

这是因为,由于B-树节点内部每个 key 都带着 data 域,而B+树节点只存储 key 的副本,真实的 key 和 data 域都在叶子节点存储。前面说过磁盘是分 block 的,一次磁盘 IO 会读取若干个 block,具体和操作系统有关,那么由于磁盘 IO 数据大小是固定的,在一次 IO 中,单个元素越小,量就越大。这就意味着B+树单次磁盘 IO 的信息量大于B-树,从这点来看B+树相对B-树磁盘 IO 次数少。

总结:由于B树的节点都存了key和data,而B+树只有叶子节点存data,非叶子节点都只是索引值,没有实际的数据,这就时B+树在一次IO里面,能读出的索引值更多。从而减少查询时候需要的IO次数!

常问面试
B+树是什么样的数据结构?
如上,略.
Mysql为什么用B+树作为索引而不用其他结构呢?

  1. 二叉树与B+数同属于树结构,但是如果在我们进行数据读取时,二叉树的深度就很深,会导致磁盘读写多次。而B+树的深度要远低于二叉树,并且一次性可以从磁盘中读取多条数据,这样能降低磁盘IO的次数。通俗的话来说就是把高瘦的树变成矮胖的树,磁盘IO次数就能减少。
  2. 为什么不用B树
    (1)每个节点中有key,也有data,但是每一个节点(磁盘页)的存储空间是有限的,如果data数据较大时会导致每个节点能存储的key的数据很小,最后导致B树的高度较大,磁盘IO次数增多。
    (2)索引和内容分散在整个B+树上,离根节点近搜索快,离根节点远搜索慢,花费的IO时间不平均。
    (3)B树不方便做范围搜索,例如要查找大于3小于10的数据,则需要先达到磁盘块5找到3,然后回到磁盘块2比较,在到磁盘块6找到9,这相当于进行了局部的中序遍历,情况更糟的情况下可能还要跨层访问。
    3.为什么不用红黑树
    (1)数据是单边增长的情况 那么出现的就是和链表一样的数据结构,树高度大,红黑树的目的主要是解决这个问题。
    (2)B树和B+树克服了红黑树克服不了的困难,因为随着数据量增多,红黑树的高度必然也会变得很高,造成磁盘IO次数的增加
    4.为什么不适用hash
    如果只是查找一条数据那确实效率很快(进行一次哈希运算即可),但我们需要考虑查询多条数据的情况,B+树索引有序,加上B+树有链表相连,这时候效率就比hash高,并且支持范围查找。

4.B+树的优势
接下来我们来看一下使用B+树作为MySQL索引存储的数据结构的示例图。所有数据保存在叶子节点上,叶子节点有链表相连。
在这里插入图片描述

1.跟B树相比,B+树的叶子结点是一条链表,会将搜有的数据连接在一起,做整表遍历和区间查找是非常容易的,例如查找3到15范围内的数据,通过链表就能把所有数据取出来了(即磁盘块4和磁盘块5是相连的)。
2.每个非叶子节点只存放key值,这样一个节点就能存放更多的key值,从而降低树的层高。
3.B+树所有的数据都存在叶子节点上,找到对应数据的时间比较平均的。

8.负载均衡常见策略

1.轮循:如有AB两个同种服务,这次访问A,下次就访问B
2.加权轮循:如A服务的服务器 16G B服务的服务器32G,我们可以配置1:2的权重,这意味着在服务器 A 接收到第一个请求后,服务器 B 会连续的接收到 2 个请求
3.最少连接数
以上两种方法都没有考虑的是系统不能识别在给定的时间里保持了多少连接。因此可能发生,服务器 B 服务器收到的连接比服务器 A 少但是它已经超载,因为 服务器 B 上的用户打开连接持续的时间更长。这就是说连接数即服务器的负载是累加的。这种潜在的问题可以通过 “最少连接数” 算法来避免:传入的请求是根据每台服务器当前所打开的连接数来分配的。即活跃连接数最少的服务器会自动接收下一个传入的请求。基本上和简单轮询的原则相同:所有拥有虚拟服务的服务器资源容量应该相近。值得注意的是,在流量率低的配置环境中,各服务器的流量并不是相同的,会优先考虑第一台服务器。这是因为,如果所有的服务器是相同的,那么 第一个服务器优先,直到第一台服务器有连续的活跃流量,否则总是会优先选择第一台服务器。
4.源 IP 哈希
这种方式通过生成请求源 IP 的哈希值,并通过这个哈希值来找到正确的真实服务器。这意味着对于同一主机来说他对应的服务器总是相同。使用这种方式,你不需要保存任何源 IP。但是需要注意,这种方式可能导致服务器负载不平衡。
5.最少连接数慢启动时间
对最少连接数和带权重的最小连接数调度方法来说,当一个服务器刚加入线上环境时,可以为其配置一个时间段,在这段时间内连接数是有限制的而且是缓慢增加的。这为服务器提供了一个‘过渡时间’以保证这个服务器不会因为刚启动后因为分配的连接数过多而超载。这个值在 L7 配置界面设置。
6.加权最少连接
如果服务器的资源容量各不相同,那么 “加权最少连接” 方法更合适:由管理员根据服务器情况定制的权重所决定的活跃连接数一般提供了一种对服务器非常平衡的利用,因为他它借鉴了最少连接和权重两者的优势。通常,这是一个非常公平的分配方式,因为它使用了连接数和服务器权重比例;集群中比例最低的服务器自动接收下一个请求。但是请注意,在低流量情况中使用这种方法时,请参考 “最小连接数” 方法中的注意事项。
7.基于代理的自适应负载均衡
负载主机包含一个自适用逻辑用来定时监测服务器状态和该服务器的权重。对于非常强大的 “基于代理的自适应负载均衡” 方法来说,负载主机以这种方式来定时检测所有服务器负载情况:每台服务器都必须提供一个包含文件,这个文件包含一个 0~99 的数字用来标明改服务器的实际负载情况 (0 = 空前,99 = 超载,101 = 失败,102 = 管理员禁用),而服务器同构 http get 方法来获取这个文件;同时对集群中服务器来说,以二进制文件形式提供自身负载情况也是该服务器工作之一,然而,并没有限制服务器如何计算自身的负载情况。根据服务器整体负载情况,有两种策略可以选择:在常规的操作中,调度算法通过收集的服务器负载值和分配给该服务器的连接数的比例计算出一个权重比例。因此,如果一个服务器负载过大,权重会通过系统透明地做调整。和加权轮循调度方法一样,不正确的分配可以被记录下来使得可以有效地为不同服务器分配不同的权重。然而,在流量非常低的环境下,服务器报上来的负载值将不能建立一个有代表性的样本;那么基于这些值来分配负载的话将导致失控以及指令震荡。 因此,在这种情况下更合理的做法是基于静态的权重比来计算负载分配。当所有服务器的负载低于管理员定义的下限时,负载主机就会自动切换为加权轮循方式来分配请求;如果负载大于管理员定义的下限,那么负载主机又会切换回自适应方式。
8.固定权重
最高权重只有在其他服务器的权重值都很低时才使用。然而,如果最高权重的服务器下降,则下一个最高优先级的服务器将为客户端服务。这种方式中每个真实服务器的权重需要基于服务器优先级来配置。
9.加权响应
流量的调度是通过加权轮循方式。加权轮循中 所使用的权重 是根据服务器有效性检测的响应时间来计算。每个有效性检测都会被计时,用来标记它响应成功花了多长时间。但是需要注意的是,这种方式假定服务器心跳检测是基于机器的快慢,但是这种假设也许不是总能够成立。所有服务器在虚拟服务上的响应时间的总和加在一起,通过这个值来计算单个服务物理服务器的权重;这个权重值大约每 15 秒计算一次。

Dubbo 中使用的5种负载均衡:
RandomLoadBalance 是一种比较容易实现的负载均衡策略,也是Dubbo 默认使用的负载均衡策略。就是通过加权的随机,负载均衡分发请求。
LeastActiveLoadBalance 最小活跃度轮询,也就是优先选择活跃度最小的服务进行调用,活跃度简单来说就是服务调用的次数,通过一个 ConcurrentHashMap存储调用服务的次数,获取最小的调用,如果存在多个最小的则通过上面随机的方式调用。
ConsistentHashLoadBalance 一致性Hash 就是通过请求参数来具体定位服务的方式,Dubbo 通过一致性Hash 算法得到具体的服务地址,为了防止资源倾斜,又加入了虚拟节点。
RoundRobinLoadBalance 加权重的轮询算法,通过权重来模拟实现轮询。每个服务会维护一个静态的权重,以及不断变化的动态权重。每次服务会选择动态权重最大的服务,然后将该服务的动态权重剪去总权重,再下次计算动态权重就是通过【原权重】+ 【动态权重】得到,也就是权重高的经过选择之后,权重会变低,而没有被选择的服务权重会慢慢变高,起到加权以及轮询的作用。
ShortestResponseLoadBalance 最短响应负载均衡,也就是调用负载均衡响应时间最多的服务,如果有多个就通过加权的随机来选择,和 LeastActiveLoadBalance 类似,都是去一个 ConcurrentHashMap 中取值,取得历次响应时间的平均,然后比较。


http://www.ppmy.cn/news/1978.html

相关文章

Java项目:SSM企业OA管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目包含管理员与普通员工两种角色&#xff0c; 管理员角色包含以下功能&#xff1a; 岗位管理,部门管理,工龄奖金管理,员工管理,考勤管理,…

电池供电遥测终端RTU 遥测终端机 低功耗遥测采集终端 智能远传 防水IP68

平升电子电池供电遥测终端RTU/遥测终端机/低功耗遥测采集终端是基于4G、5G、NB-IoT网络实现数据采集、远程传输、分析计算、越限报警的智能设备&#xff0c;具有功耗低、IP68防水等特点。特别适合用在无供电条件、防水防尘要求高的监测现场。 随着通信网络更迭、产品持续改进&…

Flink系列之Flink中RestartStrategy重启策略和FailoverStrategy故障转移策略

title: Flink系列 八、Flink RestartStrategy 重启策略 和 FailoverStrategy 故障转移策略 官网链接&#xff1a; 重启策略链接&#xff1a; https://nightlies.apache.org/flink/flink-docs-release-1.14/docs/ops/state/task_failure_recovery/#restart-strategies 故障转…

Cisco ASA应用——NAT的类型

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.NAT的类型 1.动态NAT 2.静态NAT 3.静态PAT 4.动态PAT 前言…

【JavaScript】用echarts绘制饼图

&#x1f64b;‍ 哈喽大家好&#xff0c;本次是JavaScript专栏echarts板块第一期 ⭐本期内容&#xff1a;用echarts绘制饼图 &#x1f3c6;系列专栏&#xff1a;JavaScript &#x1f44d;一起学习&#xff0c;一起加油&#xff01; 文章目录前言效果图思路准备一个dom基于准备好…

confluence的几个高危漏洞复现

序言 本次复现涉及了好几个confluence的相关漏洞&#xff0c;从复现利用到提权&#xff0c;有兴趣的可以自行搭建环境测试。 1.CVE-2021-26084 Confluence OGNL 注入漏洞 1.1 漏洞描述 在某些情况下&#xff0c;远程攻击者在经过身份验证或在特定环境下未经身份验证的情况下…

qt人员管理模块(模块化程序)功能块复制直接使用不冲突

一、前言 qt对人员管理部分个人总结的模块化程序&#xff0c;直接按照步骤复制粘贴程序&#xff0c;直接实现人员管理功能&#xff0c;无需花费脑筋在理清各个思路&#xff0c;适合快速编写组装程序 二、环境 windows qt5.7 sqlite3 三、正文 思来想去大半天&#xff0c;…

Linux上docker部署Mysql备份与恢复

Linux上Mysql备份与恢复 1.完全备份 完整备份是将所选的全部数据都备份起来&#xff0c;将备份文件生成一个镜像&#xff0c;再保存到其他的硬盘分区中。 1.1 完全备份一个或多个完整的库 ps: 博主mysql是用docker部署的&#xff0c;这时候需要进入docker容器进行操作。 d…