Java 常见面试题
1|0一、搜索
1|11、什么是Solr
Solr是一个Java开发的基于Lucene的 企业级 开源 全文搜索 平台。 它采用的是反向索引,即从关键字到文档的映射过程。 Solr的资源以Document为对象进行存储,每个文档由一系列的 Field 构成,每个Field 表示资源的一个属性。 文档的Field可以被索引, 以提工高性能的搜索效率。 一般情况下文档都包含一个能唯一表示该文档的id字段。
1|22、什么是Lucene
Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索
1|33、Solr的倒排索引
倒排索引就是从文档内容到文档序号的过程,将文档内容用solr自带分词器进行分词,然后作为索引,用二分法将关键字与排序号的索引进行匹配,进而查找到对应文档。倒排索引相对于正排而言,正排是从key查询value的一个过程,而倒排索引则是根据value查询key的一个过程,solr首先将数据进行分析,然后创建索引,将创建好的索引存储起来,查询时利用二分法去查询value,这个value对应一个Key,然后将这个Key返回。
1|44、 Solr和elasticsearch的区别?
https://www.cnblogs.com/jajian/p/9801154.html
共同点:solr和elasticsearch都是基于Lucene实现的!
不同点:
A. solr利用zookeeper进行分布式管理,而elasticsearch自身带有分布式协调管理功能;
B. solr比elasticsearch实现更加全面,solr官方提供的功能更多,而elasticsearch本身更注 重于核心功能,高级功能多由第三方插件提供;
C. solr在传统的搜索应用中表现好于elasticsearch,而elasticsearch在实时搜索应用方面比solr表现好!
2|0二、Java基础知识
2|11、native关键字:
https://www.cnblogs.com/qian123/p/5702574.html
2|22、Java异常:
https://www.cnblogs.com/Qian123/p/5715402.html
2|33、static,final,this,super关键字总结:
https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/basic/final,static,this,super.md
2|44、集合总结
https://www.cnblogs.com/skywang12345/p/3323085.html
1、fail-fast机制
ArrayList在用Iterator遍历数据时会产生fail-fast,导致异常,这是因为ArrayList遍历时会检查当前List的预期值和实际值是否相同,如果相同,则遍历,如果不同则产生异常
解决方案:
使用CopyOnWriteArrayList,他没有继承AbstractList,而是重写了iterator方法,遍历时新建一个数组,然后保存当前数据,由于是新数组,所以不会产生不一样的情况,自然不会有异常
2、HashMap详解:
https://zhuanlan.zhihu.com/p/21673805
3、我对于集合的理解
(1)、集合工具类Arrays
https://blog.csdn.net/samjustin1/article/details/52661862
(2)、集合工具类Collections
https://www.cnblogs.com/nayitian/p/3269585.html
(3)、ArrayList
继承关系:
特点:底层是数组实现,查找快,增删慢,它是线程不安全的,如果需要线程安全,则可以使用Vector
定义:它继承于AbstractList,实现了List, RandomAccess, Cloneable
ArrayList包含了两个重要的对象:elementData 和 size。
(01) elementData 是"Object[]类型的数组",它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长,具体的增长方式,请参考源码分析中的ensureCapacity()函数。
(02) size 则是动态数组的实际大小。
遍历:
遍历ArrayList时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!
(4)、LinkedList
继承关系:
特点:
底层是链表实现的,增删快,查找慢
简介:
LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。
定义:
LinkedList的本质是双向链表。
(01) LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。
(02) LinkedList包含两个重要的成员:header 和 size。
header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。
size是双向链表中节点的个数。
遍历:
遍历LinkedList时,使用removeFist()或removeLast()效率最高。但用它们遍历时,会删除原始数据;若单纯只读取,而不删除,应该使用第3种遍历方式。
无论如何,千万不要通过随机访问去遍历LinkedList!
(5)、vector
Vector简介
Vector 是矢量队列,它是JDK1.0版本添加的类。继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。
Vector 继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能。
Vector 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在Vector中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。
Vector 实现了Cloneable接口,即实现clone()函数。它能被克隆。
和ArrayList不同,Vector中的操作是线程安全的。
特点:底层是数组实现,是线程安全的,Vector里面的方法加上了synchronized关键字
继承关系:
Vector的数据结构和ArrayList差不多,它包含了3个成员变量:elementData , elementCount, capacityIncrement。
(01) elementData 是"Object[]类型的数组",它保存了添加到Vector中的元素。elementData是个动态数组,如果初始化Vector时,没指定动态数组的>大小,则使用默认大小10。随着Vector中元素的增加,Vector的容量也会动态增长,capacityIncrement是与容量增长相关的增长系数,具体的增长方式,请参考源码分析中的ensureCapacity()函数。
(02) elementCount 是动态数组的实际大小。
(03) capacityIncrement 是动态数组的增长系数。如果在创建Vector时,指定了capacityIncrement的大小;则,每次当Vector中动态数组容量增加时>,增加的大小都是capacityIncrement。
遍历:
遍历Vector使用索引的方式随机访问最快,使用迭代器最慢
(6)HashMap
HashMap简介
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。
HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
继承关系:
特点:
HashMap是数组加链表的方式实现的,首先根据hash值计算出元素存储的位置,如果该位置上已经有元素,则判断key是否相同,如果相同则覆盖,如果不同则在该节点创建链表,当链表长度超过8时,将链表改为红黑树
(7)、HashTable
特点:线程安全
(8)、TreeMap
特点:有序的key-value集合,它是通过红黑树实现的
(9)、set
set和list集合相同,但是set集合中不允许有重复的元素
HashSet:无序集合
TreeSet:有序集合
2|55、多线程
(1)、创建多线程
(2)、Join方法
join()方法可以让一个线程强制运行
(3)、线程的状态
1、创建状态
Thread thread=new Thread();
当程序new Thread(),说明该线程处于创建状态
2、就绪状态
t.start当线程调用start方法时,该线程则处于就绪状态,等待着CPU的调度
3、运行状态
线程获得了CPU和相应资源,开始运行run方法
4、阻塞状态
线程由于某种原因暂时停止运行,sleep(),suspend(),wait()等方法都可以让线程处于阻塞状态
5、死亡状态
线程运行完毕,或者线程调用stop方法,则该线程处于死亡状态
(4)、几个常用方法
1、join方法 强制线程运行
在线程操作中,可以使用 join() 方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才可以继续执行。
2、sleep方法 休眠线程
在程序中允许一个线程进行暂时的休眠,直接使用 Thread.sleep() 即可实现休眠。
3、interrupt方法 中断线程
当一个线程运行时,另外一个线程可以直接通过interrupt()方法中断其运行状态。
4、setDaemon方法 后台线程
在 Java 程序中,只要前台有一个线程在运行,则整个 Java 进程都不会消失,所以此时可以设置一个后台线程,这样即使 Java 线程结束了,此后台线程依然会继续执行,要想实现这样的操作,直接使用 setDaemon() 方法即可。
5、setPriority方法
设置线程优先级 值分别为Thread.MIN_PRIORITY Thread.MAX_PRIORITY Thread.NORM_PRIORITY 范围1-10
6、yield方法 线程礼让
在线程操作中,也可以使用 yield() 方法将一个线程的操作暂时让给其他线程执行
(5)、start()和run()区别
(6)、synchronized
一、原理:
在java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。 当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。 不同线程对同步锁的访问是互斥的。也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。 例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。
二、sychronized使用规则
我们将synchronized的基本规则总结为下面3条,并通过实例对它们进行说明。
第一条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
第二条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。
第三条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
三、实例锁和全局锁(对象锁和类锁)
实例锁:当时使用synchronized方法或者sychronized代码块时,如果不加上static的话,那么这个锁就是实例锁(对象锁),也就是说同一个对象共享同一个实例锁,不同的对象享受不同的实例锁,互不干涉。
全局锁:当使用static synchronized实现同步时,那么就是全局锁,即同一个类共享一个锁,不管有多少对象,只要他们属于同一个类,那么这些对象都共享一个锁
(7)、wait和notify
一、介绍
在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
Object类中关于等待/唤醒的API详细信息如下:
notify() -- 唤醒在此对象监视器上等待的单个线程。
notifyAll() -- 唤醒在此对象监视器上等待的所有线程。
wait() -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout, int nanos) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
二、注意点:
- wait()方法的作用是让当前线程等待,当调用wait方法后,当前线程释放同步锁,其他线程可以获取该同步锁执行
- 只有和持有该对象同步锁的线程执行了notify()方法并且释放了同步锁以后,wait线程才可以获取锁继续执行
三、示例:
(8)、线程优先级
一、定义
用户线程:用户线程一般用于执行用户任务
守护线程:守护线程一般用于执行后台任务
当用户线程全部执行完毕后,守护线程也会自动结束。
我们可以用isDaemon()方法判断线程是否为守护线程,当isDaemon()返回false时,表明该线程为用户线程,可以用setDaemon()方法将一个线程设为守护线程
二、线程优先级
线程优先级范围1-10,数字越大,说明线程优先级越高,默认这个数字为5。优先级高的优先于优先级低执行
3|0三、算法
3|11、链表:
Java链表的实现:https://blog.csdn.net/jianyuerensheng/article/details/51200274
tips:双指针法,快慢指针(一个指针速度慢,一个指针速度快)
eg1:查找链表中间元素
fast指针每次往后走两步,slow每次向后走一步,这样当fast走到链表结尾时,slow刚好走到链表的中间位置
eg2:倒数第k个元素问题
先来看"倒数第k个元素的问题"。设有两个指针 p 和 q,初始时均指向头结点。首先,先让 p 沿着 next 移动 k 次。此时,p 指向第 k+1个结点,q 指向头节点,两个指针的距离为 k 。然后,同时移动 p 和 q,直到 p 指向空,此时 p 即指向倒数第 k 个结点
eg3:链表是否存在环
类似于两个人在操场上跑步,其中一个快,一个慢,那么最终快和慢的一定会相遇
4|0四:Redis
1、Redis持久化:
RDB和AOF
2、Redis事务
MULTI:开启事务 EXEC:提交事务 DISCARD:放弃事务
开启事务后,所有操作命令都会加入到队列中,并不会立即执行,等到执行EXEC时再统一执行命令
1、正常执行:当所有命令正常执行时,提交事务时会将所有在队列中的命令正常提交,然后执行
2、放弃事务:执行DISCARD命令则放弃本次事务
3、全体连坐:有一个出错,全部都不提交
4、Watch监控:Watch监控时如果有其他人修改了数据,那么此次事务提交失败,需要获取到最新的数据才能继续
5|0五、网络
TCP三次握手
1、首先客户端发送一个SYN=1和seq=x包给服务器
2、服务器确认收到后,发送给客户端SYN=1,ack=x+1,seq=y(这个是服务器端的序列号)
3、客户端收到服务器端的通知后发送ACK=1,seq=x+1,ack=y+1
TCP四次挥手
__EOF__

本文链接:https://www.cnblogs.com/wugongzi/p/16030043.html
关于博主:我是说故事的五公子,欢迎扫描左边二维码关注
版权声明:沪漂一员,互联网架构方向,如有问题探讨可以直接私信我,亦可下方留言。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!