【科大讯飞】Java实习一面面经|讲解|0514
今天挑选一篇【科大讯飞Java实习一面面经】,给大家做讲解分析~
感谢这位同学的分享,预祝Offer多多~~~ 原贴链接
本文也是 《热门面经讲解》 专栏系列文章之一,大家可以点跳转链接,加个关注和订阅,我会持续更新~
自产《大厂后端Top100面试题讲解》对本篇面经题目覆盖率:
5/5 = 100%
自产《大厂后端Top200面试题讲解》对本篇面经题目覆盖率:
5/5 = 100%
八股问题
1. ThreadLocal类怎么避免内存溢出(泄漏)?
解析
属于高频考题:
自产《大厂后端Top100面试题讲解|第35题》
所属专项:Java|Java并发
专项考察占比:
【Java】面试中考察Java的比率:大厂:17%| 腾讯:6%| 阿里:32%
【Java-并发】面试考察Java时,问Java并发问题的比率:37%
参考回答
ThreadLocal内存泄漏问题
ThreadLocal如果使用不当,可能会导致内存泄漏。这主要是因为ThreadLocalMap中的Entry对ThreadLocal实例是弱引用(WeakReference),而对应的值value则是强引用。如果ThreadLocal实例被回收了,但是对应的value还没有被回收,那么这部分数据就可能成为内存泄漏的源头。
为了避免这种情况,有几种方法:
- 使用完ThreadLocal后,及时调用其remove()方法清除对应的Entry,避免因为线程长时间存活而导致的内存泄漏。
- 将ThreadLocal变量设置为static和final,以延长其生命周期,减少被垃圾回收的可能性。但这并不是根本的解决办法,因为即使ThreadLocal实例不被回收,其对应的value还是可能被长时间持有而无法释放。
因此,最佳实践是在使用完ThreadLocal后,及时通过remove()方法清除数据,以避免潜在的内存泄漏问题。
推荐学习资料
《JavaGuide》| 并发面试题:# ThreadLocal 面试题
《JavaGuide》| 详解:# ThreadLocal 详解
2. List集合有哪些?ArrayList动态数组怎么实现的?ArrayList扩容是深拷贝还是浅拷贝?双向链表和单向链表的区别?
解析
属于高频考题:
自产《大厂后端Top100面试题讲解|第21题》
所属专项:Java|Java集合框架
专项考察占比:
【Java】面试中考察Java的比率:大厂:17%| 腾讯:6%| 阿里:32%
【Java-集合框架】面试考察Java时,问Java集合框架问题的比率:9%
参考回答
List集合有哪些? 在Java中,List接口的实现类主要有ArrayList、LinkedList、Vector等。它们分别具有不同的特性和使用场景。
ArrayList动态数组是怎么实现的?
ArrayList是基于动态数组实现的。它内部维护了一个Object类型的数组elementData来存储元素。当我们向ArrayList中添加元素时,如果数组已满,ArrayList会自动扩容。初始时,ArrayList的容量通常会有一个默认值,比如10。当我们添加的元素数量超过这个容量时,ArrayList就会进行扩容操作,通常是扩大到当前容量的1.5倍或者2倍,这个扩容因子可以根据具体的Java版本和虚拟机实现有所不同。
ArrayList扩容是深拷贝还是浅拷贝?
ArrayList的扩容操作是浅拷贝。当ArrayList进行扩容时,它会创建一个新的更大的数组,并把旧数组中的元素复制到新数组中。这个过程是浅拷贝,因为它只复制了对象的引用,而没有复制对象本身。如果数组中的元素是可变对象,并且被其他引用所共享,那么修改这个对象将会影响到所有持有这个对象引用的地方。
双向链表和单向链表的区别?
单向链表和双向链表是线性表链式存储结构的两种不同形式。单向链表只有一个指针,指向下一个节点,因此它只能从头到尾顺序访问。而双向链表则有两个指针,一个指向前一个节点,另一个指向后一个节点,这使得双向链表可以双向遍历。
具体来说,双向链表在存储结构上比单向链表更复杂,因为它需要存储前驱节点和后继节点的指针。但是,双向链表提供了更好的功能性和灵活性,比如可以双向遍历,以及在某个节点处插入和删除元素时更加方便。
此外,从内存占用的角度来看,双向链表因为存储了额外的指针,所以占用的内存会比单向链表多一些。但从操作效率上讲,双向链表在某些情况下(如双向遍历、插入和删除操作)会比单向链表更高效。
推荐学习
《JavaGuide》| 集合面试题:# List 面试题
3. Redis数据结构有哪些?Redis string最大长度?
解析
属于高频考题:
自产《大厂后端Top100面试题讲解|第65题》
所属专项:Redis|数据类型
专项考察占比:
【Redis】面试中考察操作系统的比率:大厂:12%| 腾讯:7%| 阿里:13%
【Redis-数据类型】面试考察Redis时,问“数据类型”相关问题的比率:20%
参考口述回答
- 5种常用数据类型:
首先,字符串 String是Redis最基本的数据类型,它可以存储任意类型的数据,包括文本、数字和二进制数据,且其值最大可以达到512MB。字符串在缓存、计数器、分布式锁等场景下有着广泛的应用。例如,在缓存场景中,我们可以将热点数据存储在Redis的字符串类型中,以提高数据的访问速度;在计数器场景中,我们可以利用Redis的原子性操作来实现高效、准确的计数功能。
其次,哈希类型 Hash是一种键值对的集合,它适合存储对象的多个属性。在哈希类型中,每个键都与一个值相关联,这使得我们可以方便地获取或修改对象的某个属性。哈希类型的值最多可以包含2^32-1个键值对,这使得它能够存储大量的数据。哈希类型在存储用户信息、配置信息等场景下非常有用。例如,我们可以将用户的个人信息存储在一个哈希值中,通过键值对的方式来访问和更新这些信息。
第三,列表类型 List是一种有序的字符串集合,它可以存储多个字符串值。列表类型支持在头部或尾部插入元素,以及获取指定范围内的元素等操作。这使得列表类型非常适合用于实现队列、栈等数据结构。例如,在消息队列场景中,我们可以利用列表类型来存储待处理的消息,并通过LPUSH和RPOP等命令来实现消息的入队和出队操作。
第四,集合类型 Set是一种无序、唯一的字符串集合。它支持添加元素、删除元素以及判断元素是否存在等操作。此外,集合类型还支持求交集、并集和差集等操作。这使得集合类型非常适合用于存储不重复的元素,并进行快速的集合运算。例如,在标签系统中,我们可以利用集合类型来存储用户的标签信息,并通过集合运算来查找具有相同标签的用户或者计算用户之间的相似度等。
最后,有序集合类型 ZSet是一种有序的字符串集合,每个元素都关联着一个分数用于排序。有序集合支持添加元素、删除元素以及获取指定范围内的元素等操作,并且还支持根据分数进行范围查找和计算元素的排名等操作。这使得有序集合非常适合用于排行榜、优先级队列等场景。例如,在排行榜场景中,我们可以利用有序集合来存储用户的得分信息,并通过ZRANK等命令来获取用户的排名情况。
- 后面新增4种
首先是Bitmap数据类型,它是一种基于String类型实现的特殊数据结构,用于存储大量二进制位(0或1)的数据。这些位可以代表不同的状态或标志。Bitmap非常适合用于签到打卡等场景,因为这类场景通常只需要记录用户是否进行了某个操作,例如签到(1)或未签到(0)。使用Bitmap可以极大地节省存储空间,并提高处理速度。
接下来是HyperLogLog数据类型,它是Redis 2.8.9版本引入的,用于做数据基数计算。HyperLogLog的优势在于它占用的内存非常少,并且不保存原始数据,而是通过一定的算法估计数据的基数。尽管它有一定的误差(标准误差为0.81%),但在对数据准确度要求不是特别高的场景下,如统计网站注册IP数、每日访问IP数或页面实时UV/PV数等,HyperLogLog是一个非常好的选择。
再来说说GEO数据类型,这是Redis 3.2版本新增的特性,用于存储经纬度格式的地理坐标,并对这些坐标执行距离计算、范围查找等操作。GEO数据类型非常适合用于地理位置相关的业务场景,如各类社交软件中的“附近的人”功能、外卖配送服务中的距离计算和最优配送员分配等。
最后是Stream数据类型,它类似于消息队列或日志系统,可以记录一系列的事件或消息,并按照时间顺序进行存储。Stream数据类型非常适合用于实时监控、大数据处理、数据流转、实时数据分析和视频流处理等场景。例如,在实时监控中,可以使用Stream来记录服务器的日志或网络流量数据;在大数据处理中,可以使用Stream来对一批数据进行筛选、排序和统计等操作;在实时数据分析中,可以使用Stream来处理网站访问记录并了解用户行为。
3.Redis string最大长度?
Redis中String类型的最大长度是512MB。
推荐学习资料
《小林Coding》|图解Redis:Redis 常见数据类型和应用场景
《小林Coding》|图解Redis:Redis 常见数据类型底层实现
4. Linux用什么命令查看Java进程?Linux用什么命令查看进程?
解析
属于高频考题:
自产《大厂后端Top100面试题讲解|第61题》
所属专项:操作系统|Linux命令
专项考察占比:
【操作系统】面试中考察操作系统的比率:大厂:12%| 腾讯:18%| 阿里:8%
【操作系统-Linux命令】面试考察操作系统时,问“网络系统”相关问题的比率:7%
参考回答
查看Java进程:
- ps命令结合grep:可以使用
ps -ef | grep java
来查看所有包含"java"关键字的进程。这个命令会列出所有正在运行的进程,并通过grep过滤出包含"java"关键字的进程。- jps命令:jps是Java Virtual Machine Process Status Tool的缩写,可以列出所有正在运行的Java进程的进程ID和主类名。使用
jps -l
可以显示完整的主类名。查看一般进程:
- ps命令:
ps aux
可以显示所有用户的所有进程,包括进程ID、用户、CPU和内存使用率等信息。ps -ef
则可以显示所有进程的完整信息,包括父进程ID、进程ID、用户、CPU和内存使用率、开始时间、所用控制终端和CPU使用时间等。- top命令:此命令可以实时显示系统中运行的进程和系统资源使用情况,包括CPU使用率、内存使用率、正在运行的进程等信息。在top命令的输出中,可以通过按下"Shift + H"来按CPU占用率的高低排序进程列表,从而方便地找到CPU占用率较高的进程。
- pgrep命令:这个命令可以根据进程名或其他属性来查找并打印匹配的进程ID。例如,
pgrep ssh
将列出所有名为ssh的进程ID。- pidof命令:此命令可以根据进程名查找并打印匹配的第一个进程ID。例如,
pidof sshd
将返回sshd进程的ID。此外,还有一些其他的命令和工具也可以用来查看进程,如htop、pstree和lsof等。这些命令提供了不同的视图和功能,可以根据需要选择使用。
5. 强引用和弱引用的区别?(这里补充软引用和虚引用一起介绍)
解析
属于高频考题:
自产《大厂后端Top100面试题讲解|第38题》
所属专项:Java| JVM
专项考察占比:
【Java】面试中考察Java的比率:大厂:17%| 腾讯:6%| 阿里:32%
【Java-JVM】面试考察Java时,问JVM问题的比率:24%
参考回答
首先,我们来谈谈强引用。强引用是Java中最常见的引用类型,它是默认的引用方式。当一个对象被强引用所指向时,垃圾回收器是不会回收这个对象的,即使系统内存不足。只要强引用存在,对象就不会被判定为可回收。例如,当我们通过
new
关键字创建一个对象并将其赋值给一个变量时,这个变量就是对该对象的一个强引用。接下来是软引用。软引用是通过
SoftReference
类来实现的。它用于描述那些还有用但并非必需的对象。当系统内存足够时,软引用指向的对象不会被回收;但当系统内存不足时,垃圾回收器会开始考虑回收这些对象。这种特性使得软引用非常适合用于实现内存敏感的缓存,比如图片缓存等。当内存紧张时,可以自动释放这些缓存,从而避免内存溢出。再来说说弱引用。弱引用通过
WeakReference
类来实现,它比软引用更加“脆弱”。只要垃圾回收器开始运行,无论当前内存是否充足,弱引用指向的对象都会被回收。弱引用的生命周期相对较短,主要用于解决内存泄漏问题,如缓存、监听器等情况。当对象只被弱引用所指向时,垃圾回收器会毫不犹豫地将其回收。最后是虚引用。虚引用是最弱的一种引用类型,它不会对对象的生存时间构成影响,也无法通过虚引用来获取一个对象实例。虚引用的主要作用是跟踪对象被垃圾回收的状态。当垃圾回收器准备回收一个被虚引用指向的对象时,会将该虚引用加入到与之关联的引用队列中。这样,我们可以通过检查引用队列来了解对象何时被回收。虚引用通常用于实现一些特殊的内存管理需求。
推荐学习资料
《JavaGuide》| 并发面试题: #死亡对象的判断方法?
其他问题
1. 项目问题:Jwt令牌的结构?Jwt令牌能不能多服务器共享?
解析
Jwt虽然后端用得挺多,但是一般项目中用到了才会问到。
参考回答
JWT令牌的结构
JWT令牌主要由三部分组成,它们分别是:
- 头部(Header) :这部分包含了令牌的类型和所使用的加密算法等信息。例如,它可能包含一个声明,指出这是一个JWT令牌,以及使用的是哪种签名算法,如HMAC、SHA256或RSA。这些信息会被Base64Url编码,成为JWT令牌的第一部分。
- 载荷(Payload) :这是JWT令牌的第二部分,包含了一些声明,如用户身份信息、权限等。这些声明是以JSON对象的形式存在的,并被Base64Url编码。需要注意的是,虽然载荷中的信息可以被解码还原,但不应在此部分存放敏感信息。
- 签名(Signature) :这是JWT令牌的第三部分,用于防止令牌内容被篡改。签名的生成方式是,先将头部和载荷部分进行Base64Url编码,并使用点(.)连接组成字符串,然后使用头部中声明的签名算法和密钥对这个字符串进行签名。
JWT令牌能不能多服务器共享?
JWT令牌的一个重要特性就是可以在多个服务之间共享和验证。在分布式系统中,不同的服务可能需要对用户进行身份验证和授权。通过共享JWT令牌,这些服务可以轻松地验证用户的身份和权限,而无需每次都进行身份验证。
要实现JWT令牌的共享,通常的做法是:
- 当用户在某个服务上成功登录后,该服务会生成一个JWT令牌并返回给用户。
- 用户可以将这个JWT令牌保存在本地,例如浏览器的localStorage中。
- 当用户需要访问其他服务时,他们可以将JWT令牌作为请求头部或参数发送给该服务。
- 接收到请求的服务可以使用公钥验证JWT令牌的签名和完整性,从而确认用户的身份和权限。
推荐学习资料 《博客》|JWT 令牌
2. 项目问题:项目有没有上线,有没有压测?
推荐学习资料
3. 算法问题:排序算法属于算法,重点掌握。
推荐学习资料
最后
本文也是 《热门面经讲解》 专栏系列文章之一,大家可以点跳转链接,加个关注和订阅,我会持续更新~
#面经##科大讯飞##实习##秋招##24届软开秋招面试经验大赏#挑选近期热门真实后端面经进行讲解分析,给出:个人分析+参考回答+学习资料指引。