1.JDK、JRE、JVM:
- JDK(Java开发工具包):
- JDK 是用于开发 Java 应用程序的工具包,包含了开发和运行 Java 程序所需的所有工具。
- 它包括编译器(
javac
)、Java 类库、各种开发工具(如调试器)以及 JRE。 - 开发人员通过 JDK 编写和编译 Java 代码。
- JRE(Java运行时环境):
- JRE 是用于运行 Java 应用程序的环境,它不包含开发工具。
- JRE 包含了 JVM 和 Java 类库,提供了 Java 应用程序运行时所需的所有资源。
- 如果只需要运行 Java 程序而不需要开发,安装 JRE 即可。
- JVM(Java虚拟机):
- JVM 是一种虚拟的运行环境,负责执行 Java 字节码。
- 它提供平台无关性,即 Java 程序可以“一次编写,处处运行”(Write Once, Run Anywhere)。
- JVM 执行 Java 字节码,并通过内存管理、垃圾回收等机制来保证程序的稳定运行。
三者关系:
- JDK 包含 JRE,而 JRE 包含 JVM。开发者使用 JDK 来编写和编译代码,编译后的字节码通过 JRE 运行,其中 JVM 负责实际的执行。
┌─ ┌──────────────────────────────────┐
│ │ Compiler, debugger, etc. │
│ └──────────────────────────────────┘
JDK ┌─ ┌──────────────────────────────────┐
│ │ │ │
│ JRE │ JVM + Runtime Library │
│ │ │ │
└─ └─ └──────────────────────────────────┘
2.JAVA类的分类:
- Javabean类: 用来描述一类事物的类。比如 Student
- 测试类: 用来检查其他类是否书写正确,带有main方法的类,是程序的入口
- 工具类:不是用来描述一类事物的,而是包含一组静态方法,这些方法提供通用的、可重用的功能的类。
- 私有化构造方法
- 方法定义为静态
3.PSVM的理解:
public static void main(String[] args){}
- public : 被JVM调用,访问权限要大
- static : 被JVM调用,不用创建对象,直接类名访问。由于main方法是静态的,所以测试类中的其他方法也需要是静态的
- void : 被JVM调用,无返回值
- main : 主入口函数关键字
- String[] args : 过去用于接收键盘输入,现已无用
4.没有指针?基本数据类型怎么通过形参改实参?
通过包装类:
每个基本数据类型都有一个对应的包装类:
基本数据类型 | 对应的包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Java 的基本数据类型和引用类型 – CMD137’s Blog (cmd137blog.top)
5.package 包:
包就是文件夹,便于分类管理类。
导包:import
- 使用同一个包中的类时,无需导包;
- 使用java.lang包中的类时,无需导包;
- 其他情况都需要导包;
- 如果同时使用两个包的同名类,需要用全类名。
6.final:
修饰:
- 方法:不能被重写;
- 类:不能被继承;
- 变量:变成常量:
- 基本类型:储存的数据值不能改变;
- 引用类型:储存的地址值不能改变,对象内部的可以改变。
7.静态代码块:
格式:static{}
特点:随着类的加载而加载,并自动触发,只执行一次
8.构造函数中的this();
在Java中,this()
是一个特殊的方法,称为构造函数引用,它用于在当前类的构造函数中调用另一个构造函数。这通常用于减少代码重复,特别是在有多个构造函数,并且它们之间有很多共同代码的情况下。
使用 this()
时,你需要在构造函数的第一行调用它,并且只能调用一次。this()
后面可以跟括号,里面包含需要传递给另一个构造函数的参数。如果没有参数,就不需要括号。
下面是一个简单的例子来说明 this()
的用法:
public class Person {
private String name;
private int age;
// 无参构造函数
public Person() {
this("Unknown", 0); // 调用带两个参数的构造函数
}
// 带两个参数的构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 带一个参数的构造函数
public Person(String name) {
this(name, 0); // 调用带两个参数的构造函数
}
}
9 sout(对象名称)直接输出对象消息:
Java中,当你在类中对 toString()方法重写以后,System.out.println(对象名)将会调用toString方法并输出。如:
Student.java:
public class Student {
private String name;
private int age;
...
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Test:
Student student =new Student("asd",18);
System.out.println(student);
输出:
Student{name=’asd’, age=18}
10 可变参数
可变参数允许一个方法接收数量可变的参数。这意味着你可以传递任意数量的参数给一个方法,这些参数在方法内部被当作一个数组来处理。
在方法声明中,可变参数通过在参数类型后面加上省略号(…)来表示。
public void printNumbers(int... numbers) {
for (int number : numbers) {
System.out.println(number);
}
}
printNumbers(1); // 只传递一个参数
printNumbers(1, 2); // 传递两个参数
printNumbers(1, 2, 3, 4, 5); // 传递多个参数
11 mysql 自增属性:
自增属性只加不减:
例如15被删去后,新增的为16而非跟上上一个属性值。
当你在服务端的插入语句插入失败时,也会触发“自增”,即使这条记录没有被加入数据表。
12 日志注解(Springboot中)@Slf4j
属于lombak,无需再maven中再次引入。
13 现在配置与代码分离,但是实际在生产环境中不是只有一个jar包吗,那么在生产环境中要怎么修改配置?
有多种方法:
- 外部配置文件
- 在
jar
包同级目录放置配置文件(如application - prod.yml
),通过命令行指定激活该配置文件对应的环境(如java -jar your - application.jar --spring.profiles.active = prod
)来修改配置。
- 在
14 对象属性拷贝 BeanUtils.copyProperties()
使用工具类BeanUtils.copyProperties()将一个对象的属性值拷贝到另一个对象(可以为不同类型)中,前提是目标对象的属性和源对象对应的属性具有相同的名称并且类型兼容。
BeanUtils.copyProperties(target, source);
15 反射:类与其对象的Class
对象的唯一性
class1与class2 一样。
public class Main {
public static void main(String[] args) {
User user = new User();
// 获取 User 类的 Class 对象
Class<?> class1 = User.class;
// 获取 user 实例对应的 Class 对象
Class<?> class2 = user.getClass();
// 比较 class1 和 class2 是否相同
System.out.println(class1 == class2); //ture
}
}
16 Spring 使用 @RequestParam
时自动类型转换:
16.1 基本数据类型及其包装类
Spring 可以将请求参数的字符串值自动转换为 Java 的基本数据类型及其包装类。这是通过内部的 StringToNumberConverterFactory
等转换器实现的。
目标类型 | 示例请求参数值 | 转换后的值 |
---|---|---|
byte / Byte | "12" | (byte) 12 |
short / Short | "123" | (short) 123 |
int / Integer | "1234" | 1234 |
long / Long | "12345" | 12345L |
float / Float | "1.23" | 1.23f |
double / Double | "1.234" | 1.234 |
boolean / Boolean | "true" | true |
char / Character | "a" | 'a' |
16.2 数组和集合类型
集合:对于 List<String>
等集合类型,使用 StringToCollectionConverter
进行转换。
数组:Spring 会使用 StringToArrayConverter
将以逗号分隔的字符串分割成数组元素。
例:
由于是批量删除菜品,前端请求参数:ids string 菜品id,之间用逗号分隔。示例值: 1,2,3
使用@RequestParam 自动类型转换:
@DeleteMapping
@ApiOperation("批量删除菜品")
public Result delete(@RequestParam List<Long> ids){
log.info("批量删除菜品:{}",ids);
dishService.delete(ids);
return Result.success();
}
其他情况
重复参数名
在 HTTP 请求中,如果使用重复的参数名,Spring 也能将这些参数值收集到数组或集合中。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class MultiParamController {
@GetMapping("/multi")
public String getMultiParams(@RequestParam("item") List<String> items) {
return String.join(", ", items);
}
}
对于请求 http://localhost:8080/multi?item=apple&item=banana&item=orange
,Spring 会把这些重复参数的值收集到 items
列表中,最终 items
列表包含 ["apple", "banana", "orange"]
。
自定义分隔符
可以通过自定义类型转换器来实现使用其他分隔符进行分割。例如,使用分号作为分隔符:
收起
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import java.util.Arrays;
import java.util.List;
@Configuration
public class AppConfig {
@Bean
public Converter<String, List<String>> stringToListConverter() {
return new Converter<String, List<String>>() {
@Override
public List<String> convert(String source) {
return Arrays.asList(source.split(";"));
}
};
}
}
然后在控制器中使用:
收起
java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class CustomSeparatorController {
@GetMapping("/custom")
public String getCustomSeparatedValues(@RequestParam("items") List<String> items) {
return String.join(", ", items);
}
}
对于请求 http://localhost:8080/custom?items=apple;banana;orange
,Spring 会根据自定义转换器将字符串按分号分割并赋值给 items
列表。
17 常见对象模型
对象模型 | 全称 | 主要用途 | 特点 | 使用场景 | 使用目的 |
---|---|---|---|---|---|
VO | Value Object(值对象) | 封装一组相关的数据 | 不可变、无行为、值相等 | 领域模型中的值(如货币、日期范围) | 封装值,强调数据的不可变性和值相等性,用于领域模型中的值表示。 |
DTO | Data Transfer Object(数据传输对象) | 跨层数据传输 | 可序列化、无行为、通常可变 | REST API 请求/响应、服务间通信 | 减少网络调用次数,封装数据以便在不同层(如前端与后端)之间高效传输。 |
POJO | Plain Old Java Object(普通Java对象) | 通用的数据封装 | 简单、灵活、不依赖框架 | 任何需要封装数据的场景 | 提供一种简单、通用的方式封装数据,不依赖特定框架或接口。 |
PO | Persistent Object(持久化对象) | 与数据库表映射 | 包含与数据库字段对应的属性 | ORM 框架中的实体类 | 将数据库表映射为对象,便于通过面向对象的方式操作数据库。 |
BO | Business Object(业务对象) | 封装业务逻辑和数据 | 包含数据和行为 | 领域模型中的业务逻辑处理 | 封装业务逻辑和数据,用于处理复杂的业务规则和操作。 |
18 Cookie、Session 和 Token(JWT)
区别
- 存储位置
- Cookie:数据存储在客户端浏览器中。
- Session:数据存储在服务器端。
- Token(JWT):通常存储在客户端,如浏览器的本地存储或内存中。
- 数据传输
- Cookie:每次请求都会将 Cookie 发送到服务器,增加了请求头的大小。
- Session:客户端通过 Session ID 来访问服务器端的 Session 数据,数据传输量相对较小。
- Token(JWT):在每次请求中,需要将 Token 放在请求头中发送到服务器,数据传输量取决于 Token 的大小。
- 有效期
- Cookie:可以设置过期时间,也可以是临时 Cookie,浏览器关闭后即失效。
- Session:通常有一个固定的有效期,服务器会定期清理过期的 Session。
- Token(JWT):可以设置过期时间,过期后需要重新获取 Token。
- 安全性
- Cookie:容易受到 XSS 攻击,若被窃取,攻击者可以伪造用户身份。
- Session:依赖于服务器端的安全机制,如 Session ID 的生成和验证,若服务器被攻击,Session 数据可能泄露。
- Token(JWT):由于其自包含性和签名验证机制,在传输过程中相对安全,但如果密钥泄露,也会存在安全风险。
优缺点
- Cookie
- 优点:实现简单,浏览器原生支持;可以方便地记录用户的偏好和行为;可以设置不同的作用域和过期时间。
- 缺点:存储容量有限,一般不超过 4KB;安全性相对较低,容易被篡改和窃取;会增加每次请求的头部大小,影响性能。
- Session
- 优点:数据存储在服务器端,相对安全;可以存储大量的数据,不受客户端存储限制;可以方便地实现用户的登录状态管理和权限控制。
- 缺点:服务器端需要维护大量的 Session 数据,占用服务器资源;分布式环境下,Session 共享存在一定的复杂性。
- Token(JWT)
- 优点:无状态,服务器不需要存储用户的登录状态,易于扩展;自包含性,携带了用户的相关信息,方便验证和授权;可以在不同的系统之间进行身份验证和授权的共享。
- 缺点:Token 一旦生成,在过期之前无法主动失效,除非采用额外的机制,如黑名单;如果 Token 被窃取,攻击者可以利用其进行非法访问。
19 Spring Boot 与 Spring MVC
Spring Boot 对 Spring MVC 进行了很多优化和简化,以下是对比说明:
依赖管理
- Spring Boot:使用
starter
依赖,如spring - boot - starter - web
,它会自动引入 Spring MVC、Tomcat 等 Web 开发所需的相关依赖,并且通过parent
POM 统一管理依赖版本,避免版本冲突,极大地简化了依赖配置。 - Spring MVC:需要在项目的构建文件(如 Maven 的 pom.xml 或 Gradle 的 build.gradle)中手动添加 Spring MVC 相关的多个依赖,包括
spring - webmvc
、spring - context
等,同时还要明确指定每个依赖的版本号,容易出现版本不兼容的问题。
配置文件
- Spring Boot:配置更加简洁和灵活,默认配置就能够满足大多数场景的需求。可以使用
application.properties
或application.yml
文件进行配置,并且支持配置的外部化,能方便地根据不同环境切换配置。 - Spring MVC:通常需要在
web.xml
文件中配置 Servlet、Filter 等,还需要配置 Spring 的DispatcherServlet
以及相关的上下文配置文件,如spring - servlet.xml
,配置较为繁琐。
服务器启动
- Spring Boot:内置了 Tomcat、Jetty 等服务器,可直接将应用打包成可执行的 JAR 或 WAR 包,通过
java - jar
命令就能启动应用,无需手动部署到外部服务器,大大简化了部署过程。 - Spring MVC:一般需要将应用部署到外部的 Servlet 容器,如 Tomcat、JBoss 等,需要手动将 WAR 包部署到服务器,并进行服务器的配置和启动操作。
自动配置
- Spring Boot:基于条件注解和自动配置类,根据项目的依赖和配置自动配置 Spring MVC 的相关组件,如视图解析器、消息转换器等,开发人员无需手动进行大量的配置。
- Spring MVC:需要开发人员在配置文件中手动配置视图解析器、处理器映射器、处理器适配器等各种组件,以满足不同的业务需求,配置工作量较大。
应用监控
- Spring Boot:通过 Spring Boot Actuator 可以方便地监控应用的各种指标,如健康状况、性能指标、环境变量等,只需引入相关依赖并进行简单配置,就可以通过 HTTP 端点暴露这些信息。
- Spring MVC:需要借助其他第三方监控工具,如 Prometheus、Grafana 等,并且需要手动编写一些代码来暴露应用的监控信息,集成和配置过程相对复杂。