Java面试题

131 阅读14分钟

Java基础

equal 和 ==

==判断地址相同

equal判断对象内容相同

重写equal需要重写hashcode

值相同的对象必须有相同的hashCode,当我们向一个Hash结构的集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则链到后面(如果是链地址法)。 如果重写equals不重写hashCode它与散列集合无法正常工作。

重载和重写

重载 方法名一致,参数列表中参数的顺序,类型,个数不同。

重写 构造方法不能被重写(名称都不一样)

Object 方法

clone()、 equals()、 finalize()、 getClass()、 hashCode()、 notify()、 notifyAll()、 toString()、 wait()

String、String StringBuffer和StringBuilder的区别是什么

String 不可变

StringBuffer  StringBuffer对象则代表一个字符序列可变的字符串,

StringBuilder类也代表可变字符串对象。实际上,StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同。不同的是:StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高

HashMap

Java值传递

       值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

Java值传递是把实参对象的引用地址****当作值 来传递进去。

总结:
如果参数是基本类型,传递的是基本类型的字面量值的拷贝
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝

深拷贝和浅拷贝的区别是什么

final有哪些用法

static都有哪些用法

Java 高级

异常

泛型

反射

JAVA机制反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射就是把Java的各种成分映射成相应的Java类。

注解

多线程

线程池的作用和参数配置

Spring

Spirng循环依赖

事务的传播机制

PROPAGATION_REQUIRED:(默认传播行为)如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。

PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务进行执行。 PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务执行。

PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。

PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。

PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

事务隔离级别

ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

ISOLATION_READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据。

ISOLATION_READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已经提交的数据。

ISOLATION_REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果都是一致的。

ISOLATION_SERIALIZABLE:所有事务逐个依次执行。

SpringBoot

SpringBoot Start

SpringBoot自动装配原理

Spring Boot配置加载顺序

SpringCloud

注册中心

配置中心

服务网关

断路器

Hystrix是一种断路器,主要的作用是在微服务治理中保护服务。

服务降级(当接口调用失败,自动执行一个空的方法。避免线程阻塞)

服务熔断 当接口调用失败,自动执行提前定义好的熔断方法 统一返回错误信息)

服务隔离:隔离服务间的相互影响 

Ribbon

Feign

认证与授权

分布式事务

Mysql

查询语句执行顺序

(7)     SELECT 
(8)     DISTINCT <select_list>
(1)     FROM <left_table>
(3)     <join_type> JOIN <right_table>
(2)     ON <join_condition>
(4)     WHERE <where_condition>
(5)     GROUP BY <group_by_list>
(6)     HAVING <having_condition>
(9)     ORDER BY <order_by_condition>
(10)    LIMIT <limit_number>

