当前位置: 首页 > news >正文

Java面试八股(Java基础,Spring,SpringBoot篇)

java基础

        • JDK,JRE,JVM
        • Java语言的特点
        • Java常见的运行时异常
        • Java为什么要封装​
        • 自增自减
        • +=的隐式转换
        • 移位运算符
          • 1. 左移运算符(`<<`)
          • 2. 带符号右移运算符(`>>`)
          • 3. 无符号右移运算符(`>>>`)
        • 可变参数
        • break,continue,return 的区别及作用?
        • this 关键字有什么作用?
        • 深拷贝
        • 浅拷贝
        • finally 代码块是否一定执行?​​
        • BigDecimal
        • try-with-resources语句
          • 语法:
          • 与传统 `try…finally` 对比
        • `Java`序列化中如果有些字段不想进行序列化,怎么办?
        • 序列化
        • SPI机制
        • ​String的三大技术​
        • String 底层数据结构是什么?
        • String 不可变性如何实现?​​
        • 字符串常量池
        • String s1 = new String("abc");这句话创建了几个字符串对象?
        • intern()方法
        • +号拼接字符串
        • 什么是泛型?
        • `Exception` 和 `Error`的区别
        • 给你个jar包,里面有A类,B类,你要写C类来扩展它们。
        • 基本数据类型和引用数据类型对比
        • Integer和int的区别
        • 如何理解面向对象?
        • 多态存在的三个条件
        • java面向对象,为什么还保留的基本数据类型?
        • 值传递
        • 泛型和通配符
        • 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
        • 对象实体,对象引用的区别
          • 对象实体
          • 对象引用
        • 1. 构造器`Constructor`是否可被`override`?为什么?
        • 2.` String`, `StringBuilder`和 `StringBuffer` 的区别是什么?`String`为什么是不可变的
        • 3. 对象的相等与指向他们的引用相等,两者有什么不同?
        • 4. 重载和重写的区别?
        • 5. 在一个静态方法内调用一个非静态成员为什么是非法的?
        • 6. 简述线程,进程的基本概念。以及他们之间关系?
        • 7. 一个类的构造方法的作用是什么 若一个类没有声明构造方法,该程序能正确执行吗 ?为什么?
        • 9. 成员变量与局部变量的区别有哪些?
        • final、finalize 和 finally 的不同之处?
        • `==`和`equals`的区别
        • Java创建对象的五种方式?
        • 接口和抽象类的区别
        • 抽象类和普通类的区别?
        • throw和throws
        • Static可以修饰哪些?
          • 1.1 成员变量(静态变量)
          • 1.2 成员方法(静态方法)
          • 1.3 静态初始化块
        • 集合体系结构
        • 有一个list,里面的元素是String类型,需要找出里面值为"abc"的并remove掉,该怎么做?
        • ArrayList 的底层数据结构是什么?如何扩容?时间复杂度?
        • ArrarList和LinkedList区别
        • LinkedList 为什么不能实现 RandomAccess 接口?
        • HashMap 的底层实现原理是什么?JDK 1.8 之前和之后的区别?
      • HashCode方法
          • 为什么两个对象的 `hashCode` 值相等,它们也不一定是相等的?
          • 总结:
        • 为什么重写 equals() 时必须重写 hashCode() 方法?
          • 保持哈希契约的一致性
          • 保证集合操作的正确性
        • map的key可以重复吗,能不能为空?
        • 为什么 HashSet 存和取的顺序不一样?
        • HashSet 使用什么机制进行数据去重
        • 集合遍历的几种方式
        • synchronized 和 java.util.concurrent.locks.Lock 的异同?
        • 线程的创建方式
        • 线程有哪些基本状态?
        • 反射是什么?
        • IOC和AOP是通过什么机制来实现的?
        • Spring的核心思想,说说你的理解?
        • Spring事务
        • Spring事务的实现原理​​
        • `BeanFactory` 和 `ApplicationContext`有什么区别?
        • AOP 面向切面编程
        • Spring IOC 是什么?使用场景有哪些?Spring 事务,事务的属性,数据库隔离级别
        • IOC中的bean
        • 什么是Spring的bean?
        • Bean 的生命周期
        • Bean 的配置方式:
        • Bean的作用域
        • 依赖注入的三种方式
        • 单例bean是线程安全的吗
        • 单例bean和非单例的生命周期是否一样?
        • Spring 如何解决循环依赖?
        • Spring MVC 的核心组件有哪些?
        • MVC分层
        • 单点登录
        • cookie和session的区别
        • get和post请求的区别
        • HTTP请求状态码
        • 过滤器和拦截器的区别
        • HTTP方法
        • Spring 设计模式
        • Spring Boot、Spring MVC 和 Spring 有什么区别?
        • SpringMVC 怎么样设定重定向和转发的?
        • 当一个方法向`AJAX`返回特殊对象,比如`Object`,`List`等,需要做什么处理?
        • SpringMVC 用什么对象从后台向前台传递数据的?
        • @Component 和 @Bean 的区别?
        • @Autowired和@Resource注解的区别
        • @Controller和@RestController注解的区别
        • 将一个类声明为 Bean 的注解有哪些?
        • ​Spring Boot自动装配原理​**​
        • 为什么在`web`开发中,声明控制器 `bean` 只能用 `@Controller`?
        • 依赖冲突问题
        • @Transactional注解
        • SpringBoot原理, SpringBoot为什么大大简化了 `Spring` 开发?
        • SpringBoot中哪里用到了反射知识?
        • 配置文件相关
        • Spring Boot 四大核心注解

JDK,JRE,JVM
+-------------------+
|       JDK         |  ← Java 开发工具包,包含开发和运行 Java 程序所需的工具和环境
|  +-------------+  |
|  |     JRE     |  |  ← Java 运行环境,包含JVM和一些类库
|  |  +-------+  |  |
|  |  |  JVM  |  |  |  ← Java 虚拟机,执行 Java 程序的引擎
|  |  +-------+  |  |
|  +-------------+  |
+-------------------+
  • JVM:​是Java程序运行的引擎,负责将字节码转换为机器码并执行,实现Java的跨平台特性

![[Pasted image 20250506140234.png]]

![[Pasted image 20250506140625.png]]

Java在执行流程上兼具“编译”和“解释”两种特性:它首先通过 javac 编译器将源代码编译成与平台无关的字节码(.class 文件),然后由JVM以解释或即时编译(JIT)的方式将字节码转为本地机器码并执行。因此,Java通常被称为“编译-解释型”或“混合型”语言.

栈区: 存储局部变量、方法调用和返回值。每当一个方法被调用时,JVM会为该方法创建一个栈帧(stack frame),并将其压入当前线程的栈中。当方法执行完成后,栈帧会被弹出,释放该方法所占的栈内存。

堆区: 存放new创建的对象和数组, 类的实例变量; JVM不定期检查堆区,如果对象没有引用指向它,内存将被回收.

方法区: 用于存储类信息、常量池、静态变量、方法代码等数据。可以认为方法区是类级别的内存区域,而栈区和堆区存储的是实例级别的数据。

成员变量(字段)指的是在类中、方法外声明的字段,它们包括两大类:实例变量静态变量

