前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >赢了!美的一面,被我狠狠拿捏了

赢了!美的一面,被我狠狠拿捏了

作者头像
小林coding
发布2025-02-19 12:53:31
发布2025-02-19 12:53:31
5800
代码可运行
举报
文章被收录于专栏:小林coding
运行总次数:0
代码可运行
图片
图片

图解学习网站:https://xiaolincoding.com

大家好,我是小林。

美的(不是美团)开发岗的校招薪资普遍是 17.5k x 14,办公地点主要是在二线城市,比如佛山、武汉、顺德,总包 24.5w 在二线城市过的相当舒服。

再来聊聊,美的校招的面试流程:

  • 笔试:选择题+编程题为主,跟Java相关的比较多,考察了Java基础,spring,数据库,算法,并发,JVM,操作系统,网络,智力题等,比较全面,范围很广。
  • 测评:常规测评题,性格、价值观、智商方面的
  • 一面:技术面为主,以项目+八股拷打为主,一场技术面最多就半小时,大部分是 20 分钟左右
  • 二面:聊天局,聊聊经历和项目,比较少会再问八股细节了。
  • 终面:领导面,面试还是关注岗位本身的工作内容与简历内容的匹配度

那美的技术面到底难度如何呢?因为美的技术面考察时间就 20 分钟左右,所以最多就问 10 个技术问题,面试的强度还是比互联网中大低的。

这次来看看一位同学的 「美的 Java 软开的一面」,考察的知识点主要是 Java、Spring、MySQL、项目这些内容,同学最后是通过了,成功进入到二面。

你们觉得难度如何?

美的一面(25分钟)

什么是继承和多态?

特性

继承

多态

核心目的

复用代码,构建层次结构

统一接口,多样化实现

操作对象

类与类的关系

方法与对象的关系

关键语法

extends 关键字

父类引用 = new 子类对象()

继承是面向对象编程中代码重用的一种重要机制,在 Java 中通过extends关键字来实现继承,子类可以直接使用父类中已定义好的属性和方法,还可以添加自己特有的属性和方法,实现功能的扩展。继续也具备传递性,如果类 C 继承自类 B,类 B 继承自类 A,那么类 C 不仅继承了类 B 的属性和方法,也间接继承了类 A 的属性和方法。

多态是指同一个操作在不同对象上可以表现出不同的行为。例如,同样是 “发声” 这个操作,“狗” 类的对象调用会发出 “汪汪” 声,“猫” 类的对象调用会发出 “喵喵” 声。多态实现方式有两种:

  • 运行时多态:基于方法重写(Override),通过父类引用调用子类对象,比如,父类Animal中有void sound()方法,子类Dog重写这个方法后实现自己特有的 “汪汪” 叫的声音。
  • 编译时多态:方法重载(Overload),同一类中有同名不同参数的方法,例如,一个Calculator类中可以有add(int a, int b)add(double a, double b)等方法。

Java是单继承还是多继承?

是单继承,就是说一个类只能有一个直接父类。

代码语言:javascript
代码运行次数:0
复制
class Animal { } 

class Dog extends Animal { } // ✅ 正确:单继承

// class Cat extends Animal, Plant { } // ❌ 错误:Java不支持类多继承

单继承的好处是可以避免多继承引发的钻石问题,这样一个类从多个父类继承相同成员,引发二义性,如类 D 同时继承类 B 和类 C,而 B 和 C 又都继承自类 A,且 B 和 C 对 A 中的某个方法进行了不同实现,那么 D 在调用该方法时就无法确定应使用 B 还是 C 的实现。

有用过泛型吗,讲一下?

用过,泛型允许开发者编写类型参数化的代码,让同一套逻辑可以安全地操作多种数据类型,泛型的主要目的是在编译时提供更强的类型检查,并且在编译后能够保留类型信息,避免了在运行时出现类型转换异常。

比如,把泛型定义在类上,定义格式为class 类名<类型参数>{},如class Box<T>{},使用时需在创建对象时指定具体类型,如Box<String> stringBox = new Box<>();,这时候遇到与指定类型不符的代码,就会在编译的时候报错。

代码语言:javascript
代码运行次数:0
复制
// 泛型类的定义
public class Box<T> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

// 使用类型参数(实例化时指定类型)
Box<String> stringBox = new Box<>();
stringBox.setContent("Java");   // ✔️ 编译时检查类型
// stringBox.setContent(123);   ❌ 编译报错
String value = stringBox.getContent(); // 无需强制转换