事务ACID

       原子性(Atomicity):一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败,对于一个事务来说,不能只执行其中的一部分操作。

       一致性(Consistency):一致性是指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏。

       隔离性(Isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

       持久性(Durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的修改数据也不会丢失。 

事务并发引起的问题

       脏读:当一个事务读取到了另外一个事务修改但未提交的数据,被称为脏读。

       不可重复读:当事务内相同的记录被检索两次,且两次得到的结果不同时,此现象称为不

可重复读。

       幻读:在事务执行过程中,另一个事务将新记录添加到正在读取的事务中时,会发

生幻读。

       如果事务 2 中是删除了符合的记录而不是插入新记录,那事务 1 中之后再根据条件读取的记录变少了,这种现象算不算幻读呢?明确说一下,在 MySQL 中这种现象不属于幻读,幻读强调的是一个事务按照某个相同条件多次读取记录时,后读取时读到了之前没有读到的记录。

那对于先前已经读到的记录,之后又读取不到这种情况,算啥呢?其实这相当于对每一条记录都发生了不可重复读的现象。幻读只是重点强调了读取到了之前读取没有获取到的记录。 

事务的隔离级别

       READ UNCOMMITTED:未提交读。

       READ COMMITTED:已提交读。

       REPEATABLE READ:可重复读。

       SERIALIZABLE:可串行化。

       MySQL 在 REPEATABLE READ 隔离级别下,是可以禁止幻读问题的发生的。MySQL 的默认隔离级别为 REPEATABLE READ,我们可以手动修改事务的隔离级别。

MVCC

索引

       一个 select 查询语句在执行过程中一般最多能使用一个二级索引,即 使在 where 条件中用了多个二级索引。

聚集索引/聚簇索引

       InnoDB 中使用了聚集索引,就是**将表的主键用来构造一棵 B+树,并且将整张表的行记录数据存放在该 B+树的叶子节点中。也就是所谓的索引即数据,数****据即索引。**由于聚集索引是利用表的主键构建的,所以每张表只能拥有一个聚集索引。

       聚集索引的叶子节点就是数据页。换句话说,**数据页上存放的是完整的每行记录。**因此聚集索引的一个优点就是:通过聚集索引能获取完整的整行数据。另一个优点是:对于主键的排序查找和范围查找速度非常快。

辅助索引/二级索引

       对于辅助索引(Secondary Index,也称二级索引、非聚集索引),叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签( bookmark)。该书签用来告诉 InnoDB 存储引擎哪里可以找到与索引相对应的行数据。因此 InnoDB 存储引擎的辅助索引的书签就是相应行数据的聚集索引键。

       回表:辅助索引的存在并不影响数据在聚集索引中的组织,因此每张表上可以有多个辅助索引。**当通过辅助索引来寻找数据时,InnoDB 存储引擎会遍历辅助索引并通过叶级别的指针获得指向主键索引的主键,然后再通过主键索引(聚集索引)来找到一个完整的行记录。**这个过程也被称为回表。也就是根据辅助索引的值查询一条完整的用户记录需要使用到 2 棵 B+树----一次辅助索引,一次聚集索引。

       回表的记录越少,性能提升就越高,需要回表的记录越多,使用二级索引的性能就越低,甚至让某些查询宁愿使用全表扫描也不使用二级索引。查询优化器会事先对表中的记录计算一些统计数据,然后再利用这些统计数据根据查询的条件来计算一下需要 回表的记录数,需要回表的记录数越多,就越倾向于使用全表扫描,反之倾向于 使用二级索引 + 回表的方式。

联合索引/复合索引

        将表上的多个列组合起来进行索引我们称之为联合索引或者复合索引,建立联合索引只会建立 1 棵 B+树,index(note,b)在索引构建上,包含了两个意思:

       1、先把各个记录按照 note 列进行排序。

       2、在记录的 note 列相同的情况下,采用 b 列进行排序。

覆盖索引/索引覆盖

       既然多个列可以组合起来构建为联合索引,那么辅助索引自然也可以由多个列组成。InnoDB 存储引擎支持覆盖索引(covering index,或称索引覆盖),即**从辅助索引中就可以得到查询的记录,而不需要查询聚集索引中的记录。使用覆盖索引的一个好处是辅助索引不包含整行记录的所有信息,故其大小要远小于聚集索引,因此可以减少大量的 IO 操作。**所以记住,覆盖索引并不是索引类型的一种。

自适应哈希索引

        InnoDB 存储引擎除了我们前面所说的各种索引,还有一种自适应哈希索引, 我们知道 B+树的查找次数,取决于 B+树的高度,在生产环境中,B+树的高度一般 为 34 层,故需要 34 次的 IO 查询。 所以在 InnoDB 存储引擎内部自己去监控索引表,如果监控到某个索引经常 用,那么就认为是热数据,然后内部自己创建一个 hash 索引,称之为自适应哈 希索引( Adaptive Hash Index,AHI),创建以后,如果下次又查询到这个索引, 那么直接通过 hash 算法推导出记录的地址,直接一次就能查到数据,比重复去 B+tree 索引中查询三四次节点的效率高了不少。 InnoDB 存储引擎使用的哈希函数采用除法散列方式,其冲突机制采用链表 方式。注意,对于自适应哈希索引仅是数据库自身创建并使用的,我们并不能对 其进行干预。

       哈希索引只能用来搜索等值的查询,如 SELECT* FROM table WHERE index co=xxx。而对于其他查找类型,如范围查找,是不能使用哈希索引的。

慢查询

       慢查询日志,顾名思义,就是查询花费大量时间的日志,是指 mysql 记录所有执行超过 long_query_time 参数设定的时间阈值的 SQL 语句的日志。该日志能为 SQL 语句的优化带来很好的帮助。

Redis

常见的5中数据结构

字符串(String)、哈希(Hash)、列表(list)、集合(set)、有序集合(ZSET)。

集合里的字符串不允许有重复

有序集合,不能有重复,但有序集合中的元素可以排序。

持久化

分布式锁

SETNX        EXPIRE      设置自己的key     redission

缓存一致性

pipeline

       Pipeline(流水线)机制能将一组 Redis 命令进行组装,通过一次 RTT 传输给 Redis,再将这组 Redis 命令的执行结果按顺序返回给客户端。 

缓存雪崩

       同一时间缓存数据大面积失效,于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会级联宕机的情况。解决:依赖隔离组件为后端限流并降级。将缓存失效时间分散开。

       缓存雪崩和缓存击穿的区别在于缓存击穿针对某一 key 缓存,缓存雪崩则是很多 key。 

缓存穿透

      缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,如果从存储 层查不到数据则不写入缓存层。 缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保 护后端存储的意义。解决:

       1.缓存空对象。当存储层不命中后,仍然将空对象保留到缓存层中,之后再访问这个数据将会从缓存中获取,这样就保护了后端数据源。

       2.布隆过滤器拦截。如果布隆过滤器认为不存在,那么就不会访问存储层,在一定程度保护了存储层。

缓存击穿

       缓存击穿是指一个热点 Key,大并发集中对这一个点进行访问,当这个 Key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库。 解决:设置热点数据永远不过期,或者加上互斥锁就能搞定了。

     1永不过期

      2 互斥锁(mutex key)。简单地来说,就是在缓存失效的时候(redis.get(key)为空),不是立即去 load db,而是先使用缓存工具的某些带成功操作返回值的操作(if (redis.setnx(key_mutex, 1, 3 * 60) == 1))去 set 一个 mutex key,当操作返回成功时,再进行 load db 的操作并回设缓存;否则(说明set成功的那个,去加载db了),就重试整个 get 缓存的方法。

热点 Key

在 Redis 中,访问频率高的 key 称为热点 key。

BigKey

       bigkey 是指 key 对应的 value 所占的内存空间比较大,例如一个字符串类型的 value 可以最大存到 512MB,一个列表类型的 value 最多可以存储 23-1 个元素。

红锁RedLock

       解决Redis挂了的时候加锁失败的场景。红锁采用主节点过半机制,即获取锁或者释放锁成功的标志为:在过半的节点上操作成功。

       Redlock 的方案基于 2 个前提: 不需要部署从库和哨兵实例,只部署主库;但主库要部署多个,官方推荐 至少 5 个实例。 也就是说,想用使用 Redlock,你至少要部署 5 个 Redis 实例,而且都是 主库,它们之间没有任何关系,都是一个个孤立的实例。 注意:不是部署 Redis Cluster,就是部署 5 个简单的 Redis 实例。

Redission

       Redisson 是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap,ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue,BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock,AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

缓存预热

       缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就 可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直 接查询事先被预热的缓存数据! 解决方案 :

       直接写个缓存刷新页面,上线时手工操作一下; 

       数据量不大,可以在项目启动的时候自动进行加载; 

       定时刷新缓存

kafka

消费者组

每个分区只能被一个消费者使用

重复消费问题

kafka顺序消费问题

单分区

MongoDB

联表查询

lookup

数组展开

unwind

网络

https

分布式

接口幂等性设计

跨域问题

单点登陆