Java
什么是 JVM?有哪些主要职责?
JVM(Java Virtual Machine,Java 虚拟机)是一个抽象的计算机,它负责加载、验证、解释和执行 Java 字节码。主要职责包括:
- 加载代码: 将编译好的 .class 文件加载到内存中。
- 执行代码: 解释或即时编译(JIT)字节码,并在底层操作系统上运行。
- 内存管理: 包括垃圾回收(GC)来自动回收无用对象,管理堆、方法区等。
这种设计使得 Java 具有平台无关性,只需编写一次代码,便能在不同平台上运行。
JDK、JRE 与 JVM 有什么区别?
- JDK(Java Development Kit): 开发工具包,包含编译器(javac)、调试工具、文档生成器等,同时包含 JRE。
- JRE(Java Runtime Environment): 运行环境,提供 JVM 以及 Java 核心类库,使得用户能够运行 Java 程序。
- JVM: 是 JRE 的核心组件,负责执行 Java 字节码。
简单来说,JDK 用于开发,JRE 用于运行,而 JVM 则是真正执行代码的虚拟机。
什么是面向对象编程(OOP)?Java 如何支持 OOP?
面向对象编程是一种程序设计思想,它通过将数据和行为封装到对象中,来模拟现实世界中的事物。Java 通过以下机制支持 OOP:
- 封装: 将数据(成员变量)和操作数据的方法封装在类中,保护数据安全。
- 继承: 子类可以继承父类的属性和方法,实现代码复用。
- 多态: 同一接口的不同实现可以有不同的行为,实现灵活性。
- 抽象: 通过抽象类和接口定义模板和规范,不关注具体实现细节。
简述封装、继承、多态和抽象这四大特性
- 封装: 隐藏对象内部实现细节,只暴露必要接口。例如,通过 private 访问修饰符保护类的内部数据。
- 继承: 子类继承父类的属性和方法,减少重复代码。如:
class Animal { }
,class Dog extends Animal { }
。 - 多态: 同一个方法调用在不同对象上可能表现出不同行为。如:
Animal a = new Dog(); a.sound();
调用 Dog 类的 sound 方法。 - 抽象: 定义抽象类或接口,只提供方法声明而不实现具体逻辑,由子类实现。例如:
interface Shape { void draw(); }
。
什么是异常处理?如何使用 try-catch-finally?
异常处理用于捕获程序运行时可能出现的错误,并进行处理,防止程序崩溃。
- try 块: 放置可能出现异常的代码。
- catch 块: 捕获并处理 try 块中抛出的特定异常。可以有多个 catch 来分别处理不同异常。
- finally 块: 无论是否发生异常,都会执行的代码(例如关闭资源)。
示例代码:
java
try {
int result = 10 / 0; // 可能抛出异常
} catch (ArithmeticException e) {
System.out.println("除数不能为零!");
} finally {
System.out.println("执行结束。");
}
Java 的集合框架及常见的集合类
集合框架提供了一系列用来存储和操作数据集合的类和接口。主要接口和实现类有:
- List 接口: 有序且可重复。常用实现类:ArrayList、LinkedList。
- Set 接口: 无序且不允许重复。常用实现类:HashSet、TreeSet。
- Map 接口: 存储键值对,键不允许重复。常用实现类:HashMap、TreeMap。
这些集合类提供了丰富的方法来操作数据,如增加、删除、遍历等操作。
什么是 HashMap?它的基本原理是什么?
HashMap 是一种基于哈希表的数据结构,用来存储键值对。
- 原理: 当存入一个键值对时,HashMap 通过键的 hashCode() 计算出一个哈希值,并映射到数组的某个索引位置;如果出现哈希冲突(多个键映射到同一索引),Java 8 以后会用链表或红黑树来存储多个元素。
- 使用场景: 快速查找、插入和删除数据。
接口(interface)和抽象类(abstract class)的区别
- 接口:
- 只能声明常量和抽象方法(Java 8 后允许默认方法和静态方法)。
- 一个类可以实现多个接口。
- 主要用于定义行为规范,不涉及实现细节。
- 抽象类:
- 可以包含抽象方法和具体方法,也可以有成员变量。
- 一个类只能继承一个抽象类。
- 用于提供基本实现和模板,供子类扩展。
选择使用时:如果只需要定义行为而无共享实现,建议用接口;如果有部分实现需要共享,则使用抽象类。
什么是多线程?Java 中如何创建线程?
多线程是指程序同时运行多个线程,以充分利用 CPU 资源,实现并发处理。Java 中常用的创建线程方式有:
- 继承 Thread 类: 重写 run() 方法,并调用 start() 启动线程。java
class MyThread extends Thread { public void run() { System.out.println("线程运行中"); } } // 启动线程 new MyThread().start();
- 实现 Runnable 接口: 实现 run() 方法,并将实例传入 Thread 对象,再调用 start()。java
class MyRunnable implements Runnable { public void run() { System.out.println("线程运行中"); } } // 启动线程 new Thread(new MyRunnable()).start();
这种方式更灵活,因为 Java 支持多重继承接口,但只支持单继承类。
static 和 final 关键字的作用
static 关键字:
- 用于声明类的成员变量或方法,使其归属于类本身,而不是对象。
- 静态成员在内存中只有一份,所有对象共享。
- 常用于工具类(如 Math 类中的方法)和常量定义。
final 关键字:
- 修饰变量:表示常量,一旦赋值就不能改变。
- 修饰方法:表示该方法不能被重写。
- 修饰类:表示该类不能被继承。
这两个关键字有助于提高代码的安全性和稳定性。
Java 的垃圾回收机制(GC)
- 原理:自动回收不再使用的对象内存,开发者无需手动释放。
- 核心步骤:
- 标记:找到所有存活对象。
- 清除:回收未标记的对象内存。
- 常见垃圾回收器:G1、CMS(侧重低延迟)、Parallel GC(侧重吞吐量)。
==
和 equals()
的区别
==
:比较对象内存地址是否相同(基本类型比较值)。equals()
:默认比较地址,可重写(如String
重写后比较内容)。- 示例:java
String a = new String("abc"); String b = new String("abc"); a == b; // false(地址不同) a.equals(b); // true(内容相同)
RESTful API 设计原则
- 资源导向:URL 表示资源(如
/users
)。 - HTTP 方法:GET(查询)、POST(新增)、PUT(更新)、DELETE(删除)。
- 状态码:200(成功)、404(资源不存在)、500(服务器错误)。
- 数据格式:通常用 JSON 传输。
数据库连接池
- 作用:预先创建并管理数据库连接,避免频繁创建/关闭连接。
- 优势:
- 减少连接开销,提升性能。
- 控制连接数,防止资源耗尽。
- 常见实现:HikariCP(Spring Boot 默认)、Druid。