泛型的价值体现在下面这三个地方:

特性

解决的问题

实际应用场景

类型参数化

避免重复编写类似代码

通用容器类(如 List<T>、Map<K,V>)

编译时类型检查

防止类型错误扩散到运行时

集合操作、工具方法设计

通配符

提升方法参数的灵活性

通用算法(如集合工具类 Collections)

什么是反射?有用过吗

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

比如,获取一个Class对象。Class.forName(完整类名)。通过Class对象获取类的构造方法,class.getConstructor。根据Class对象获取类的方法,getMethodgetMethods。使用Class对象创建一个对象,class.newInstance等。

反射具有以下特性:

  1. 运行时类信息访问:反射机制允许程序在运行时获取类的完整结构信息,包括类名、包名、父类、实现的接口、构造函数、方法和字段等。
  2. 动态对象创建:可以使用反射API动态地创建对象实例,即使在编译时不知道具体的类名。这是通过Class类的newInstance()方法或Constructor对象的newInstance()方法实现的。
  3. 动态方法调用:可以在运行时动态地调用对象的方法,包括私有方法。这通过Method类的invoke()方法实现,允许你传入对象实例和参数值来执行方法。
  4. 访问和修改字段值:反射还允许程序在运行时访问和修改对象的字段值,即使是私有的。这是通过Field类的get()和set()方法完成的。

反射的优点就是增加灵活性,可以在运行时动态获取对象实例。缺点是反射的效率很低,而且会破坏封装,通过反射可以访问类的私有方法,不安全。

springboot的常用注解有哪些?

Bean 相关:

  • @Component:将一个类标识为 Spring 组件(Bean),可以被 Spring 容器自动检测和注册。通用注解,适用于任何层次的组件。
  • @ComponentScan:自动扫描指定包及其子包中的 Spring 组件。
  • @Controller:标识控制层组件,实际上是 @Component 的一个特化,用于表示 Web 控制器。处理 HTTP 请求并返回视图或响应数据。
  • @RestController:是 @Controller 和 @ResponseBody 的结合,返回的对象会自动序列化为 JSON 或 XML,并写入 HTTP 响应体中。
  • @Repository:标识持久层组件(DAO 层),实际上是 @Component 的一个特化,用于表示数据访问组件。常用于与数据库交互。
  • @Bean:方法注解,用于修饰方法,主要功能是将修饰方法的返回对象添加到 Spring 容器中,使得其他组件可以通过依赖注入的方式使用这个对象。

依赖注入:

  • @Autowired:用于自动注入依赖对象,Spring 框架提供的注解。
  • @Resource:按名称自动注入依赖对象(也可以按类型,但默认按名称),JDK 提供注解。
  • @Qualifier:与 @Autowired 一起使用,用于指定要注入的 Bean 的名称。当存在多个相同类型的 Bean 时,可以使用 @Qualifier 来指定注入哪一个。

读取配置:

  • @Value:用于注入属性值,通常从配置文件中获取。标注在字段上,并指定属性值的来源(如配置文件中的某个属性)。
  • @ConfigurationProperties:用于将配置属性绑定到一个实体类上。通常用于从配置文件中读取属性值并绑定到类的字段上。

Web相关:

  • @RequestMapping:用于映射 HTTP 请求到处理方法上,支持 GET、POST、PUT、DELETE 等请求方法。可以标注在类或方法上。标注在类上时,表示类中的所有响应请求的方法都是以该类路径为父路径。
  • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping:分别用于映射 HTTP GET、POST、PUT、DELETE 请求到处理方法上。它们是 @RequestMapping 的特化,分别对应不同的 HTTP 请求方法。

其他常用注解:

  • @Transactional:声明事务管理。标注在类或方法上,指定事务的传播行为、隔离级别等。
  • @Scheduled:声明一个方法需要定时执行。标注在方法上,并指定定时执行的规则(如每隔一定时间执行一次)。

springboot相比spring的优势在哪里?

Spring Boot 不是一个新框架,而是在 Spring 框架基础上的高级封装,通过「开箱即用」的设计哲学,让开发者专注于业务代码而非基础配置。以下是详细对比:

对比点

Spring

Spring Boot

项目初始化

手动配置 XML/JavaConfig

内置自动配置,提供 start.spring.io 快速生成项目结构

依赖管理

手动维护版本,易冲突

Starter POMs 统一管理依赖版本

内嵌服务器

需手动部署到 Tomcat 等

默认内嵌 Tomcat/Jetty,无需外部部署

