Java 核心知识点总结:接口与 ArrayList
本文基于学习文档,系统梳理接口(面向对象高级规范)和ArrayList(常用动态集合)的核心特性、用法及实战案例,同时包含作业题的完整解答,助力夯实 Java 基础进阶技能。
一、接口
1. 核心概念
接口(interface)是面向对象编程的“行为规范”,仅定义对象的行为标准(如方法签名),不包含具体实现。它的核心价值是解耦代码、制定规则、支持多实现,是框架开发和团队协作的重要工具。
2. 基本语法
(1)接口定义
用 interface 关键字声明,内部可包含常量、抽象方法、默认方法等(无构造方法,不能实例化)。
// 订单业务接口:定义订单相关行为规范
public interface OrderService {
// 1. 常量(默认 public static final,可省略)
String SERVICE_NAME = "订单服务";
// 2. 抽象方法(默认 public abstract,可省略)
void createOrder(); // 创建订单
void cancelOrder(String orderId); // 取消订单
String getOrderStatus(String orderId); // 查询订单状态
// 3. 默认方法(有方法体,实现类可直接使用或重写)
default void printServiceInfo() {
System.out.println("当前服务:" + SERVICE_NAME);
}
// 4. 静态方法(接口名调用,实现类不能重写)
static void showTips() {
System.out.println("订单操作请遵守业务规范");
}
}(2)接口实现
用 implements 关键字让类实现接口,必须重写所有抽象方法(否则类需声明为抽象类)。
// 订单服务实现类:实现接口的抽象方法
public class OrderServiceImpl implements OrderService {
// 重写抽象方法:创建订单
@Override
public void createOrder() {
System.out.println("创建订单:生成订单号、扣减库存");
}
// 重写抽象方法:取消订单
@Override
public void cancelOrder(String orderId) {
System.out.println("取消订单:订单号=" + orderId + ",恢复库存");
}
// 重写抽象方法:查询订单状态
@Override
public String getOrderStatus(String orderId) {
return "订单号=" + orderId + ",状态:已支付";
}
// 可选:重写默认方法
@Override
public void printServiceInfo() {
System.out.println("自定义服务信息:订单服务V2.0");
}
}3. 接口的核心特点
| 成员类型 | 规则说明 |
|---|---|
| 成员变量 | 仅允许常量,默认 public static final,初始化后不可修改(如 String VERSION = "1.0")。 |
| 构造方法 | 无,接口不能实例化(需通过实现类创建对象)。 |
| 抽象方法 | 默认 public abstract,无方法体,实现类必须全部重写。 |
| 默认方法 | 用 default 修饰,有方法体,实现类可直接调用或重写(解决接口升级问题)。 |
| 静态方法 | 用 public static 修饰,通过“接口名.方法名”调用(如 OrderService.showTips())。 |
| 私有方法 | 用 private 修饰,仅接口内部调用(抽取默认方法的公共逻辑,避免冗余)。 |
4. 接口的关系规则
- 类与类:继承关系(
extends),仅支持单继承、多层继承(如class A extends B)。 - 类与接口:实现关系(
implements),支持单实现或多实现(如class A implements B, C),也可“继承类+实现接口”(如class A extends Parent implements B, C)。 - 接口与接口:继承关系(
extends),支持单继承或多继承(如interface C extends A, B),实现类需重写所有接口的抽象方法。
5. 接口与抽象类的区别
| 对比维度 | 接口 | 抽象类 |
|---|---|---|
| 成员变量 | 仅常量(public static final) | 可定义变量或常量(无默认修饰符) |
| 成员方法 | 抽象方法、默认方法、静态方法、私有方法 | 抽象方法、普通方法(有实现)、静态方法等 |
| 构造方法 | 无 | 有(用于子类初始化,不能直接实例化) |
| 继承/实现 | 类可多实现,接口可多继承 | 类仅支持单继承 |
| 核心作用 | 制定行为规范,解耦代码(如服务接口) | 封装子类通用逻辑,强制子类实现抽象方法(如模板类) |
6. 接口作业题:用户服务接口设计
题目需求
- 定义
UserService接口,包含方法:void register(String username, String password)(用户注册)、boolean login(String username, String password)(用户登录)、String getUserInfo(String username)(查询用户信息)。 - 定义实现类
UserServiceImpl,重写所有抽象方法(模拟注册存储、登录校验逻辑)。 - 编写测试类,验证注册、登录、查询功能。
解答代码
// 1. 用户服务接口
public interface UserService {
// 注册:参数为用户名和密码
void register(String username, String password);
// 登录:返回是否成功
boolean login(String username, String password);
// 查询用户信息:返回用户详情
String getUserInfo(String username);
}
// 2. 接口实现类(模拟数据存储)
import java.util.HashMap;
import java.util.Map;
public class UserServiceImpl implements UserService {
// 用Map存储用户信息(用户名→密码)
private Map<String, String> userMap = new HashMap<>();
// 重写注册方法
@Override
public void register(String username, String password) {
if (userMap.containsKey(username)) {
System.out.println("注册失败:用户名'" + username + "'已存在");
return;
}
userMap.put(username, password);
System.out.println("注册成功:用户名'" + username + "'");
}
// 重写登录方法
@Override
public boolean login(String username, String password) {
// 校验用户名是否存在 + 密码是否匹配
if (!userMap.containsKey(username)) {
System.out.println("登录失败:用户名不存在");
return false;
}
if (!userMap.get(username).equals(password)) {
System.out.println("登录失败:密码错误");
return false;
}
System.out.println("登录成功:欢迎'" + username + "'");
return true;
}
// 重写查询用户信息方法
@Override
public String getUserInfo(String username) {
if (!userMap.containsKey(username)) {
return "查询失败:用户名'" + username + "'不存在";
}
return "用户信息:用户名=" + username + ",密码(加密前)=" + userMap.get(username);
}
}
// 3. 测试类
public class TestUserService {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
// 测试注册
userService.register("zhangsan", "123456");
userService.register("zhangsan", "654321"); // 重复注册
// 测试登录
userService.login("zhangsan", "123456"); // 正确密码
userService.login("zhangsan", "111111"); // 错误密码
// 测试查询用户信息
System.out.println(userService.getUserInfo("zhangsan"));
System.out.println(userService.getUserInfo("lisi")); // 不存在的用户
}
}运行结果
注册成功:用户名'zhangsan'
注册失败:用户名'zhangsan'已存在
登录成功:欢迎'zhangsan'
登录失败:密码错误
用户信息:用户名=zhangsan,密码(加密前)=123456
查询失败:用户名'lisi'不存在二、ArrayList
1. 核心概念
ArrayList 是 Java 中最常用的动态数组集合,底层基于数组实现,支持大小自动扩容,提供丰富的增删改查方法。适用于“有序、可重复、频繁查询、少量插入删除”的场景(如商品列表、用户列表)。
2. 核心特点
- 长度可变:底层数组满时自动扩容,解决普通数组“长度固定”的问题。
- 有序存储:元素添加顺序与存储顺序一致,支持通过索引快速访问(如
list.get(0))。 - 可重复:允许存储重复元素,包括
null(如list.add(null))。 - 查询高效:通过索引直接访问元素(时间复杂度 O(1)),插入/删除效率低(需移动元素,时间复杂度 O(n))。
3. 构造器与常用方法
(1)构造器
| 构造器 | 说明 |
|---|---|
ArrayList() | 创建初始容量为 0 的空集合,第一次添加元素时扩容为 10(默认无参构造)。 |
ArrayList(int initialCapacity) | 创建指定初始容量的集合(如 new ArrayList<>(20),避免频繁扩容)。 |
(2)常用方法
| 方法名 | 说明 |
|---|---|
boolean add(E e) | 向集合末尾添加元素,返回是否成功(如 list.add("Java"))。 |
void add(int index, E e) | 在指定索引处插入元素,后续元素后移(如 list.add(1, "Python"))。 |
E get(int index) | 返回指定索引处的元素(索引范围:0 ~ size()-1,越界抛异常)。 |
int size() | 返回集合中元素个数(非底层数组容量,如 list.size())。 |
E remove(int index) | 删除指定索引处的元素,返回被删除元素,后续元素前移(如 list.remove(0))。 |
boolean remove(Object o) | 删除第一个匹配的元素,返回是否成功(如 list.remove("Java"))。 |
E set(int index, E e) | 修改指定索引处的元素,返回旧元素(如 list.set(0, "C++"))。 |
boolean contains(Object o) | 判断集合是否包含指定元素(如 list.contains("Java"))。 |
void clear() | 清空集合所有元素(如 list.clear())。 |
4. 长度可变原理(扩容机制)
ArrayList 底层通过“数组+扩容”实现动态长度,核心流程如下:
- 初始状态:无参构造创建的 ArrayList,底层数组初始容量为 0(空数组)。
- 第一次添加元素:底层创建容量为 10 的新数组,将元素存入。
- 触发扩容:当元素个数(
size)等于底层数组容量时,触发扩容。 - 扩容规则:新容量 = 原容量 × 1.5(如 10→15→22→...),通过
Arrays.copyOf()拷贝原数组元素到新数组。 - 后续添加:将新元素存入新数组,原数组被垃圾回收。
5. 常见问题与解决方案
问题 1:遍历删除元素“漏删”
原因:正序遍历删除时,元素前移导致后续元素索引错乱(如删除索引 2 的元素后,原索引 3 的元素变为索引 2,下一轮循环跳过该元素)。
解决方案:① 倒序遍历;② 正序遍历删除后索引自减。
问题 2:频繁扩容影响性能
解决方案:已知元素数量时,使用指定初始容量的构造器(如 new ArrayList<>(100)),减少扩容次数。
6. ArrayList 作业题:学生成绩管理
题目需求
- 定义
Student类,属性:name(姓名)、score(成绩),提供构造器、getter 方法和toString()方法。 - 用 ArrayList 存储 5 个学生对象(成绩随机 60~100)。
- 实现功能:① 查找成绩≥90 的学生;② 删除成绩<60 的学生(本题无,模拟删除逻辑);③ 遍历打印所有学生信息。
解答代码
// 1. 学生实体类
class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
// getter 方法(用于筛选)
public int getScore() {
return score;
}
// 重写 toString(),便于打印
@Override
public String toString() {
return "Student{name='" + name + "', score=" + score + "}";
}
}
// 2. 测试类(成绩管理逻辑)
import java.util.ArrayList;
import java.util.Random;
public class TestStudentScore {
public static void main(String[] args) {
// 初始化 ArrayList,存储 5 个学生
ArrayList<Student> students = new ArrayList<>();
Random random = new Random();
String[] names = {"张三", "李四", "王五", "赵六", "钱七"};
// 添加学生(成绩 60~100 随机)
for (String name : names) {
int score = random.nextInt(41) + 60; // 60~100
students.add(new Student(name, score));
}
// 功能 1:遍历打印所有学生
System.out.println("=== 所有学生信息 ===");
for (Student s : students) {
System.out.println(s);
}
// 功能 2:查找成绩≥90 的学生(优秀学生)
ArrayList<Student> excellentStudents = new ArrayList<>();
for (Student s : students) {
if (s.getScore() >= 90) {
excellentStudents.add(s);
}
}
System.out.println("\n=== 优秀学生(成绩≥90) ===");
if (excellentStudents.isEmpty()) {
System.out.println("无优秀学生");
} else {
for (Student s : excellentStudents) {
System.out.println(s);
}
}
// 功能 3:模拟删除成绩<60 的学生(倒序遍历避免漏删)
for (int i = students.size() - 1; i >= 0; i--) {
if (students.get(i).getScore() < 60) {
students.remove(i);
System.out.println("\n已删除成绩<60 的学生");
}
}
System.out.println("\n=== 删除后剩余学生 ===");
for (Student s : students) {
System.out.println(s);
}
}
}运行结果(示例)
=== 所有学生信息 ===
Student{name='张三', score=85}
Student{name='李四', score=92}
Student{name='王五', score=78}
Student{name='赵六', score=95}
Student{name='钱七', score=65}
=== 优秀学生(成绩≥90) ===
Student{name='李四', score=92}
Student{name='赵六', score=95}
=== 删除后剩余学生 ===
Student{name='张三', score=85}
Student{name='李四', score=92}
Student{name='王五', score=78}
Student{name='赵六', score=95}
Student{name='钱七', score=65}三、总结
- 接口:核心是“规范”,用于定义行为标准,支持多实现和解耦,是服务设计、框架开发的基础。
- ArrayList:核心是“动态存储”,底层数组+自动扩容,适用于有序、可重复、频繁查询的场景,需注意遍历删除的“漏删”问题。
- 实战结合:接口制定业务规则(如
UserService),ArrayList 负责数据存储(如用户列表),两者结合可实现规范、高效的 Java 程序。
掌握这两个知识点,能大幅提升代码的规范性和灵活性,是 Java 基础进阶的关键。