Java语言的特点
  • 跨平台: java程序编译后生成和平台无关的字节码文件,由针对不同操作系统的JVM执行,实现一次编译处处运行的跨平台能力

  • 面向对象

  • 健壮性:有垃圾回收和异常处理机制

Java常见的运行时异常
  • 空指针异常(NullPointerException),

  • 数组/字符串下标越界(ArrayIndexOutOfBoundsException & StringIndexOutOfBoundsException)

  • 算术异常(ArithmeticException)

  • 类型转换异常(ClassCastException)

Java为什么要封装​
  • ​隐藏对象的内部实现细节,仅暴露必要接口,实现“高内聚、低耦合”。
  • ​作用​​:保护​数据安全​​:通过private字段限制直接访问,防止非法修改。
    ​ 灵活维护​​:内部逻辑修改不影响外部调用。
自增自减

++-- 运算符可以放在变量之前,也可以放在变量之后:

  • 前缀形式(例如 ++a--a):先自增/自减变量的值,然后再使用该变量,例如,b = ++a 先将 a 增加 1,然后把增加后的值赋给 b
  • 后缀形式(例如 a++a--):先使用变量的当前值,然后再自增/自减变量的值。例如,b = a++ 先将 a 的当前值赋给 b,然后再将 a 增加 1。

![[Pasted image 20250506142657.png]]

  1. Java 里使用 long 类型的数据一定要在数值后面加上 L,否则将作为整型解析。
  2. Java 里使用 float 类型的数据一定要在数值后面加上 f 或 F,否则将无法通过编译。
System.out.println(42 == 42.0);// true

当使用 == 操作符比较 4242.0 时,Java 会进行类型转换。会将 int 类型的 42 自动提升为 double 类型,然后与 42.0 进行比较。

由于 42 转换为double类型后是 42.0,与 42.0 的值相等,所以比较结果为 true

+=的隐式转换
  • 复合赋值(+=)会在赋值时对结果做一次“自动缩小转换
   a += b;  // ⇔ a = (TypeOfA) (a + b);

而普通赋值 a = a + b 则不含此隐式转换,若右侧类型更宽必须显式强转,否则编译报错