配置复杂度

需配置大量 Bean 和集成代码

约定优于配置,自动配置大部分组件

监控与管理

需集成第三方工具

内置 Actuator 提供健康检查、指标收集等

打包与部署

需生成 WAR 包并部署到服务器

可执行 JAR,java -jar 一键启动

Spring Boot 的核心竞争优势在于提升开发效率,通过以下设计实现:

  • 约定优于配置:Spring Boot 采用 “约定优于配置” 原则,通过自动配置机制,根据项目依赖自动识别并配置相关 Bean。例如,引入 Spring Data JPA 依赖,Spring Boot 会自动配置好数据源、实体管理器等相关组件,而在 Spring 中则需手动配置大量的 XML 或 Java 配置类。
  • 构建即运行的一体化体验:Spring Boot 提供依赖启动器 “starter”,在构建项目时,只需选择对应的场景依赖启动器,内部会自动包含并拉取相关依赖,而且 Spring Boot 内嵌 Tomcat、Jetty 等服务器,可将项目打成 JAR 包,使用 “java -jar xx.jar” 直接运行。Spring 应用通常需要部署到外部容器中才能运行,部署过程相对复杂。

这样设计的好处是,对于开发者:避免重复造轮子,聚焦业务逻辑,对于企业:加速产品迭代,降低维护成本。

Spring框架如何解决循环依赖问题?

循环依赖指的是两个类中的属性相互依赖对方:例如 A 类中有 B 属性,B 类中有 A属性,从而形成了一个依赖闭环,如下图。

null
null

null

循环依赖问题在Spring中主要有三种情况:

  • 第一种:通过构造方法进行依赖注入时产生的循环依赖问题。
  • 第二种:通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
  • 第三种:通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。

只有【第三种方式】的循环依赖问题被 Spring 解决了,其他两种方式在遇到循环依赖问题时,Spring都会产生异常。

Spring 解决单例模式下的setter循环依赖问题的主要方式是通过三级缓存解决循环依赖。

三级缓存指的是 Spring 在创建 Bean 的过程中,通过三级缓存来缓存正在创建的 Bean,以及已经创建完成的 Bean 实例。具体步骤如下:

  • 实例化 Bean:Spring 在实例化 Bean 时,会先创建一个空的 Bean 对象,并将其放入一级缓存中。
  • 属性赋值:Spring 开始对 Bean 进行属性赋值,如果发现循环依赖,会将当前 Bean 对象提前暴露给后续需要依赖的 Bean(通过提前暴露的方式解决循环依赖)。
  • 初始化 Bean:完成属性赋值后,Spring 将 Bean 进行初始化,并将其放入二级缓存中。
  • 注入依赖:Spring 继续对 Bean 进行依赖注入,如果发现循环依赖,会从二级缓存中获取已经完成初始化的 Bean 实例。

通过三级缓存的机制,Spring 能够在处理循环依赖时,确保及时暴露正在创建的 Bean 对象,并能够正确地注入已经初始化的 Bean 实例,从而解决循环依赖问题,保证应用程序的正常运行。

对注解解析的底层实现了解吗?

注解本质上是一种特殊的接口,它继承自 java.lang.annotation.Annotation 接口,所以注解也叫声明式接口,例如,定义一个简单的注解:

代码语言:javascript
代码运行次数:0
复制
public @interface MyAnnotation {
    String value();
}

编译后,Java 编译器会将其转换为一个继承自 Annotation 的接口,并生成相应的字节码文件。

根据注解的作用范围,Java 注解可以分为以下几种类型:

  • 源码级别注解 :仅存在于源码中,编译后不会保留(@Retention(RetentionPolicy.SOURCE))。
  • 类文件级别注解 :保留在 .class 文件中,但运行时不可见(@Retention(RetentionPolicy.CLASS))。
  • 运行时注解 :保留在 .class 文件中,并且可以通过反射在运行时访问(@Retention(RetentionPolicy.RUNTIME))。

只有运行时注解可以通过反射机制进行解析。

当注解被标记为 RUNTIME 时,Java 编译器会在生成的 .class 文件中保存注解信息。这些信息存储在字节码的属性表(Attribute Table)中,具体包括以下内容:

  • RuntimeVisibleAnnotations :存储运行时可见的注解信息。
  • RuntimeInvisibleAnnotations :存储运行时不可见的注解信息。
  • RuntimeVisibleParameterAnnotationsRuntimeInvisibleParameterAnnotations :存储方法参数上的注解信息。

