不甘示弱,我们也新招6000人!
共 8844字,需浏览 18分钟
·
2024-07-28 14:04
大家好,我是二哥呀。
25 届秋招正式批是说来就来啊,这不京东官宣要招聘 16000 人,美团这边也不甘示弱,表示要新招 6000 人,于 7 月 29 日正式开启,比京东还早 2 天。
美团去年就招了 6000 人,今年人数虽然没有上涨,但也算是稳打稳扎了。并且美团的薪资待遇也不错。人才们,请抓紧时间冲吧(😄)。
大家可以先瞅一眼 24 届美团的薪资待遇,211 本也能拿到 21k 的白菜,一年 33 万朝上的年包很香了(15.5 个月)。星球里去年有球友拿到团子的 SSP offer,薪资就可观到只能保密。
应该有不少小伙伴对美团很感兴趣,那接下来我们就以《Java 面试指南》里收录的《美团面经同学3 Java 一面》为例,来看看开水团的面试官都喜欢问哪些问题,好为今年的秋招做个模拟。
1、二哥修订版《30天速通Java.pdf》下载 2、三分恶面渣逆袭在线版:https://javabetter.cn/sidebar/sanfene/nixi.html
美团同学3 Java 一面面经
一些常见的八股这里就不贴答案了,大家直接去看《面渣逆袭》在线版,我在每道题下面都会标记清楚。
java的反射机制,反射的应用场景AOP的实现原理是什么,与动态代理和反射有什么区别
反射允许 Java 在运行时检查和操作类的方法和字段。通过反射,可以动态地获取类的字段、方法、构造方法等信息,并在运行时调用方法或访问字段。
反射有哪些应用场景?
①、Spring 框架就大量使用了反射来动态加载和管理 Bean。
Class<?> clazz = Class.forName("com.example.MyClass");
Object instance = clazz.newInstance();
②、Java 的动态代理(Dynamic Proxy)机制就使用了反射来创建代理类。代理类可以在运行时动态处理方法调用,这在实现 AOP 和拦截器时非常有用。
InvocationHandler handler = new MyInvocationHandler();
MyInterface proxyInstance = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class<?>[] { MyInterface.class },
handler
);
AOP 的实现原理是什么?
Spring 的 AOP 是通过动态代理来实现的,动态代理主要有两种方式:JDK 动态代理和 CGLIB 代理。
①、JDK 动态代理是基于接口的代理,只能代理实现了接口的类。使用 JDK 动态代理时,Spring AOP 会创建一个代理对象,该代理对象实现了目标对象所实现的接口,并在方法调用前后插入横切逻辑。
②、CGLIB 动态代理是基于继承的代理,可以代理没有实现接口的类。使用 CGLIB 动态代理时,Spring AOP 会生成目标类的子类,并在方法调用前后插入横切逻辑。
说说 AOP 和反射的区别?
-
反射:用于检查和操作类的方法和字段,动态调用方法或访问字段。反射是 Java 提供的内置机制,直接操作类对象。 -
动态代理:通过生成代理类来拦截方法调用,通常用于 AOP 实现。动态代理使用反射来调用被代理的方法。
object有哪些方法 hashcode和equals为什么需要一起重写 不重写会导致哪些问题 什么时候会用到重写hashcode的场景
Object 主要提供了 11 个方法,大致可以分为六类:
为什么重写 equals 时必须重写 hashCode ⽅法?
因为基于哈希的集合类(如 HashMap)需要基于这一点来正确存储和查找对象。
具体地说,HashMap 通过对象的哈希码将其存储在不同的“桶”中,当查找对象时,它需要使用 key 的哈希码来确定对象在哪个桶中,然后再通过 equals()
方法找到对应的对象。
如果重写了 equals()
方法而没有重写 hashCode()
方法,那么被认为相等的对象可能会有不同的哈希码,从而导致无法在HashMap 中正确处理这些对象。
最左匹配原则 索引失效
最左前缀原则,也叫最左匹配原则,或者最左前缀匹配原则。
最左匹配原则是指在使用联合索引(即包含多列的索引)时,查询条件从索引的最左列开始并且不跳过中间的列。
如果一个复合索引包含(col1, col2, col3)
,那么它可以支持 col1
、col1,col2
和 col1, col2, col3
的查询优化,但不会优化只有 col2 或 col3 的查询。
也就说,在进行查询时,如果没有遵循最左前缀,那么索引可能不会被利用,导致查询效率降低。
索引失效的场景
-
在索引列上使用函数或表达式:如果在查询中对索引列使用了函数或表达式,那么索引可能无法使用,因为数据库无法预先计算出函数或表达式的结果。例如: SELECT * FROM table WHERE YEAR(date_column) = 2021
。 -
使用不等于( <>
)或者 NOT 操作符:这些操作符通常会使索引失效,因为它们会扫描全表。 -
使用 LIKE 操作符,但是通配符在最前面:如果 LIKE 的模式串是以“%”或者“_”开头的,那么索引也无法使用。例如: SELECT * FROM table WHERE column LIKE '%abc'
。 -
OR 操作符:如果查询条件中使用了 OR,并且 OR 两边的条件分别涉及不同的索引,那么这些索引可能都无法使用。 -
联合索引不满足最左前缀原则时,索引会失效。
线程池怎么设计,拒绝策略有哪些,如何选择
线程池的设计需要考虑这几个关键因素:
-
核心线程池类:包含核心线程数、最大线程数。 -
工作线程:线程池中实际工作的线程,从任务队列中获取任务并执行。 -
任务队列:存放待执行任务的队列,可以使用阻塞队列实现。 -
拒绝策略:当任务队列满时,处理新任务的策略。
小二去银行办理业务,被经理“薄纱”了:“我们系统瘫痪了”、“谁叫你来办的你找谁去”、“看你比较急,去队里加个塞”、“今天没办法,不行你看改一天”。
分别对应线程池中的四种拒绝策略:
-
AbortPolicy:这是默认的拒绝策略。该策略会抛出一个 RejectedExecutionException 异常。也就对应着“我们系统瘫痪了”。 -
CallerRunsPolicy:该策略不会抛出异常,而是会让提交任务的线程(即调用 execute 方法的线程)自己来执行这个任务。也就对应着“谁叫你来办的你找谁去”。 -
DiscardOldestPolicy:策略会丢弃队列中最老的一个任务(即队列中等待最久的任务),然后尝试重新提交被拒绝的任务。也就对应着“看你比较急,去队里加个塞”。 -
DiscardPolicy:策略会默默地丢弃被拒绝的任务,不做任何处理也不抛出异常。也就对应着“今天没办法,不行你看改一天”。
jmm内存模型 栈 方法区存放的是什么
Java 内存模型(Java Memory Model)是一种抽象的模型,简称 JMM,主要用来定义多线程中变量的访问规则,用来解决变量的可见性、有序性和原子性问题,确保在并发环境中安全地访问共享变量。
JMM 定义了线程内存和主内存之间的抽象关系:线程之间的共享变量存储在主内存
(Main Memory)中,每个线程都有一个私有的本地内存
(Local Memory),本地内存中存储了共享变量的副本,用来进行线程内部的读写操作。
-
当一个线程更改了本地内存中共享变量的副本后,它需要将这些更改刷新到主内存中,以确保其他线程可以看到这些更改。 -
当一个线程需要读取共享变量时,它可能首先从本地内存中读取。如果本地内存中的副本是过时的,线程将从主内存中重新加载共享变量的最新值到本地内存中。
介绍一下 Java 虚拟机栈?
Java 虚拟机栈(Java Virtual Machine Stack),通常指的就是“栈”,它的生命周期与线程相同。
当线程执行一个方法时,会创建一个对应的栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,然后栈帧会被压入栈中。当方法执行完毕后,栈帧会从栈中移除。
介绍一下方法区?
方法区并不真实存在,属于 Java 虚拟机规范中的一个逻辑概念,用于存储已被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等。
在 HotSpot 虚拟机中,方法区的实现称为永久代(PermGen),但在 Java 8 及之后的版本中,已经被元空间(Metaspace)所替代。
如何判断sql的效率,怎样排查效率比较低的sql
排查 SQL 效率主要通过两种手段:
-
慢查询日志:开启 MySQL 慢查询日志,再通过一些工具比如 mysqldumpslow 去分析对应的慢查询日志,找出问题的根源。 -
服务监控:可以在业务的基建中加入对慢 SQL 的监控,常见的方案有字节码插桩、连接池扩展、ORM 框架过程,对服务运行中的慢 SQL 进行监控和告警。
也可以使用 show processlist;
查看当前正在执行的 SQL 语句,找出执行时间较长的 SQL。
找到对应的慢 SQL 后,使用 EXPLAIN 命令查看 MySQL 是如何执行 SQL 语句的,再根据执行计划对 SQL 进行优化。
EXPLAIN SELECT * FROM your_table WHERE conditions;
如何保证redis缓存与数据库的一致性,为什么这么设计
在技术派实战项目中,我采用的是先写 MySQL,再删除 Redis 的方式来保证缓存和数据库的数据一致性。
对于第一次查询,请求 B 查询到的缓存数据是 10,但 MySQL 被请求 A 更新为了 11,此时数据库和缓存不一致。
但也只存在这一次不一致的情况,对于不是强一致性的业务,可以容忍。
当请求 B 第二次查询时,因为请求 A 更新完数据库把缓存删除了,所以请求 B 这次不会命中缓存,会重新查一次 MySQL,然后回写到 Redis。
缓存和数据库又一致了。
java的类加载机制 双亲委派机制 这样设计的原因是什么
JVM 的操作对象是 Class 文件,JVM 把 Class 文件中描述类的数据结构加载到内存中,并对数据进行校验、解析和初始化,最终形成可以被 JVM 直接使用的类型,这个过程被称为类加载机制。
其中最重要的三个概念就是:类加载器、类加载过程和类加载器的双亲委派模型。
-
类加载器:负责加载类文件,将类文件加载到内存中,生成 Class 对象。 -
类加载过程:加载、验证、准备、解析和初始化。 -
双亲委派模型:当一个类加载器收到类加载请求时,它首先不会自己去尝试加载这个类,而是把请求委派给父类加载器去完成,依次递归,直到最顶层的类加载器,如果父类加载器无法完成加载请求,子类加载器才会尝试自己去加载。
为什么要用双亲委派模型?
可以为 Java 应用程序的运行提供一致性和安全性的保障。
①、保证 Java 核心类库的类型安全
如果自定义类加载器优先加载一个类,比如说自定义的 Object,那在 Java 运行时环境中就存在多个版本的 java.lang.Object,双亲委派模型确保了 Java 核心类库的类加载工作由启动类加载器统一完成,从而保证了 Java 应用程序都是使用的同一份核心类库。
②、避免类的重复加载
在双亲委派模型中,类加载器会先委托给父加载器尝试加载类,这样同一个类不会被加载多次。如果没有这种模型,可能会导致同一个类被不同的类加载器重复加载到内存中,造成浪费和冲突。
https相比http有什么区别 对称加密和非对称加密 ca证书验证
使用 HTTPS 主要是为了解决 HTTP 传输过程中的一些安全问题,因为 HTTP 是明文传输,所以 HTTPS 在 HTTP 的基础上加入了 SSL/TLS 协议。
SSL(安全套接字)/TLS(传输层安全)协议可以用来加密通信内容,保证通信过程中的数据不被窃取和篡改。整个加密过程主要涉及两种类型的加密方法:
-
非对称加密:服务器向客户端发送公钥,然后客户端用公钥加密自己的随机密钥,也就是会话密钥,发送给服务器,服务器用私钥解密,得到会话密钥。 -
然后双方用会话密钥加密通信内容。
客户端会通过数字证书来验证服务器的身份,数字证书由 CA(证书权威机构)签发,包含了服务器的公钥、证书的颁发机构、证书的有效期等信息。
数据库中的全局锁 表锁 行级锁 每种锁的应用场景有哪些
全局锁就是对整个数据库实例进行加锁,在 MySQL 中,可以使用 FLUSH TABLES WITH READ LOCK
命令来获取全局读锁。
全局锁的作用是保证在备份数据库时,数据不会发生变化【数据更新语句(增删改)、数据定义语句(建表、修改表结构等)和更新事务的提交语句】。当我们需要备份数据库时,可以先获取全局读锁,然后再执行备份操作。
表锁(Table Lock)就是锁住整个表。在 MySQL 中,可以使用 LOCK TABLES
命令来锁定表。
表锁可以分为读锁(共享锁)和写锁(排他锁)。
LOCK TABLES your_table READ;
-- 执行读操作
UNLOCK TABLES;
读锁允许多个事务同时读取被锁定的表,但不允许任何事务进行写操作。
LOCK TABLES your_table WRITE;
-- 执行写操作
UNLOCK TABLES;
写锁允许一个事务对表进行读写操作,其他事务不能对该表进行任何操作(读或写)。
在进行大规模的数据导入、导出或删除操作时,为了防止其他事务对数据进行并发操作,可以使用表锁。
或者在进行表结构变更(如添加列、修改列类型)时,为了确保变更期间没有其他事务访问或修改该表,可以使用表锁。
说说 MySQL 的行锁?
行级锁(Row Lock)是数据库锁机制中最细粒度的锁,主要用于对单行数据进行加锁,以确保数据的一致性和完整性。
在 MySQL 中,InnoDB 存储引擎支持行级锁。通过 SELECT ... FOR UPDATE
可以加排他锁,通过 LOCK IN SHARE MODE
可以加共享锁。
比如说:
START TRANSACTION;
-- 加排他锁,锁定某一行
SELECT * FROM your_table WHERE id = 1 FOR UPDATE;
-- 对该行进行操作
UPDATE your_table SET column1 = 'new_value' WHERE id = 1;
COMMIT;
START TRANSACTION;
-- 加共享锁,锁定某一行
SELECT * FROM your_table WHERE id = 1 LOCK IN SHARE MODE;
-- 只能读取该行,不能修改
COMMIT;
在高并发环境中,行级锁能够提高系统的并发性能,因为锁定的粒度较小,只会锁住特定的行,不会影响其他行的操作。
内容来源
-
星球嘉宾三分恶的面渣逆袭:https://javabetter.cn/sidebar/sanfene/nixi.html -
二哥的 Java 进阶之路(GitHub 已有 12000+star):https://javabetter.cn
ending
一个人可以走得很快,但一群人才能走得更远。二哥的编程星球已经有 5800 多名球友加入了,如果你也需要一个良好的学习环境,戳链接 🔗 加入我们吧。这是一个编程学习指南 + Java 项目实战 + LeetCode 刷题的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。
两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的学习资源,相信能帮助你走的更快、更稳、更远。
欢迎点击左下角阅读原文了解二哥的编程星球,这可能是你学习求职路上最有含金量的一次点击。
最后,把二哥的座右铭送给大家:没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。共勉 💪。