移位运算符
1. 左移运算符(<<

作用:将 a 的二进制位向左移动 n 位,右边补 0
效果:相当于 a * 2ⁿ(在不溢出的情况下)。

示例:

int a = 3;        // 二进制:00000011
int b = a << 2;   // 左移两位:00001100,即12
System.out.println(b); // 输出12
2. 带符号右移运算符(>>

作用:将 a 的二进制位向右移动 n 位,左边用原来的符号位(最高位)补齐。
效果:相当于 a / 2ⁿ,并保留符号(正数补0,负数补1)。

示例:

int a = -8;       // 二进制(补码):11111000
int b = a >> 2;   // 右移两位:11111110,即-2
System.out.println(b); // 输出-2
3. 无符号右移运算符(>>>

作用:将 a 的二进制位向右移动 n 位,左边统一补 0(不管正负)。
适用:适用于 intlong 类型,特别是处理位运算时。

示例:

int a = -8;        // 补码:11111000
int b = a >>> 2;   // 无符号右移:00111110(高位补0)
System.out.println(b); // 输出1073741822(一个大正数)
可变参数
  • 可变参数编译后实际会被转换成一个数组
public static void method1(String... args) {//......
}
  • 可变参数只能作为方法的最后一个参数
public static void method2(String arg1, String... args) {//......
}
  • 如果出现方法重载,会优先匹配固定参数的方法:
    ![[Pasted image 20250506190537.png]]

这里输出aaa方法2.

break,continue,return 的区别及作用?
  • break 跳出整个循环,不再执行循环
  • continue 结束当前循环,继续执行下次循环
  • return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)
this 关键字有什么作用?
  • this是指向对象本身的一个指针

  • 用来区分成员变量和局部变量:

    public Student(String name) {// 使用 this 来区分成员变量 name 和局部变量 namethis.name = name;}
  • 可用来传递当前对象,引用当前对象的方法等
深拷贝

深拷贝是把对象及其引用的所有对象都复制一份,新对象和原对象在内存中没有任何关联。修改新对象不会影响原对象,包括对象中引用的其他对象。

浅拷贝

浅拷贝是指对象的字段值的复制,当对象的字段是基本数据类型时,会直接复制数值;当对象的字段是引用类型时,浅拷贝只是复制了引用地址,新对象和原对象仍然引用同一个内存地址

finally 代码块是否一定执行?​​
  • ​无论是否发生异常,finally 代码块都会执行。
  • ​例外情况​​:
    • JVM崩溃
    • 线程被终止
    • 无限循环或死锁导致无法执行到 finally
BigDecimal

BigDecimal对小数进行运算时,不会出现精度损失

使用BigDecimal(String val)构造方法或者 BigDecimal.valueOf(double val) 静态方法来创建对象:

BigDecimal a = new BigDecimal("1.0");

BigDecimal类型的数据进行比较时应使用compareTo()方法,而不是equals(),因为 equals() 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 compareTo() 方法比较的时候会忽略精度。

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.equals(b));//false,不应该使用equals方法

compareTo() 方法可以比较两个 BigDecimal 的值,如果相等就返回0,如果第1个数比第2个数大则返回1,反之返回-1

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.compareTo(b));//0
try-with-resources语句

不用再像try...catch...finally那样手动关闭 (close) 资源,使用前要实现 AutoCloseable 接口.

语法:
try (ResourceType res = new ResourceType()) {// 使用 res 执行操作
} catch (ExceptionType e) {// 异常处理
}
  • try()中声明资源,调用结束后自动关闭
与传统 try…finally 对比
特性try-with-resources传统 try…finally
资源关闭自动调用 close()按逆序关闭支持异常抑制手动调用 close()易漏写或漏捕获
代码简洁性声明式管理,省略多余 finally 代码大量样板 finally 和嵌套 try…catch
异常处理抑制式管理关闭异常,不丢失原抛出异常关闭异常可覆盖原异常,需手动链式处理
Java序列化中如果有些字段不想进行序列化,怎么办?

Java原生的序列化机制中(即实现 Serializable 接口的类),可以使用 transient 关键字来标记不需要序列化的字段。被 transient 修饰的字段在序列化时会被忽略,反序列化后其值会被重置为默认值(如 0null 等)。

import java.io.Serializable;public class User implements Serializable {private String username;private transient String password; // 不会被序列化// 构造方法、getter 和 setter 省略
}
序列化
  • 序列化:将数据结构或对象转换成可以存储或传输的形式,通常是二进制字节流,也可以是 JSON, XML等文本格式
  • 反序列化:将在序列化过程中所生成的数据转换为原始数据结构或者对象的过程
SPI机制
  • 解释: JDK内置的一种 服务提供发现机制,用来启用框架扩展和替换组件,,比如java.sql.Driver接口,不同厂商可以针对同一接口做出不同的实现,比如MySQLPostgreSQL都有不同的实现提供给用户

  • SPI机制可以为某个接口寻找服务实现。其主要思想是将装配的控制权移到程序之外,它的核心思想是解耦

![[Pasted image 20250508111708.png]]

![[Pasted image 20250508083736.png]]

​String的三大技术​
  • ​​压缩​:String 内部用 byte[] 存储,节省空间

  • ​常量池​:避免重复创建字符串对象

  • ​​不可变​:保证线程安全、哈希值稳定

String 底层数据结构是什么?
  • JDK 8 及之前是final char[] , JDK 9 以后是final byte[]
String 不可变性如何实现?​​
  • 存储数据的数组被 final修饰(引用不可变)

  • String没有提供修改数组内容的方法

  • String类本身被final修饰

![[Pasted image 20250507091559.png]]

字符串常量池

![[Pasted image 20250507093543.png]]

String s1 = new String(“abc”);这句话创建了几个字符串对象?

答案:会创建12个字符串对象。

如果字符串常量池中已经有一个,则不再创建新的,直接引用;如果没有,则创建一个。

堆中肯定有一个,因为只要使用了new关键字,肯定会在堆中创建一个

intern()方法

String.intern() 方法可以让 String 对象在运行时加入到JVM的字符串常量池, 并返回常量池中该字符串的唯一实例引用,从而保证具有相同字符序列的字符串仅被存储一次,可减少内存占用和提高比较效率。

原理:

  • 当执行 s.intern() 时,JVM 首先在字符串常量池中查找是否已有与 s.equals(...) 相等的字符串:

  • 若存在,则立即返回该已有实例的引用;

  • 否则,将 s 加入常量池,并返回其自身引用。

示例:

String s1 = new String("Hello");
String s2 = "Hello";
String s3 = s1.intern();System.out.println(s1 == s2);  // false
System.out.println(s2 == s3);  // true

s1 是堆上创建的对象, s2s3 都引用常量池中的 "Hello" 实例,因此 s2 == s3true

+号拼接字符串
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";  // 编译期常量 -> 常量池驻留
String str4 = str1 + str2;    // 运行时新建对象
String str5 = "string";       // 直接字面量 -> 常量池驻留System.out.println(str3 == str4); // false
System.out.println(str3 == str5); // true
System.out.println(str4 == str5); // false
什么是泛型?
  • 一种参数化类型机制, 允许在定义类,接口,方法的时候使用参数, 可以提高代码的复用性、类型安全性(比如集合使用泛型来约束元素类型)

  • 类型擦除 : 代码在编译阶段会移除泛型信息,把泛型信息替换成原始类型(通常是Object)

ExceptionError的区别

ExceptionError 都是 Throwable 类的子类

Throwable
├── Error        // 严重错误(程序无法处理)
└── Exception    // 程序可处理的异常├── RuntimeException  // 非受检异常(Unchecked)└── 其他Exception      // 受检异常(Checked)

​​特征​​​​Error​​​​Exception​​
​​严重性​JVM 无法处理的问题程序可处理的异常
​​是否可恢复​​不可恢复(程序应终止)可恢复(通过捕获处理)
​​是否强制捕获​​非受检(无需 try-catchthrows受检异常需处理,非受检异常(如 RuntimeException)不用处理
​​典型示例​OutOfMemoryErrorStackOverflowErrorIOExceptionNullPointerException
给你个jar包,里面有A类,B类,你要写C类来扩展它们。
  • 已有类 AB,需要编写类 C 来扩展它们的功能。
  • Java 不支持多继承,直接继承 AB 不可行。
  • 最终方案是:
    1. 创建 A 的子类 AChildB 的子类 BChild
    2. C 类中组合 AChildBChild 的实例。

设计原则:

  • ​开闭原则:通过子类扩展(而非修改父类)实现功能增强。

  • ​​组合优于继承:用组合实现多逻辑复用,避免多重继承的复杂性。

  • ​​单一职责原则​​:AChildBChild 各自只负责对父类功能的扩展,C 负责组合逻辑。

// 原有类
public class A {public void log(String message) {System.out.println("Log: " + message);}
}public class B {public boolean validate(String input) {return input != null;}
}// 扩展子类
public class AChild extends A {@Overridepublic void log(String message) {super.log("[Enhanced] " + message); // 增强日志格式}
}public class BChild extends B {@Overridepublic boolean validate(String input) {return super.validate(input) && input.length() > 0; // 增加非空校验}
}// 组合类
public class C {private AChild aChild = new AChild();private BChild bChild = new BChild();public void process(String input) {if (bChild.validate(input)) {aChild.log("Valid input: " + input);} else {aChild.log("Invalid input: " + input);}}
}
基本数据类型和引用数据类型对比
​​维度​​​​基本数据类型​​​​对象类型​​
​存储内容​直接存储值存储引用
​内存位置​值存储在栈内存引用在栈,对象在堆内存
​是否可为 null不能可以
​性能​操作速度快操作较慢
​内存占用​固定大小(如 int 占 4 字节)对象内存包含对象头、字段等,通常更大
​方法调用​按值传递(复制值)按引用传递(复制引用地址)
​泛型支持​不能直接用于泛型(需包装类)可直接用于泛型
Integer和int的区别
  • integer初始值是null, int初始值是0;

  • integer存放在内存, int存放在内存

  • integer是一个对象类型,封装了很多方法,使用的时候更加灵活

如何理解面向对象?
  • 面向过程注重的是解决问题的步骤, 比如洗衣服,打开洗衣机,放入衣服,启动洗衣机,漂洗,烘干

  • 面向对象关注“参与者”(对象),把“人”“洗衣机”“衣服”都看作对象,赋予它们属性与行为,通过对象协作完成业务。

  • 还有个计算圆面积的例子, 如果使用面向过程的方法, 是直接定义半径啥的进行计算, 但是如果使用面向对象的方式, 首先会定义一个圆类, 然后提供一些方法来计算圆面积,

多态存在的三个条件
  • 存在继承关系

  • 子类重写父类的方法

  • 向上转型: 通过父类引用指向子类对象

Animal a = new Dog();  // 向上转型
a.speak();             // 调用 Dog 的 speak()
java面向对象,为什么还保留的基本数据类型?
  • 基本数据类型的性能效率比对象更高,而且占用的内存更小

  • 基本数据类型不需要进行垃圾回收

值传递

Java中将实参传递给方法的方式是值传递

  • 如果参数是基本类型的话,传递的就是基本类型的字面量值的拷贝,会创建副本。
  • 如果参数是引用类型,传递的就是实参所引用的对象在堆中地址值的拷贝,同样也会创建副本。
泛型和通配符
在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
  • 子类构造方法默认会调用父类的无参构造方法,来初始化继承的成员。

  • 如果父类没有无参构造方法,子类必须显式调用父类的有参构造方法。

对象实体,对象引用的区别
对象实体
  • 是类的实例,包含了类定义的属性和方法。
  • 存储在堆内存中。
  • 每次使用 new 创建的对象,都是一个新的实体。
对象引用
  • 是指向对象实体的变量,存储在栈内存中。
  • 保存了对象实体在堆内存中的地址。
  • 多个引用变量可以指向同一个对象实体。

![[Pasted image 20250511203349.png]]

全对.

1. 构造器Constructor是否可被override?为什么?

不能,因为 构造器不是继承自父类的方法, 而且构造器方法名要和类名相同, 如果重写的话,子类的构造方法会和父类相同,所以不满足这个条件, 不属于继承体系的一部分

2. String, StringBuilderStringBuffer 的区别是什么?String为什么是不可变的
  • String不可变, StringBuilder, StringBuffer可变

  • String 天然线程安全, 但是String拼接生成新对象,性能最差

  • StringBuffer 线程安全,性能低,

  • StringBuilder 线程不安全,性能较高

  • 如果是单线程,使用StringBuilder; 多线程环境下使用StringBuffer

3. 对象的相等与指向他们的引用相等,两者有什么不同?
  • 引用相等是指两个引用变量是否指向同一个对象实例,使用 == 进行比较,比较的是两个引用变量的内存地址是否相同.
  • 对象相等是指两个对象的内容是否相同,使用 equals() 方法比较。
4. 重载和重写的区别?
  • 重载发生发生在同一类中(方法与方法之间),方法名相同而参数类型或者参数个数,顺序不同

  • 重写发生在类之间,指的是子类继承父类方法并提供新的实现,方法签名(方法名+参数列表)必须完全相同

5. 在一个静态方法内调用一个非静态成员为什么是非法的?
  • 静态方法是属于类的,不依赖于任何对象实例;

  • 非静态成员属于对象实例,静态方法在非静态成员存在之前就已经存在了

6. 简述线程,进程的基本概念。以及他们之间关系?
  • 程序是指一组有序的指令集合,表示了某个任务的逻辑和操作步骤,并不具备运行能力。
  • 进程是程序的一次执行实例,是资源分配的基本单位,进程之间相互独立
  • 线程是进程中的一个执行单元,是CPU调度的基本单位
  • 一个程序可以对应多个进程(如多次运行),一个进程可以包含多个线程。线程依赖于进程存在,不能独立于进程存在。
7. 一个类的构造方法的作用是什么 若一个类没有声明构造方法,该程序能正确执行吗 ?为什么?
  • 构造方法的作用是在创建对象时初始化对象的状态;

  • 能正常运行,如果一个类没有定义任何构造方法,编译器会自动生成一个无参构造方法;

  • 但是如果类中已经声明了带参数的构造方法,编译器将不会再自动生成默认的无参构造方法。如果还需要使用无参构造方法,必须显式声明;

9. 成员变量与局部变量的区别有哪些?
  • 成员变量定义在类中方法外, 整个类都可以访问,成员变量储存在堆/方法区中,有默认初始化值

  • 局部变量定义在方法/代码块内, 只有在该方法/代码块内才能访问,局部变量储存在中,无默认初始化值

final、finalize 和 finally 的不同之处?
  • final 是一个修饰符,可以修饰变量、方法和类。如果final修饰变量,意味着该变量在初始化后不能被改变。修饰类则该类不能被继承; 修饰一个方法时,表明这个方法不能被重写

  • finalize() 方法用于在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

  • finally 是一个关键字,与 trycatch 一起用于异常的处理。finally 块一定会被执行,无论在 try块中是否有发生异常.但在调用 System.exit()、JVM 崩溃、无限循环或进程被强制杀死等极端情况下,finally 不会执行

==equals的区别
  • ==比较基本数据类型时比较的是内容, 比较引用数据类型比较的是地址值(引用)
  • equals比较的是引用,但是有一些类比如String重写之后就是比较的是内容
Java创建对象的五种方式?

(1)new关键字

(2)反射 Class.newInstanceConstructor.newInstance

try {// 方法1:Class.newInstance()(已过时,推荐Constructor)Class<?> clazz = Class.forName("com.example.Employee");Employee emp1 = (Employee) clazz.newInstance();  // Deprecated in Java 9+// 方法2:Constructor.newInstance()Constructor<Employee> constructor = Employee.class.getDeclaredConstructor();Employee emp2 = constructor.newInstance();
} catch (Exception e) {e.printStackTrace();
}

(3)Clone方法

public class Employee implements Cloneable {private String name;@Overridepublic Employee clone() throws CloneNotSupportedException {return (Employee) super.clone();  // 浅拷贝}
}// 使用克隆创建对象
Employee original = new Employee("Alice");
Employee copy = original.clone();

(4)反序列化

接口和抽象类的区别
  • 类是单继承的(包括抽象类), 但一个类可以实现多个接口,接口是多继承;

  • 成员变量:接口中的成员变量只能是 public static final 类型的,不能被修改且必须有初始值。抽象类的成员变量可以有任何修饰符(private, protected, public),可以在子类中被重新定义或赋值。

  • 抽象类可以有构造方法, 接口没有构造方法

抽象类和普通类的区别?
  • 抽象类用abstract关键字定义,不能被实例化,只能作为其他类的父类。普通类没有abstract关键字,可以实例化。

  • 抽象类可以包含抽象方法和非抽象方法。抽象方法没有方法体,必须由子类实现。普通类只能包含非抽象方法。

abstract class Animal {// 抽象方法public abstract void makeSound();// 非抽象方法public void eat() {System.out.println("This animal is eating.");}
}
throw和throws
  • throw 用于抛出异常
  • throws 用于方法签名中声明该方法可能抛出的异常
Static可以修饰哪些?
1.1 成员变量(静态变量)

使用 static 修饰的字段称为静态变量(或类变量),在类加载时分配内存,所有对象实例共享同一份数据。

public class Example {public static int count = 0;  // 静态变量
}
1.2 成员方法(静态方法)

静态方法,属于类本身,可通过 ClassName.method() 调用,不依赖于具体实例。

public class Example {public static void printHello() {  // 静态方法System.out.println("Hello");}
}
1.3 静态初始化块

静态初始化块在类第一次加载时执行一次,用于对复杂静态变量进行初始化。

public class Example {public static Map<String, String> map;static {map = new HashMap<>();map.put("key", "value");}
}
集合体系结构

![[Pasted image 20250515134740.png]

有一个list,里面的元素是String类型,需要找出里面值为"abc"的并remove掉,该怎么做?
  • 注意不能在增强for循环中直接调用 list.remove()方法,否则会触发 ConcurrentModificationException

    错误示例:

List<String> list = new ArrayList<>(Arrays.asList("abc", "def", "abc"));
for (String s : list) {  if ("abc".equals(s)) {list.remove(s);  // 直接调用 list.remove() ❌}
}
  • 使用迭代器:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String s = iterator.next();if ("abc".equals(s)) {  // 避免空指针异常iterator.remove();  // 安全移除}
}
ArrayList 的底层数据结构是什么?如何扩容?时间复杂度?
  • 底层数据结构是动态数组,支持快速随机访问

  • 扩容机制: 使用无参构造方法进行初始化时,默认容量是0, 第一次添加元素时扩容到 10, 以后如果容量不足,会触发扩容,新容量为旧容量的1.5倍.

  • 如果一次添加多个元素,1.5倍扩容后还放不下,则容量大小为实际元素个数为准

  • 时间复杂度: 尾部插入O(1),中间插入O(n), 随机访问O(1), 删除元素O(n)

ArrarList和LinkedList区别
  • ArrayList底层基于动态数组, 适合读多写少的场景,而且线程不安全

  • LinkedList底层基于链表,适合写多、读操作不依赖随机访问的场景;

  • 对于 删除 和 新增元素 操作谁的性能更好, 要看情况, 若只对单条数据插入或删除,ArrayList的速度更好。如果是批量随机的插入删除数据,LinkedList的速度更好, 因为ArrayList每插入一条数据,要移动插入点及之后的数据。

LinkedList 为什么不能实现 RandomAccess 接口?

RandomAccess 是一个标记接口,用来表明实现该接口的类支持随机访问(即可以通过索引访问元素)。 LinkedList 底层数据结构是链表,内存地址不连续,只能通过指针来定位,不支持随机快速访问,所以不能实现 RandomAccess 接口。

HashMap 的底层实现原理是什么?JDK 1.8 之前和之后的区别?
  • 底层实现:- ​​JDK 1.8 前​是数组 + 链表(拉链法解决哈希冲突)。JDK 1.8 后​是数组 + 链表/红黑树(当链表长度 ≥ 8 时,链表转为红黑树;当树节点数 ≤ 6 时,退化为链表)。

HashCode方法

为什么两个对象的 hashCode 值相等,它们也不一定是相等的?

答: 因为 hashCode() 使用的哈希算法可能会让不同对象产生相同的哈希值

总结:
  • 如果两个对象的hashCode 值不相等,则这两个对象不相等
  • 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。
  • 如果两个对象的hashCode 值相等并且equals()方法也返回 true,这两个对象才相等。
为什么重写 equals() 时必须重写 hashCode() 方法?

有规范指定需要同时重写hashcodeequals是方法,许多容器如HashMapHashSet都依赖于这个规范。

因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。

如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。

保持哈希契约的一致性

Java的规范规定:如果两个对象通过 equals() 方法比较相等,那么它们的 hashCode() 方法必须返回相同的整数。这是为了确保在哈希结构中能够正确地存储和检索对象。如果只重写了 equals() 而没有重写 hashCode(),可能会导致逻辑上相等的对象被分配到不同的哈希桶中,从而无法正确地查找或去重。

保证集合操作的正确性

HashMap 为例,其 put()get() 方法首先会根据键对象的 hashCode() 计算哈希值,然后在对应的桶中通过 equals() 方法查找匹配的键。如果 equals()hashCode() 的实现不一致,可能会导致无法找到已存储的键,造成数据丢失或重复存储

map的key可以重复吗,能不能为空?
  • Map 不允许重复的键(key)
  • 是否允许 null 键取决于具体的 Map 实现;例如HashMapLinkedHashMap 允许一个 null 键,而 HashtableConcurrentHashMapTreeMap 等不允许。
为什么 HashSet 存和取的顺序不一样?

HashSet 基于哈希表 实现的,不保证元素的插入顺序。

HashSet 使用什么机制进行数据去重

使用的是哈希值(hashCode)+ equals 方法来判断元素是否重复。

具体如下:

  1. 当添加元素时,先计算元素的 hashCode() 值;

  2. 然后查找该哈希值所在的桶(bucket);

  3. 在桶中会遍历已有元素,通过 equals() 比较是否有“相等”的元素:

    • 如果有,认为是重复元素,不添加;

    • 如果没有,则加入。

集合遍历的几种方式
  • 增强 for 循环foreach

  • forEach循环

  • 普通for循环

  • 迭代器

  • Stream API遍历

synchronized 和 java.util.concurrent.locks.Lock 的异同?

相同:

  • 都用于解决线程安全问题
  • 都能保证可见性和原子性
  • 都使用互斥机制

不同 :

  • synchronized是一个关键字,Lock 是一个接口

  • Lock的锁控制比synchronized更加灵活,可以更精确的控制锁的范围和粒度

  • synchronized的使用更加简单

线程的创建方式
  • 继承Thread

  • 实现Runnable接口

  • 使用Callable接口和Future接口

  • 使用线程池创建线程

线程有哪些基本状态?
  • 新建(NEW):线程刚创建但hai未启动

  • 可运行(RUNNABLE):调用线程的 start() 方法后,线程进入可运行状态,等待被线程调度器分配CPU时间片执行。

  • 阻塞(BLOCKED):线程在等待获取一个被其他线程持有的监视器锁时进入阻塞状态。

  • 等待(WAITING):线程无限期地等待另一个线程执行特定操作(如 notify()notifyAll())以唤醒它。

  • 计时等待(TIMED_WAITING):线程在指定的时间内等待另一个线程的操作,超过时间后自动唤醒。常见的方法包括 sleep()join(long)wait(long) 等。

  • 终止(TERMINATED):线程执行完毕或因异常退出,进入终止状态。

反射是什么?
  • 反射是指在程序运行时,对于任意一个类,都能获取到这个类的所有属性和方法,对于任意一个对象,都能调用它的任意属性和方法

  • 反射允许程序在运行时动态地获取类的信息并操作类的属性、方法、构造器等

  • 传统方式是 “通过类创建对象”,而反射是 “通过对象反向获取类的信息”

Spring,SpringBoot相关

        • JDK,JRE,JVM
        • Java语言的特点
        • Java常见的运行时异常
        • Java为什么要封装​
        • 自增自减
        • +=的隐式转换
        • 移位运算符
          • 1. 左移运算符(`<<`)
          • 2. 带符号右移运算符(`>>`)
          • 3. 无符号右移运算符(`>>>`)
        • 可变参数
        • break,continue,return 的区别及作用?
        • this 关键字有什么作用?
        • 深拷贝
        • 浅拷贝
        • finally 代码块是否一定执行?​​
        • BigDecimal
        • try-with-resources语句
          • 语法:
          • 与传统 `try…finally` 对比
        • `Java`序列化中如果有些字段不想进行序列化,怎么办?
        • 序列化
        • SPI机制
        • ​String的三大技术​
        • String 底层数据结构是什么?
        • String 不可变性如何实现?​​
        • 字符串常量池
        • String s1 = new String("abc");这句话创建了几个字符串对象?
        • intern()方法
        • +号拼接字符串
        • 什么是泛型?
        • `Exception` 和 `Error`的区别
        • 给你个jar包,里面有A类,B类,你要写C类来扩展它们。
        • 基本数据类型和引用数据类型对比
        • Integer和int的区别
        • 如何理解面向对象?
        • 多态存在的三个条件
        • java面向对象,为什么还保留的基本数据类型?
        • 值传递
        • 泛型和通配符
        • 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
        • 对象实体,对象引用的区别
          • 对象实体
          • 对象引用
        • 1. 构造器`Constructor`是否可被`override`?为什么?
        • 2.` String`, `StringBuilder`和 `StringBuffer` 的区别是什么?`String`为什么是不可变的
        • 3. 对象的相等与指向他们的引用相等,两者有什么不同?
        • 4. 重载和重写的区别?
        • 5. 在一个静态方法内调用一个非静态成员为什么是非法的?
        • 6. 简述线程,进程的基本概念。以及他们之间关系?
        • 7. 一个类的构造方法的作用是什么 若一个类没有声明构造方法,该程序能正确执行吗 ?为什么?
        • 9. 成员变量与局部变量的区别有哪些?
        • final、finalize 和 finally 的不同之处?
        • `==`和`equals`的区别
        • Java创建对象的五种方式?
        • 接口和抽象类的区别
        • 抽象类和普通类的区别?
        • throw和throws
        • Static可以修饰哪些?
          • 1.1 成员变量(静态变量)
          • 1.2 成员方法(静态方法)
          • 1.3 静态初始化块
        • 集合体系结构
        • 有一个list,里面的元素是String类型,需要找出里面值为"abc"的并remove掉,该怎么做?
        • ArrayList 的底层数据结构是什么?如何扩容?时间复杂度?
        • ArrarList和LinkedList区别
        • LinkedList 为什么不能实现 RandomAccess 接口?
        • HashMap 的底层实现原理是什么?JDK 1.8 之前和之后的区别?
      • HashCode方法
          • 为什么两个对象的 `hashCode` 值相等,它们也不一定是相等的?
          • 总结:
        • 为什么重写 equals() 时必须重写 hashCode() 方法?
          • 保持哈希契约的一致性
          • 保证集合操作的正确性
        • map的key可以重复吗,能不能为空?
        • 为什么 HashSet 存和取的顺序不一样?
        • HashSet 使用什么机制进行数据去重
        • 集合遍历的几种方式
        • synchronized 和 java.util.concurrent.locks.Lock 的异同?
        • 线程的创建方式
        • 线程有哪些基本状态?
        • 反射是什么?
        • IOC和AOP是通过什么机制来实现的?
        • Spring的核心思想,说说你的理解?
        • Spring事务
        • Spring事务的实现原理​​
        • `BeanFactory` 和 `ApplicationContext`有什么区别?
        • AOP 面向切面编程
        • Spring IOC 是什么?使用场景有哪些?Spring 事务,事务的属性,数据库隔离级别
        • IOC中的bean
        • 什么是Spring的bean?
        • Bean 的生命周期
        • Bean 的配置方式:
        • Bean的作用域
        • 依赖注入的三种方式
        • 单例bean是线程安全的吗
        • 单例bean和非单例的生命周期是否一样?
        • Spring 如何解决循环依赖?
        • Spring MVC 的核心组件有哪些?
        • MVC分层
        • 单点登录
        • cookie和session的区别
        • get和post请求的区别
        • HTTP请求状态码
        • 过滤器和拦截器的区别
        • HTTP方法
        • Spring 设计模式
        • Spring Boot、Spring MVC 和 Spring 有什么区别?
        • SpringMVC 怎么样设定重定向和转发的?
        • 当一个方法向`AJAX`返回特殊对象,比如`Object`,`List`等,需要做什么处理?
        • SpringMVC 用什么对象从后台向前台传递数据的?
        • @Component 和 @Bean 的区别?
        • @Autowired和@Resource注解的区别
        • @Controller和@RestController注解的区别
        • 将一个类声明为 Bean 的注解有哪些?
        • ​Spring Boot自动装配原理​**​
        • 为什么在`web`开发中,声明控制器 `bean` 只能用 `@Controller`?
        • 依赖冲突问题
        • @Transactional注解
        • SpringBoot原理, SpringBoot为什么大大简化了 `Spring` 开发?
        • SpringBoot中哪里用到了反射知识?
        • 配置文件相关
        • Spring Boot 四大核心注解

IOC和AOP是通过什么机制来实现的?
  • IOC通过反射,依赖注入,工厂模式,容器机制来实现

  • AOP基于动态代理来实现,有JDK动态代理和CGLB动态代理

Spring的核心思想,说说你的理解?

![[Pasted image 20250529104755.png]]

Spring事务
  • Spring 事务保证一组数据库操作要么全部成功,要么全部失败(原子性)

  • 分为声明式事务和编程式事务,声明式事务通过注解,如 @Transactional 实现。编程式事务通过

TransactionTemplatePlatformTransactionManager 手动控制。

  • 事务属性:
    propagation(传播行为):如 REQUIREDREQUIRES_NEW
    isolation(隔离级别):见下文
    timeout:超时时间
    readOnly:只读事务(可优化性能)
    rollbackFor:哪些异常触发回滚

  • 数据库隔离级别:

隔离级别说明可避免问题
READ UNCOMMITTED读未提交无法避免任何问题
READ COMMITTED读已提交(Oracle 默认)避免脏读
REPEATABLE READ可重复读(MySQL 默认)避免脏读、不可重复读
SERIALIZABLE串行化(最高级别)避免所有并发问题
Spring事务的实现原理​​
  • ​​核心机制​​:通过 AOP 动态代理管理事务。
  • ​流程​:
    1. 使用@Transactional注解标记方法。
    2. 生成代理对象,在方法执行前开启事务(beginTransaction())。
    3. 方法执行成功则提交事务(commit()),失败则回滚(rollback())。
BeanFactoryApplicationContext有什么区别?
  • BeanFactorySpring的基础容器,提供基本的依赖注入功能,采用延迟加载。

  • ApplicationContextBeanFactory的子接口,是更高级的容器,支持国际化、事件发布、AOP等,采用预加载策略。

![[Pasted image 20250513142459.png]]

  • 延迟加载: 真正需要bean时才创建bean实例
AOP 面向切面编程
  • AOP是面向切面编程, 将和业务无关的共性代码逻辑封装起来,减少重复的代码,降低模块之间的耦合度, 使用场景有日志记录权限控制,性能监控

  • AOP的实现原理是动态代理(JDK动态代理,CGLB代理)

  • 切入点:需要织入逻辑(增强功能)的方法。

  • 通知:织入的具体逻辑(增强功能的代码逻辑),如前置、后置、环绕通知。

  • 切面:绑定通知与切入点的关系。

  • 用途:统一日志处理、性能监控、事务管理

  • 好处: 减少代码冗余,提升可维护性。

Spring IOC 是什么?使用场景有哪些?Spring 事务,事务的属性,数据库隔离级别
  • IOC(控制反转) : 对象创建、依赖管理的控制权由程序本身转移到 IOC 容器

  • IOC 的好处 : 解耦合,提高程序可维护性和可测试性

  • 容器的作用是创建 bean 实例并管理 bean 的生命周期,并实现依赖注入

  • DI (依赖注入)是实现 IOC 的一种方式, 就是将依赖对象注入到目标对象中(给对象传递需要使用的其他对象),实现解耦合

  • DI 的实现方式有 setter 注入,构造器注入,字段注入(使用@Autowired注解)

  • DI的使用场景 : 控制对象生命周期,自动注入依赖对象(如 @Autowired), 配置管理(如使用 application.yml@Value 等)

//Setter 注入
public class UserService {private UserRepository userRepository;public void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}
//构造器注入
public class UserService {private final UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
//字段注入
public class UserService {@Autowiredprivate UserRepository userRepository;
}
IOC中的bean
  • IOC容器中,默认bean对象只有一个实例对象(单例模式)。

  • 第三方的 bean 不能通过使用@Autowired,@Componet等方式注入,这时要采用配置类中使用@Bean注解的方式:

@Configuration
public class ExternalServiceConfig {@Beanpublic ExternalService externalService() {// ExternalService 来自第三方库,无法加 @Componentreturn new ExternalService("apiKey",  timeout);}
}
什么是Spring的bean?
  • SpringBean,是由 Spring 容器“产生"并管理”的Java对象,bean 的创建、配置以及生命周期都由容器负责
Bean 的生命周期
  1. Bean实例化:通过反射或工厂方法创建Bean实例。

  2. 属性赋值:为Bean设置相关属性和依赖

  3. 初始化:完成Bean的初始化。

  4. 使用:Bean处于活动状态,可以在应用程序中使用。

  5. 销毁:容器关闭时调用销毁方法释放资源

Bean 的配置方式:
  1. XML配置:通过 <beans><bean> 标签定义 Bean

  2. 使用注解(如 @Component@Service@Controller@Repository) 自动扫描注册Bean

  3. 使用 @Configuration 配置类结合 @Bean 注解注册Bean

Bean的作用域
  • Singleton(单例) : 同一 IoC 容器中仅创建一个实例

  • Prototype(原型) : 每次请求(getBean() 或注入)均产生新实例

  • Request : 每个 HTTP 请求对应一个实例

  • Session : 每个 HTTP 会话(Session)对应一个实例

  • Application : 整个 ServletContext (Web 应用) 中仅一个实例

  • WebSocket : 每个 WebSocket 会话对应一个实例

依赖注入的三种方式
  • 构造器注入:通过构造方法注入

  • Setter注入:通过Setter方法注入

  • 字段注入:直接在字段上使用@Autowired注解

单例bean是线程安全的吗

取决于Bean的设计。默认情况下,无状态的单例Bean是线程安全的,而有状态的单例Bean可能存在线程安全问题。​

无状态 : 不能被修改,比如service层的接口

有状态 : 比如成员变量

单例bean和非单例的生命周期是否一样?

不一样, spring只管理单例bean的生命周期,对于非单例的bean,spring创建好之后,就不会管理后续的生命周期了

Spring 如何解决循环依赖?

Spring通过三级缓存来解决循环依赖问题.

Spring创建Bean的流程:

  1. 先去一级缓存中获取,存在就返回。

  2. 如果不存在或者对象正在创建中,去二级缓存中获取。

  3. 如果还没有获取到,就去三级缓存中获取,通过执行 ObjectFactorygetObject() 就可以获取该对象,获取成功之后,从三级缓存移除,并将该对象加入到二级缓存

Spring MVC 的核心组件有哪些?
  • DispatcherServlet:核心的中央处理器,负责接收请求、分发,并给予客户端响应。

  • HandlerMapping:处理器映射器,根据 URL 去匹配查找能处理的 Handler ,并会将请求涉及到的拦截器和 Handler 一起封装。

  • HandlerAdapter:处理器适配器,根据 HandlerMapping 找到的 Handler ,适配执行对应的 Handler

  • Handler:请求处理器,处理实际请求的处理器。

  • ViewResolver:视图解析器,根据 Handler 返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给 DispatcherServlet 响应客户端

MVC分层
  • M是模型,V是视图,C是控制器

  • 视图V为用户提供交互界面

  • 模型M, 代表存储数据的载体或者java pojo, 分为两类:数据承载bean和业务处理bean

  • 数据承载bean如数据传输对象(DTO)

  • 业务处理bean如服务层(Service)

  • 控制器C处理请求

单点登录
  • 身份提供者:集中式认证中心,用户首次登录后颁发 JWT Token

  • 服务提供者:各应用接收并校验 Token,有效则允许访问。

  • Token 传递:可通过HTTP HeaderCookie或重定向参数传递

cookie和session的区别
  • 存储位置:Cookie在客户端(浏览器),Session在服务器端。

  • Cookie占用内存更小,容易暴露,Session存储容量更大,更安全。

get和post请求的区别
  • get 请求参数写在 url 后面,暴露在地址栏,而且url 有长度限制

  • post 请求的参数写在请求体中,没有长度限制

  • 传输敏感数据时推荐使用 post

HTTP请求状态码
  • 200 OK:请求成功。

  • 301 Moved Permanently:资源被永久移动到新 URI,应使用新的 URI

  • 302 Found:资源临时位于不同 URI,应继续使用原 URI 发起请求。

  • 400 Bad Request:请求格式错误。

  • 401 Unauthorized:请求需要身份验证。

  • 403 Forbidden:认证成功但权限不足。

  • 404 Not Found:请求的资源不存在。

  • 405 Method Not Allowed:请求方法不允许。

  • 500 Internal Server Error:服务器内部错误

  • 502 Bad Gateway:网关/代理错误,上游服务器无响应

过滤器和拦截器的区别
  • Filter(过滤器)是 Servlet 规范, Interceptor(拦截器)属于 Spring MVC

  • Filter 可以拦截所有请求,包括静态资源。

  • Interceptor只能拦截 DispatcherServlet 处理的请求(即控制器 Controller请求)。

HTTP方法
请求类型描述
GET获取资源
POST创建新资源
PUT更新现有资源
DELETE删除资源
PATCH部分更新现有资源
Spring 设计模式
  • 代理模式:比如Spring AOP,通过JDK动态代理和CGLIB代理实现

  • 单例模式:Spring 默认将每个Bean定义作为单例管理,一个容器中同一Bean 只产生一个实例,便于集中管理和资源复用。

  • 模板方法模式:比如JmsTemplateJdbcTemplateJpaTemplate ,将固定流程抽象成模板,减少重复代码 。

  • 工厂模式:通过 BeanFactory/FactoryBean 或自定义工厂方法创建对象,客户端不用关心实例化细节,统一通过接口获取 Bean 实例,实现了解耦与扩展。

Spring Boot、Spring MVC 和 Spring 有什么区别?
  • Spring:是核心框架,提供依赖注入(IoC)和面向切面编程(AOP)的基础功能,是其他模块的基石。

  • Spring MVC:是基于SpringWeb框架,专注于MVC模式(模型-视图-控制器),用于处理 HTTP请求和响应,支持URL路由、模板引擎等Web开发功能。

  • Spring Boot:是Spring的快速开发工具,通过自动配置(如内嵌 Tomcat)和 Starter 依赖简化项目搭建

SpringMVC 怎么样设定重定向和转发的?
  • 转发:返回视图名前加 forward:,如 return "forward:/path"

  • 重定向:返回视图名前加 redirect:,如 return "redirect:/path"

当一个方法向AJAX返回特殊对象,比如Object,List等,需要做什么处理?
  • 使用 @ResponseBody 注解将返回值序列化为 JSON/XML,并配合 @RestController 或配置消息转换器(如 Jackson)。示例:
SpringMVC 用什么对象从后台向前台传递数据的?
  • 可以使用 ModelModelMapModelAndView 对象来传递数据
@Component 和 @Bean 的区别?
  • @Component 用于类,@Bean用于方法。

  • @Component标注的类不用编写配置, @Bean定义的Bean需要在配置类中定义方法来返回对象

  • @Bean 注解比 @Component 注解的自定义性更强,而且很多地方只能通过 @Bean 注解来注册 bean。比如注入第三方的类成为bean时,只能通过 @Bean来实现。

@Autowired和@Resource注解的区别
@Autowired@Resource
自动装配机制基于类型进行自动装配。如果多个匹配,需结合 @Qualifier按名称选择。优先按名称装配(指定 name 属性),若找不到对应名称的Bean,则按类型装配。
注入位置可用于字段、构造函数、方法参数等多种场景。常用于字段和方法参数的注入。
灵活性配合@Qualifier可灵活指定注入的 Bean,适合复杂场景。主要通过名称查找,灵活性稍逊于 @Autowired@Qualifier 的组合。
@Controller和@RestController注解的区别
  • @Controller 返回的是视图名称,需要结合模型和视图解析器进行页面渲染。

  • @RestController 将方法返回值直接填入HTTP响应体中,返回的通常是JSON

将一个类声明为 Bean 的注解有哪些?
  • @Component:通用注解,可标注任意类为 Spring 组件。如果一个不知道Bean 属于哪个层,可以使用@Component 注解。

  • @Repository : 持久层 (Dao层),主要用于数据库相关操作。

  • @Service : 服务层,主要涉及一些复杂的逻辑,需要用到Dao层。

  • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面

​Spring Boot自动装配原理​**​

使用 @EnableAutoConfiguration 读取 META-INF/spring.factories 中的配置类,在满足一定条件下将对应 Bean 注入容器,从而实现按需加载的“约定优于配置”

为什么在web开发中,声明控制器 bean 只能用 @Controller?
  • Spring MVC 在启动时会扫描所有被 @Controller@RestController 标注的类,注册为 Handler

  • 如果使用 @Component,虽然这个类被注入了Spring容器,但它不会被当作控制器,不能接收HTTP请求。

依赖冲突问题

@Autowired 注入依赖时,是按类型注入的。如果同一个类型的Bean有多个,Spring不知道注入哪一个,会报错, 解决方式如下:

@Primary: 当存在多个同类型的Bean时,标注了 @PrimaryBean会被默认注入。

@Component
@Primary
public class Apple implements Fruit {//...
}
@Component
public class Banana implements Fruit {//...
}
@Autowired
private Fruit fruit; // 注入 Apple,因为它被标注为 @Primary

@Qualifier: 明确指定要注入哪一个Bean(按名称注入),搭配 @Autowired 使用。

@Component("apple")
public class Apple implements Fruit {//...
}@Component("banana")
public class Banana implements Fruit {//...
}@Autowired
@Qualifier("banana") //bean名字默认为类名首字母小写
private Fruit fruit;  // 注入 banana Bean

@Resource:按名称注入,类似于 @Autowired + @Qualifier。但默认按名称注入,找不到才按类型注入。

@Component("banana")
public class Banana implements Fruit {//...
}@Resource(name = "banana")
private Fruit fruit; // 注入 banana Bean

注意:@Resource 不能和 @Qualifier 一起使用,也不支持 @Primary

@Transactional注解

使用 @Transactional 注解时,只有出现RuntimeException才回滚异常。rollbackFor属性用于控制出现何种异常类型时, 回滚事务。

@Transactional(rollbackFor = Exception.class)
public void someMethod() throws Exception {// 即使是受检异常,也会触发回滚throw new Exception("Checked Exception");
}
SpringBoot原理, SpringBoot为什么大大简化了 Spring 开发?
  • 在于起步依赖和自动配置两方面, 只需引入SpringBoot的起动依赖, 就间接引入了很多其他依赖,web开发所需要的所有的依赖都有了 (得益于Maven的依赖传递)

  • 自动配置就是当容器启动后,一些配置类、bean对象就自动存入到了容器中,不需要手动声明,从而简化了开发,省去了繁琐的配置。

  • 如何实现自动配置? 原理就是在配置类中定义一个@Bean 标识的方法, Spring会自动调用配置类中使用@Bean标识的方法,并把方法的返回值注入到IOC容器中

SpringBoot中哪里用到了反射知识?

依赖注入(DI): Spring Boot使用反射来实现依赖注入.

组件扫描:SpringBoot 通过扫描包路径来发现和注册组件(例如,@Controller@Service@Repository等)。

AOP面向切面: Spring Boot 使用 AOP 实现一些横切关注点,如事务管理、日志记录等。

动态代理: Spring Boot 中的缓存、事务管理等,使用了动态代理。动态代理是通过反射在运行时创建代理对象的一种机制。

配置属性处理: @ConfigurationProperties 注解将外部配置(如 application.yml)映射到pojo中,Spring Boot 通过反射遍历目标类的字段并调用相应的 setter方法,将值注入到对象中

配置文件相关
  • Spring Boot 配置文件优先级: 命令行参数 > 系统属性参数 > properties参数 > yml参数 > yaml参数

  • 加载顺序:YAML(.yml/.yaml)先加载,随后加载 .properties,以便让 .properties 覆盖同名配置

Spring Boot 四大核心注解
  1. @SpringBootApplication
    一个组合注解, 组合了@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan,用于标识主配置类并触发自动配置与组件扫描。

  2. @EnableAutoConfiguration
    根据类路径中的依赖和已声明的 @Bean,自动加载并配置常见组件,其实现依赖于 META-INF/spring.factories 中的自动配置类列表。

  3. @ComponentScan
    指定包路径下的组件(@Component@Service@Repository@Controller 等)自动注册到IoC容器,支持基于注解的组件扫描与发现

  4. @ConfigurationProperties
    将外部化配置(application.properties/.yml)映射到POJO中,支持类型安全的属性绑定和校验,常与 @EnableConfigurationProperties 一同使用。

相关文章:

  • json中对象转字符串和字符串转对象的方法
  • 【Linux系统移植】Cortex-A8 Linux系统移植(超详细)
  • Next.js 布局(Layout)与模板(Template)深度解析:从原理到实战
  • Vue模板语法
  • 大模型应用开发之评估
  • LeetCode 75. 颜色分类 - 双指针法高效解决(Java实现)
  • 【评测】推理和微调 “GTE文本向量-中文-通用领域-base”模型
  • [嵌入式实验]实验二:LED控制
  • 公司数据不泄露,DeepSeek R1本地化部署+web端访问+个人知识库搭建与使用
  • 19、Python字符串高阶实战:转义字符深度解析、高效拼接与输入处理技巧
  • 网络安全的守护者:iVX 如何构建全方位防护体系
  • 【Linux】线程概念
  • 代购系统数据中台搭建指南:3 步实现订单、物流、用户行为的全链路数字化
  • 大模型在老年性白内障预测及诊疗方案中的应用技术方案
  • python模块和包
  • 搭建frp内网穿透
  • 可视化图解算法47:包含min函数的栈
  • 重温经典算法——冒泡排序
  • 【HarmonyOS 5】鸿蒙中的UIAbility详解(二)
  • Python中的sorted()函数:智能排序器详解
  • 惠州网站建设电话/百度网站推广价格查询
  • 男男做爰视频网站/武汉全网营销推广公司
  • 爱站攻略/人民日报最新头条10条
  • 关键词优化收费标准/南昌seo建站
  • 成都网站设计/百度的营销推广
  • wordpress新用户站点/推广专员