通过工具(如 javap -v)可以查看 .class 文件中的注解信息。

注解的解析主要依赖于 Java 的反射机制。以下是解析注解的基本流程:

1、获取注册信息:通过反射 API 可以获取类、方法、字段等元素上的注解。例如:

代码语言:javascript
代码运行次数:0
复制
Class<?> clazz = MyClass.class;
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
if (annotation != null) {
    System.out.println(annotation.value());
}

2、底层原理:反射机制的核心类是 java.lang.reflect.AnnotatedElement,它是所有可以被注解修饰的元素(如 ClassMethodField 等)的父接口。该接口提供了以下方法:

  • getAnnotation(Class<T> annotationClass):获取指定类型的注解。
  • getAnnotations():获取所有注解。
  • isAnnotationPresent(Class<? extends Annotation> annotationClass):判断是否包含指定注解。

这些方法的底层实现依赖于 JVM 提供的本地方法(Native Method),例如:

  • native Annotation[] getDeclaredAnnotations0(boolean publicOnly);
  • native <A extends Annotation> A getAnnotation(Class<A> annotationClass);

JVM 在加载类时会解析 .class 文件中的注解信息,并将其存储在内存中,供反射机制使用。

因此,注解解析的底层实现主要依赖于 Java 的反射机制和字节码文件的存储。通过 @Retention 元注解可以控制注解的保留策略,当使用 RetentionPolicy.RUNTIME 时,可以在运行时通过反射 API 来解析注解信息。在 JVM 层面,会从字节码文件中读取注解信息,并创建注解的代理对象来获取注解的属性值。

Mysql的索引结构了解吗?

MySQL InnoDB 引擎是用了B+树作为了索引的数据结构。

B+Tree 是一种多叉树,叶子节点才存放数据,非叶子节点只存放索引,而且每个节点里的数据是按主键顺序存放的。每一层父节点的索引值都会出现在下层子节点的索引值中,因此在叶子节点中,包括了所有的索引值信息,并且每一个叶子节点都有两个指针,分别指向下一个叶子节点和上一个叶子节点,形成一个双向链表。

主键索引的 B+Tree 如图所示:

比如,我们执行了下面这条查询语句:

代码语言:javascript
代码运行次数:0
复制
select * from product where id= 5;

这条语句使用了主键索引查询 id 号为 5 的商品。查询过程是这样的,B+Tree 会自顶向下逐层进行查找:

  • 将 5 与根节点的索引数据 (1,10,20) 比较,5 在 1 和 10 之间,所以根据 B+Tree的搜索逻辑,找到第二层的索引数据 (1,4,7);
  • 在第二层的索引数据 (1,4,7)中进行查找,因为 5 在 4 和 7 之间,所以找到第三层的索引数据(4,5,6);
  • 在叶子节点的索引数据(4,5,6)中进行查找,然后我们找到了索引值为 5 的行数据。

数据库的索引和数据都是存储在硬盘的,我们可以把读取一个节点当作一次磁盘 I/O 操作。那么上面的整个查询过程一共经历了 3 个节点,也就是进行了 3 次 I/O 操作。

B+Tree 存储千万级的数据只需要 3-4 层高度就可以满足,这意味着从千万级的表查询目标数据最多需要 3-4 次磁盘 I/O,所以B+Tree 相比于 B 树和二叉树来说,最大的优势在于查询效率很高,因为即使在数据量很大的情况,查询一个数据的磁盘 I/O 依然维持在 3-4次。

介绍一下项目,你负责了哪些部分

按简历所写的内容,重新念了一遍,主要就是后端开发的职责,开发了 xxx、xxx、xx 模块。

说一下项目的亮点和难点

还好机智,提前针对简历上的面试做好了总结,每次面试真的必问,直接按照之前准备的内容流畅回答完了。

反问

问了面试官三个问题:

  • 咱们部门主要做什么业务的?技术栈是怎么样的?
  • 对我这场面试的评价?
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小林coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 美的一面(25分钟)
    • 什么是继承和多态?
    • Java是单继承还是多继承?
    • 有用过泛型吗,讲一下?
    • 什么是反射?有用过吗
    • springboot的常用注解有哪些?
    • springboot相比spring的优势在哪里?
    • Spring框架如何解决循环依赖问题?
    • 对注解解析的底层实现了解吗?
    • Mysql的索引结构了解吗?
    • 介绍一下项目,你负责了哪些部分
    • 说一下项目的亮点和难点
    • 反问
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档