4/24 哭了,没找到暑期实习,真的会耽误秋招上岸吗?
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 19 分钟
阅读:.. 评论:..
夏天到了,你大概能感受到的不仅仅是温度的上升,对很多大学生来说,暑期实习的话题也开始火热起来。
暑期实习,听着就像是一场夏日大作战,每个学生都希望能在这个季节为自己的简历添上亮眼的一笔。
但是,这到底是不是唯一的选择呢?暑期实习真的就比日常实习强?
一、丑话说在前面
首先,得承认,如果你实力足够,暑期实习当然是个不错的选择——毕竟它可能是一条直通秋招的快车道。 但话说回来,我们得实事求是,现实总是复杂的,暑期实习的HD是非常有限的。 因此,考虑到性价比,选择暑期实习不如选择日常实习,尤其是对于那些还没啥实习经验的小伙伴。
咱们来分几点聊聊:
- 门槛的事儿:现在的大环境,可以说是竞争激烈到一塌糊涂。暑期实习的要求已经和秋招差不多了,**想要入围,很可能你得有过实习经验或者有关的项目经验。**但日常实习的门槛就亲民多了,特别是那些不那么热门的岗位,对没有实习经验的同学还是很包容的。
- 秋招的影响:这可能是大家最关心的。暑期实习和日常实习的最大区别是不是能转正,对吧?但实际上,暑期实习转不转正,和日常实习在秋招时的差别并不大。没转正的暑期实习生和日常实习生一样,都是新的求职者。而且,说实话,很多时候大家还是喜欢‘野花’多于‘家花’,所以转正后的待遇可能还不如换个地方重新来。
- 实习的机会:别以为暑期实习就一定比日常实习培养得好,其实不然。机会是自己争取的,日常实习可能同样能接触到不错的项目和机会。而且,不少日常实习还能转成暑期实习,或者直接转正。
所以说,虽然暑期实习看起来挺吸引人的,但日常实习在帮你积累实力和性价比上也不是盖的,特别是对于那些还没什么经验的同学。 所以还没有实习经验的同学,有日常实习机会的话,就赶紧冲!!!
最后,说了这么多,**不如咱们直接进入一场小米暑期实习的面试现场,**看看那些参与其中的学生们是怎么想的,他们又是怎样抓住机会,向面试官展示自己的实力的。
还有更多面经可以直接去戳我主页~
(在公众号中插入主页tab)
二、面试全过程分享
以下来源于应聘者的真实回忆。
(1)自我介绍
面试官: 嗨,很高兴你能来参加小米的暑期实习面试。首先,给我做个自我介绍吧。
求职者: 您好,我是小明,目前是一名计算机科学与技术专业的学生。我对编程和新技术充满热情,尤其对网络通信、数据结构和算法等领域有着浓厚的兴趣。我曾经参与过几个小型项目,比如开发了一个简单的社交媒体应用和一个个人博客网站。我非常期待有机会加入小米,和优秀的团队一起工作,学习和成长。
(2)技术环节
面试官: 很好,小明。让我们进入技术环节。能否谈谈你对TCP/IP五层模型的理解,同时指出TCP和IP分别属于哪一层?
求职者: 当然可以。TCP/IP五层模型主要包括应用层、传输层、网络层、数据链路层和物理层。其中,TCP位于传输层,负责提供可靠的、面向连接的数据传输服务。而IP位于网络层,负责进行路由选择和数据包的传输。 面试官: 很好的回答。那么,你能否解释一下UDP和TCP的主要区别?
求职者: 当然。**TCP(传输控制协议)是一种面向连接的、可靠的传输协议,它通过三次握手建立连接,确保数据的顺序传输和完整性。而UDP(用户数据报协议)**是一种无连接的协议,它不保证数据包的顺序和完整性,因此传输效率更高,但可靠性较差。UDP常用于不需要建立连接的场景,如视频流和在线游戏。
面试官: 说得不错。接下来,谈谈你对HTTPS和HTTP的区别的理解,尤其是SSL握手过程。
求职者: HTTPS实际上是在HTTP上增加了SSL/TLS协议,用于加密客户端和服务器之间的通信,以确保数据传输的安全性。在SSL握手过程中,首先客户端会向服务器发送一个请求,包括支持的加密方法。然后服务器选择一个加密方法,并将证书发送给客户端。客户端验证证书的有效性后,双方会生成一个共享的密钥用于加密通信。这个过程确保了数据传输的安全,防止了中间人攻击。 面试官: 那么,为什么说TCP是三次握手,而断开连接时却需要四次挥手呢?
求职者: 这是因为TCP是全双工的通信方式,所以断开连接时需要双方各自确认。三次握手是为了建立连接时确保双方的接收和发送能力都是正常的。而四次挥手则是因为当一方想要关闭连接时,需要向另一方发送一个FIN报文。接收方收到后会回复一个ACK报文,但此时可能还有数据在传输,所以不能立即关闭,需要等数据传输完毕后,接收方才会发送FIN报文告知可以关闭,发送方收到后再回复一个ACK报文,最终完成断开。
面试官: 嗯,对于网络层的知识掌握得不错。现在我们来聊聊Java常用的数据结构。你提到了ArrayList和HashMap,你能告诉我它们的区别、优缺点吗?
求职者: ArrayList是基于动态数组的数据结构,它允许进行快速的随机访问。但是,由于是数组,所以在进行插入或删除操作时可能需要移动元素,特别是在数组的前部分插入或删除时,性能较低。LinkedList则是基于双向链表实现的,它允许在任何位置进行快速的插入和删除操作。但是,由于链表的特性,它在随机访问性能上不如ArrayList。
面试官: 那么使用for循环遍历LinkedList进行删除或插入操作会遇到什么问题?
求职者: 如果我们使用for循环遍历LinkedList进行删除或插入操作,可能会遇到ConcurrentModificationException异常。这是因为LinkedList的迭代器不是快速失败的,如果在迭代过程中修改了列表,则迭代器的行为将不可预知。此外,在使用索引进行操作时,LinkedList的效率会相对较低,因为它需要从头开始或从尾部开始遍历到指定索引的位置。
面试官: 明白了。那HashMap的扩容机制是怎样的?
求职者: 当HashMap中的元素数量达到负载因子乘以容量的值时,HashMap就会进行扩容。扩容通常是将HashMap的容量增加到之前的两倍,并重新计算每个元素在新数组中的位置,这个过程称为rehash。这可能是一个性能开销较大的操作,因为它涉及到重新计算所有元素的散列码。
面试官: 很好。让我们继续。ConcurrentHashMap是如何保证线程安全的?
求职者: ConcurrentHashMap通过使用分段锁来实现线程安全。它将容器分成几个段,每个段都有自己的锁。当进行修改操作时,只需要锁定当前段,这样就可以同时进行多个线程的修改操作,而不是像HashTable那样锁定整个Map,提高了并发性能。
面试官: 好的,接下来,你能讲讲你对Redis使用过的数据结构有哪些了解吗?
求职者: 当然。Redis支持多种数据结构,包括字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)、**有序集合(Sorted Sets)**等。每种数据结构都适用于特定的场景。例如,字符串可以用来存储文本或数字数据,列表适合实现队列,哈希适合存储对象,而有序集合则适用于需要排序的数据集。
面试官: 那么你能详细讲讲ZSet的底层实现吗?
求职者: ZSet即有序集合,它是通过跳表(Skip List)和哈希表的结合来实现的。跳表用于维护元素的顺序,确保元素可以在对数时间复杂度内进行插入、删除和查找操作,而哈希表则用于存储元素的分数(score),以便快速访问。这种结合的方式使得ZSet在保持元素有序的同时,也能高效地进行数据的增删查操作。
面试官: 谈到Redis,不得不提持久化。你对Redis的RDB持久化机制有何了解?
求职者: Redis的RDB持久化是通过创建数据集的快照来完成的。在配置文件中,我们可以设置不同的策略来决定何时触发快照的创建,比如,在指定的时间内执行了多少次写操作。快照一旦创建,就可以将其保存到磁盘上,并在需要时用于数据的恢复。关于面试官提到的开启RDB的时间间隔设置,它主要取决于数据的重要性以及可以容忍的数据丢失窗口。通常,频繁的快照会增加IO压力,但可以减少数据丢失的风险。
面试官: 既然提到了数据,那么缓存击穿的问题你是如何解决的?
求职者: 缓存击穿主要指查询一个数据库中不存在的数据,由于缓存未命中,每次查询都会去数据库查询,导致数据库压力过大。解决缓存击穿的常见方法是设置热点数据永不过期,或者使用布隆过滤器来提前判断数据是否存在于数据库中,避免对数据库的无效查询。
面试官: 讲到布隆过滤器,你能解释一下它的原理吗?以及它是如何解决Redis缓存问题的?
求职者: 布隆过滤器是一种空间效率高的概率型数据结构,用于判断一个元素是否在一个集合中。它通过多个不同的哈希函数将元素映射到一个大的位数组上。如果检查元素时,位数组中对应的所有位置都为1,则元素可能存在;如果有任何一个位置为0,则元素肯定不存在。布隆过滤器用于Redis缓存问题主要是减少缓存穿透的发生,通过在访问数据库之前先检查布隆过滤器,若判断数据不在缓存中,则不需要查询数据库,从而减轻数据库的压力。
面试官: 有趣。如果两个key通过布隆过滤器映射到了相同的位置,然后一个key被删除,另一个key访问时就会被误判为不存在。你如何解决这个问题?
求职者: 这是布隆过滤器的一个典型问题,即误判率。由于布隆过滤器的删除操作会影响到其他元素,一个简单的解决方案是不进行删除操作。对于需要删除的场景,可以考虑使用计数型布隆过滤器,它允许元素的添加和删除,每个位被替换为计数器,但这会增加空间的使用。另一种方法是定期更换布隆过滤器,结合适当的缓存策略,减少误判对系统的影响。
面试官: 很全面的回答。在使用@Transactional注解声明事务时,你知道它在什么情况下会失效吗?
求职者: @Transactional注解可能在几种情况下失效:首先,如果被注解的方法被同一个类中的非事务方法直接调用时,事务声明不会被处理,因为事务的代理是基于AOP的,而直接方法调用不会通过代理。其次,如果在方法抛出的异常不是RuntimeException或Error时(默认情况下),事务是不会回滚的。还有,如果使用了不支持事务的数据库,或者@Transactional注解没有配置在正确的Bean上,也会导致事务失效。
(3)应用场景技术题目(涉及到具体项目)
面试官: 这部分讲得很清楚。现在让我们来讨论一个具体的场景问题。假设我们在一个电影院买票系统中有三个表:电影票表、用户金额表、电影院金额表。你认为对这三个表进行操作时,应该怎样处理才能保证效率更高?
求职者: 对于这种涉及到多个表的操作,我们首先要保证的是数据的一致性和事务的原子性。我们可以使用事务管理来确保在一个用户购买电影票的过程中,不仅票务信息要更新,用户和电影院的金额也需要同时更新。为了提高效率,我们可以采用批处理技术,将多个更新操作合并在一起执行。此外,为了减少锁的范围和时间,我们应该尽量使用行锁而不是表锁,这样可以在不影响其他用户操作的情况下进行数据更新。同时,我们还可以考虑使用乐观锁或悲观锁,根据业务场景的具体需求来选择。
面试官: 这个场景分析得很细致。那你知道MySQL的默认存储引擎是什么吗?它有什么特点?
求职者: MySQL的默认存储引擎是InnoDB。它的特点包括支持ACID事务,具有行级锁定和外键约束等功能。InnoDB还提供了强大的恢复能力,即使在系统崩溃后也能保证数据的完整性。此外,InnoDB支持高并发,因为它使用了多版本并发控制(MVCC),在读取数据时通常不需要锁定资源。
面试官: 既然提到了InnoDB,你还知道它除了行锁、表锁之外的哪些锁类型吗?
求职者: InnoDB还支持意向锁,这是一种表级锁,用来表明某个事务对表中的行进行了锁定。具体来说,有意向共享锁(IS)和意向排他锁(IX)。此外,InnoDB还有记录锁,锁定单个行记录,以及间隙锁,锁定一个范围,但不包括实际的记录,用于防止幻读。 面试官: 关于数据库索引,你能解释一下为什么主键索引比非主键索引快吗?
求职者: 主键索引(也称为聚集索引)之所以比非主键索引(辅助索引或二级索引)快,是因为聚集索引的叶子节点存储的是整行数据。所以,当通过主键索引查找时,可以直接定位到数据行。而非主键索引的叶子节点存储的是主键的值,当通过非主键索引查找时,还需要进行一次额外的查找,即回表操作,通过主键的值来查找实际的数据行,这就增加了查询时间。
面试官: 那你平时如何排查慢SQL?在EXPLAIN语句中,你了解哪些字段?
求职者: 排查慢SQL通常首先要打开慢查询日志,记录下执行时间超过设定阈值的SQL语句。然后,我会使用EXPLAIN命令来分析这些慢查询。在EXPLAIN的结果中,我关注的字段包括type,表示连接类型,possible_keys,表示可能应用于这张表的索引,key,表示实际使用的索引,rows,表示MySQL认为必须检查的行数,以及Extra,其中可能包含重要的额外信息,比如是否使用了文件排序或者临时表。
面试官: 在实际项目中,你有没有使用过消息队列,比如RabbitMQ?能否分享一下如何保证消息不被重复消费以及如何保证消息的可靠性?
求职者: 是的,我在项目中使用过RabbitMQ。为了防止消息被重复消费,我们可以在消息处理成功后显式地发送一个acknowledgment(ACK)给消息队列,这样消息队列就知道这条消息已经被正确处理了,不会再次投递这条消息。为了保证消息的可靠性,我们使用了消息持久化,确保即使RabbitMQ服务器重启,消息也不会丢失。此外,我们还可以配置死信队列来处理无法正常消费的消息,以及使用发布确认机制来确保消息正确地从生产者发送到队列。
面试官: 如果突然有大量请求进入MQ,你会如何解决这些消息的正常消费呢?
求职者: 当大量请求涌入MQ时,首先要确保消息队列的服务能够处理这样的负载,可能需要增加更多的消费者来处理消息。如果是短时间的高峰,可以使用消息的预取功能来限制消费者一次获取的消息数量,防止一些消费者过载而其他消费者空闲。此外,可以通过设置优先级队列来确保重要的消息先被处理。如果长时间都有高负载,可能需要考虑对消息队列进行水平扩展,比如增加更多的RabbitMQ节点和消费者。
面试官: 在你的项目经历中,遇到过哪些难题,并且你是如何解决的?
求职者: 在我之前的一个项目中,我们遇到了数据库查询性能瓶颈的问题,这直接影响到了用户体验。为了解决这个问题,首先,我使用了EXPLAIN和慢查询日志来定位慢查询。然后,我对数据库的索引进行了优化,添加了必要的索引,并调整了一些查询语句的结构。此外,我还引入了缓存机制,将一些热点数据存储在Redis中,这大大减少了数据库的压力并提高了查询速度。
面试官: 说到Spring Boot,你能解释一下它的自动配置原理吗?
求职者: Spring Boot的自动配置是通过@EnableAutoConfiguration注解来实现的,这个注解会触发一个自动配置的过程。Spring Boot会在classpath中搜索所有META-INF/spring.factories配置文件,找到所有配置有@Configuration的类。然后,它会根据条件注解,如@ConditionalOnClass、@ConditionalOnBean等,来决定哪些配置是有效的,并将它们应用到应用程序上下文中。这个过程大大简化了Spring应用的配置,因为开发者不需要手动定义所有的Bean。
面试官: 最后,我们来到了手撕代码环节。你提到你解决了最长前缀的问题并且面试官给了你一个优化方案。那么,你可以分享一下你的原始思路和面试官提供的优化方案吗?
求职者: 当然。我的原始思路是使用水平扫描法。我将第一个字符串作为前缀,然后遍历其他所有字符串,一次比较每个字符串的字符。如果在某个字符串中找到不匹配的字符,我就缩短前缀并继续比较。面试官提供的优化方案是使用分治法,将字符串数组分成两部分,分别找出每部分的最长公共前缀,然后再将两个结果合并。这个方法在处理大量字符串时会更高效。
(4)其他(性格、偏好、个人理解、反问等)
面试官: 非常好。那么,你对小米有什么了解?或者说,你对加入小米有什么期待?
求职者: 我知道小米是一家以互联网思维打造硬件、软件和互联网服务的全球性公司。它不仅在智能手机领域有很强的竞争力,还在智能家居、电子健康和云服务等多个领域有所布局。加入小米,我最期待的是能够参与到这些前沿技术的研发中,和一流的团队一起工作,不断学习和挑战自己,为用户创造更好的产品和服务。
面试官: 很棒,你的回答非常全面,感谢你今天的参与。我们会尽快给你反馈。
三、总结
总结来说,这场面试强调了技术深度、问题解决能力、项目经验、对公司的了解以及持续学习的态度。 后来的面试者应该准备充分,**不仅要掌握技术知识,还要能够将这些知识应用到实际问题中,**并且展示出对目标公司的热情和个人职业发展的规划。 最近各大厂及公司的暑期实习都在密集开启了,本文抽取3位同学,帮助大家免费review大家的简历,有兴趣的朋友可以扫描以下二维码,备注【简历】即可~