Java零基础入门:数组、集合与字符串核心原理与实战应用
最近在辅导几位零基础同学冲击 Java 实习岗位时,发现很多人在学习初期容易陷入“只学语法,不懂应用”的困境。特别是面对数组、集合、字符串这些看似基础,却在面试和实战中高频出现的核心知识点时,往往知其然不知其所以然。本文是“Java零基础冲实习”系列的第六篇,我们将聚焦于Java 数组、集合框架(Collection)和字符串(String)这三大基石,通过大量可运行的代码示例,带你从零理解其原理、掌握其用法,并梳理出面试中常见的“八股文”考点和避坑指南。学完本文,你将能独立完成数组遍历、集合增删改查、字符串处理等常见任务,为后续学习更复杂的数据结构和框架打下坚实基础。
1. 核心概念:为什么需要数组、集合和字符串?
在编程中,我们经常需要处理一组相同类型的数据,比如一个班级所有学生的成绩、一份购物车里的商品列表、或者一段需要被处理的文本信息。Java 提供了三种核心机制来高效地组织和管理这些数据。
数组(Array)是 Java 中最基本的数据结构,用于存储固定长度的、相同类型的元素序列。它在内存中连续分配,通过下标(索引)访问,效率极高。但它的长度一旦声明就无法改变,这在处理动态数据时显得力不从心。
集合框架(Collection Framework)正是为了解决数组的局限性而诞生的。它提供了一套丰富的接口和类(如 List, Set, Map),用于存储和操作动态长度的对象组。集合框架封装了复杂的数据结构算法(如链表、哈希表、树),让我们可以更专注于业务逻辑。
字符串(String)在 Java 中并非基本数据类型,而是一个不可变(Immutable)的类对象,用于表示文本。几乎所有的 Java 程序都会用到字符串处理,因此深入理解其特性(如不可变性、字符串常量池)对于编写高效、正确的代码至关重要。
简单来说:
- 数组:定长、高效、基础。
- 集合:动态、功能丰富、面向对象。
- 字符串:不可变、使用频繁、有特殊优化。
2. 环境准备与学习目标
学习环境:
- JDK 版本:建议使用 JDK 8 或 JDK 11(LTS长期支持版本)。本文示例代码在这些版本上均可运行。
- IDE(集成开发环境):强烈推荐使用 IntelliJ IDEA Community Edition(免费)或 Eclipse。它们能提供代码提示、自动补全和调试功能,极大提升学习效率。
- 基础要求:已了解 Java 基本语法(变量、循环、条件判断)、类和对象的概念。
本文学习目标:
- 掌握数组的声明、初始化、遍历及基本操作。
- 理解
ArrayList,LinkedList,HashSet,HashMap等核心集合类的特性和使用场景。 - 熟练运用
String类的常用方法进行字符串处理。 - 理解
String的不可变性及其影响。 - 能分析和解决数组越界、空指针等常见异常。
- 了解相关面试高频考点(“八股文”)。
3. Java 数组详解与实战
数组是存储同一类型数据的容器,通过整型索引访问元素,索引从 0 开始。
3.1 数组的声明与初始化
// 1. 声明数组 int[] arr1; // 推荐写法 int arr2[]; // 兼容C风格的写法,不推荐 // 2. 静态初始化:声明的同时赋值 int[] staticArr = {1, 2, 3, 4, 5}; String[] names = {"Alice", "Bob", "Charlie"}; // 3. 动态初始化:先声明长度,后赋值 int[] dynamicArr = new int[5]; // 创建一个长度为5的int数组,默认值全是0 dynamicArr[0] = 10; dynamicArr[1] = 20; // dynamicArr[5] = 30; // 错误!数组索引越界 ArrayIndexOutOfBoundsException // 4. 默认值规则 // 整数类型(byte, short, int, long):0 // 浮点类型(float, double):0.0 // 字符类型(char):'\u0000' (空字符) // 布尔类型(boolean):false // 引用类型(类、数组、String等):null3.2 数组的遍历与操作
遍历数组是基本操作,主要有三种方式:
public class ArrayDemo { public static void main(String[] args) { int[] numbers = {10, 20, 30, 40, 50}; // 方式1:普通for循环(可以获取索引) System.out.println("=== for循环遍历 ==="); for (int i = 0; i < numbers.length; i++) { // 使用 .length 属性获取长度 System.out.println("索引 " + i + " 的值是: " + numbers[i]); } // 方式2:增强for循环(foreach,简洁,但无法获取索引) System.out.println("=== 增强for循环遍历 ==="); for (int num : numbers) { System.out.println("元素值是: " + num); } // 方式3:使用 Arrays.toString() 快速打印数组内容(调试常用) System.out.println("=== Arrays.toString() 输出 ==="); System.out.println(java.util.Arrays.toString(numbers)); // 输出: [10, 20, 30, 40, 50] // 数组拷贝 int[] copiedArr = new int[numbers.length]; // System.arraycopy(源数组, 源起始位置, 目标数组, 目标起始位置, 拷贝长度) System.arraycopy(numbers, 0, copiedArr, 0, numbers.length); System.out.println("拷贝后的数组: " + java.util.Arrays.toString(copiedArr)); // 数组排序 int[] unsorted = {5, 3, 8, 1, 2}; java.util.Arrays.sort(unsorted); // 升序排序 System.out.println("排序后: " + java.util.Arrays.toString(unsorted)); } }3.3 多维数组
二维数组可以理解为“数组的数组”,常用于表示表格、矩阵等数据。
public class TwoDArrayDemo { public static void main(String[] args) { // 声明并初始化一个 2行3列 的二维数组 int[][] matrix = { {1, 2, 3}, {4, 5, 6} }; // 遍历二维数组(嵌套循环) System.out.println("二维数组内容:"); for (int i = 0; i < matrix.length; i++) { // 遍历行 for (int j = 0; j < matrix[i].length; j++) { // 遍历列 System.out.print(matrix[i][j] + "\t"); } System.out.println(); // 换行 } // 动态初始化一个 3x3 的数组 char[][] board = new char[3][3]; // 初始化一个井字棋棋盘 for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[i].length; j++) { board[i][j] = '-'; } } board[1][1] = 'X'; // 在中心放置一个‘X’ // 打印棋盘 for (char[] row : board) { for (char cell : row) { System.out.print(cell + " "); } System.out.println(); } } }4. Java 集合框架核心篇
Java 集合框架主要位于java.util包中,其核心接口关系如下图所示(概念图):
Collection (接口) ├── List (接口) 有序、可重复 │ ├── ArrayList (类) 基于动态数组,查询快,增删慢(尾部增删快) │ └── LinkedList (类) 基于双向链表,增删快,查询慢 └── Set (接口) 无序、不可重复 ├── HashSet (类) 基于哈希表,存取最快,无序 └── TreeSet (类) 基于红黑树,元素有序(按比较器) Map (接口) 键值对映射,键不可重复 ├── HashMap (类) 基于哈希表,存取快,无序(主流选择) └── TreeMap (类) 基于红黑树,键有序4.1 List 接口:ArrayList 与 LinkedList
List的特点是有序(存入顺序)、可重复、有索引。
ArrayList 实战:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ArrayListDemo { public static void main(String[] args) { // 1. 创建ArrayList (推荐使用接口类型声明,提高灵活性) List<String> list = new ArrayList<>(); // 2. 添加元素 list.add("Java"); list.add("Python"); list.add("C++"); list.add("Java"); // 可以重复 System.out.println("初始列表: " + list); // [Java, Python, C++, Java] // 3. 获取元素和大小 System.out.println("第一个元素: " + list.get(0)); System.out.println("列表大小: " + list.size()); // 4. 遍历List System.out.println("=== 遍历方式1: 普通for循环 ==="); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("=== 遍历方式2: 增强for循环 ==="); for (String lang : list) { System.out.println(lang); } System.out.println("=== 遍历方式3: 迭代器Iterator ==="); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); System.out.println(item); // 可以在迭代中使用 iterator.remove() 安全删除当前元素 } // 5. 判断包含与查找索引 System.out.println("是否包含‘Python’: " + list.contains("Python")); // true System.out.println("‘Java’第一次出现的索引: " + list.indexOf("Java")); // 0 System.out.println("‘Java’最后一次出现的索引: " + list.lastIndexOf("Java")); // 3 // 6. 删除元素 list.remove(1); // 删除索引为1的元素(Python) System.out.println("删除索引1后: " + list); // [Java, C++, Java] list.remove("Java"); // 删除第一个匹配的“Java” System.out.println("删除第一个‘Java’后: " + list); // [C++, Java] // 7. 修改元素 list.set(0, "Go"); System.out.println("修改索引0后: " + list); // [Go, Java] // 8. 清空与判空 list.clear(); System.out.println("清空后列表是否为空: " + list.isEmpty()); // true } }LinkedList 实战与对比:LinkedList还实现了Deque接口,可以作为栈或队列使用。
import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args) { LinkedList<Integer> linkedList = new LinkedList<>(); // 作为List使用 linkedList.add(1); linkedList.addFirst(0); // 添加到头部 linkedList.addLast(2); // 添加到尾部 System.out.println("LinkedList: " + linkedList); // [0, 1, 2] // 作为队列Queue使用(FIFO) linkedList.offer(3); // 入队,添加到尾部 System.out.println("队首元素(不删除): " + linkedList.peek()); // 0 System.out.println("出队元素: " + linkedList.poll()); // 0, 移除并返回队首 System.out.println("出队后: " + linkedList); // [1, 2, 3] // 作为栈Stack使用(LIFO) linkedList.push(9); // 压栈,添加到头部 System.out.println("栈顶元素: " + linkedList.peek()); // 9 System.out.println("弹栈: " + linkedList.pop()); // 9, 移除并返回头部 System.out.println("弹栈后: " + linkedList); // [1, 2, 3] } }ArrayList vs LinkedList 如何选择?
- 查询多,增删少:选
ArrayList。get(int index)是 O(1) 常数时间。 - 增删多,查询少:选
LinkedList。在头部或中间插入/删除是 O(1)(如果已知节点位置)。 - 不确定时:优先使用
ArrayList,因为其实现更简单,CPU缓存友好,在大多数场景下综合性能更好。
4.2 Set 接口:HashSet
Set的特点是无序(不保证顺序)、不可重复。最常用的实现是HashSet。
import java.util.HashSet; import java.util.Set; public class HashSetDemo { public static void main(String[] args) { Set<String> set = new HashSet<>(); // 添加元素 set.add("Apple"); set.add("Banana"); set.add("Orange"); set.add("Apple"); // 重复元素,添加失败,但不会报错 System.out.println("Set集合: " + set); // 输出无序,可能是 [Orange, Apple, Banana] // 判断包含 System.out.println("是否包含‘Banana’: " + set.contains("Banana")); // true // 遍历Set (只能用增强for循环或迭代器,因为没有索引) System.out.println("=== 遍历HashSet ==="); for (String fruit : set) { System.out.println(fruit); } // 删除元素 set.remove("Orange"); System.out.println("删除‘Orange’后: " + set); // 另一个重要特性:去重 List<Integer> numbersWithDuplicates = Arrays.asList(1, 2, 2, 3, 4, 4, 5); Set<Integer> uniqueNumbers = new HashSet<>(numbersWithDuplicates); System.out.println("原始列表: " + numbersWithDuplicates); System.out.println("去重后的Set: " + uniqueNumbers); // [1, 2, 3, 4, 5] } }关键点:HashSet的“无序”是指不保证插入顺序,也不保证任何特定顺序。它的底层是HashMap,依靠hashCode()和equals()方法来判断元素是否重复。因此,存入HashSet的自定义对象必须正确重写这两个方法。
4.3 Map 接口:HashMap
Map存储键值对(Key-Value),Key不允许重复,每个Key最多映射一个Value。
import java.util.HashMap; import java.util.Map; public class HashMapDemo { public static void main(String[] args) { // 创建HashMap, Key为String, Value为Integer Map<String, Integer> scoreMap = new HashMap<>(); // 1. 添加/更新元素 put(K key, V value) scoreMap.put("Alice", 95); scoreMap.put("Bob", 87); scoreMap.put("Charlie", 92); scoreMap.put("Alice", 100); // Key已存在,则更新对应的Value System.out.println("成绩Map: " + scoreMap); // {Charlie=92, Bob=87, Alice=100} // 2. 获取元素 get(Object key) Integer aliceScore = scoreMap.get("Alice"); System.out.println("Alice的成绩: " + aliceScore); // 100 System.out.println("不存在的Key: " + scoreMap.get("David")); // null // 3. 判断Key或Value是否存在 System.out.println("是否有Key‘Bob’: " + scoreMap.containsKey("Bob")); // true System.out.println("是否有Value 92: " + scoreMap.containsValue(92)); // true // 4. 遍历HashMap (几种重要方式) System.out.println("=== 遍历方式1: 遍历KeySet ==="); for (String name : scoreMap.keySet()) { Integer score = scoreMap.get(name); System.out.println(name + " => " + score); } System.out.println("=== 遍历方式2: 遍历EntrySet (推荐,效率高) ==="); for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) { System.out.println(entry.getKey() + " => " + entry.getValue()); } System.out.println("=== 遍历方式3: 遍历Values ==="); for (Integer score : scoreMap.values()) { System.out.println("分数: " + score); } // 5. 删除元素 remove(Object key) scoreMap.remove("Charlie"); System.out.println("删除Charlie后: " + scoreMap); // {Bob=87, Alice=100} // 6. 获取大小和判空 System.out.println("Map大小: " + scoreMap.size()); // 2 System.out.println("Map是否为空: " + scoreMap.isEmpty()); // false } }面试高频点:HashMap的工作原理(基于数组+链表/红黑树)、hashCode()和equals()的作用、扩容机制、线程不安全等。Hashtable是线程安全的但性能差,ConcurrentHashMap是线程安全的高性能选择。
5. 字符串(String)深度解析
String可能是 Java 中使用最频繁的类,理解其“不可变性”是关键。
5.1 String 的创建与不可变性
public class StringImmutable { public static void main(String[] args) { // 创建String对象的几种方式 String s1 = "Hello"; // 字面量,存储在字符串常量池 String s2 = new String("Hello"); // 在堆中新建对象 String s3 = "Hello"; String s4 = new String("Hello"); System.out.println(s1 == s2); // false, 比较内存地址 System.out.println(s1 == s3); // true, s1和s3指向常量池的同一个对象 System.out.println(s2 == s4); // false, 两个不同的堆对象 System.out.println(s1.equals(s2)); // true, 比较内容 // 不可变性演示 String str = "Hello"; System.out.println("原始str: " + str + ", hashCode: " + System.identityHashCode(str)); str = str.concat(" World"); // concat() 返回一个新的String对象 System.out.println("操作后str: " + str + ", hashCode: " + System.identityHashCode(str)); // 你会发现hashCode变了,说明str指向了新的对象,原对象"Hello"并未改变。 } }重要结论:任何对String的修改操作(如concat,substring,replace,toLowerCase)都不会改变原字符串,而是返回一个新的String对象。
5.2 String 常用方法实战
public class StringMethodsDemo { public static void main(String[] args) { String text = " Hello, Java World! "; // 1. 长度与判空 System.out.println("长度: " + text.length()); // 21 (包含空格) System.out.println("是否为空: " + text.isEmpty()); // false System.out.println("是否为空白: " + text.isBlank()); // false (JDK 11+) // 2. 去除首尾空格 trim() / strip() (JDK 11+ strip更强大) String trimmed = text.trim(); System.out.println("trim后: \"" + trimmed + "\""); // "Hello, Java World!" System.out.println("strip后: \"" + text.strip() + "\""); // 同上 // 3. 大小写转换 System.out.println("大写: " + text.toUpperCase()); // " HELLO, JAVA WORLD! " System.out.println("小写: " + text.toLowerCase()); // " hello, java world! " // 4. 查找与判断 System.out.println("是否以‘ He’开头: " + text.startsWith(" He")); // true System.out.println("是否以‘! ’结尾: " + text.endsWith("! ")); // true System.out.println("包含‘Java’吗: " + text.contains("Java")); // true System.out.println("‘Java’的索引: " + text.indexOf("Java")); // 8 System.out.println("从末尾查找‘o’: " + text.lastIndexOf('o')); // 15 // 5. 截取与分割 String sub1 = text.substring(8); // 从索引8开始到结尾 System.out.println("substring(8): \"" + sub1 + "\""); // "Java World! " String sub2 = text.substring(8, 12); // [8, 12) System.out.println("substring(8,12): \"" + sub2 + "\""); // "Java" String[] words = trimmed.split(", "); // 按“, ”分割 System.out.println("分割后数组: " + java.util.Arrays.toString(words)); // [Hello, Java World!] // 6. 替换 String replaced = text.replace("Java", "Python"); System.out.println("替换后: \"" + replaced + "\""); // " Hello, Python World! " // 7. 拼接与格式化 String joined = String.join(" - ", "A", "B", "C"); System.out.println("join结果: " + joined); // A - B - C String formatted = String.format("姓名: %s, 年龄: %d", "张三", 25); System.out.println("格式化: " + formatted); // 姓名: 张三, 年龄: 25 } }5.3 StringBuilder 与 StringBuffer
由于String不可变,在需要频繁拼接字符串时(如在循环中),会产生大量临时对象,性能低下。这时应使用StringBuilder(非线程安全)或StringBuffer(线程安全)。
public class StringBuilderDemo { public static void main(String[] args) { // 错误示范:在循环中使用String拼接 String result = ""; for (int i = 0; i < 10000; i++) { result += i; // 每次循环都创建新的String对象,性能极差! } // 正确示范:使用StringBuilder StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb.append(i); // 在同一个对象上修改,高效 } String finalString = sb.toString(); // 最后再转换为String System.out.println("长度: " + finalString.length()); // StringBuilder常用方法 StringBuilder builder = new StringBuilder("Hello"); builder.append(" World"); // 追加 builder.insert(5, ","); // 在索引5处插入 builder.replace(7, 12, "Java"); // 替换[7,12)区间 builder.delete(0, 6); // 删除[0,6)区间 builder.reverse(); // 反转 System.out.println("最终结果: " + builder.toString()); // 输出反转后的字符串 } }选择建议:单线程环境用StringBuilder,多线程环境用StringBuffer(但通常可以通过其他方式同步,StringBuilder更常用)。
6. 综合实战:学生成绩管理系统(控制台版)
我们将运用所学知识,实现一个简单的学生成绩管理系统。
import java.util.*; public class StudentGradeManager { // 使用Map存储学生信息,Key为学号,Value为学生对象 private Map<String, Student> studentMap = new HashMap<>(); // 内部类:学生 static class Student { String id; String name; List<Integer> scores; // 使用List存储多门课成绩 public Student(String id, String name) { this.id = id; this.name = name; this.scores = new ArrayList<>(); } // 添加成绩 public void addScore(int score) { scores.add(score); } // 计算平均分 public double getAverageScore() { if (scores.isEmpty()) { return 0.0; } int sum = 0; for (int score : scores) { sum += score; } return (double) sum / scores.size(); } @Override public String toString() { return String.format("学号: %s, 姓名: %s, 成绩: %s, 平均分: %.2f", id, name, scores, getAverageScore()); } } // 添加学生 public void addStudent(String id, String name) { if (!studentMap.containsKey(id)) { studentMap.put(id, new Student(id, name)); System.out.println("添加成功: " + name); } else { System.out.println("添加失败,学号已存在: " + id); } } // 为学生添加成绩 public void addScoreForStudent(String id, int score) { Student student = studentMap.get(id); if (student != null) { student.addScore(score); System.out.println("为" + student.name + "添加成绩: " + score); } else { System.out.println("学生不存在,学号: " + id); } } // 查询所有学生(按平均分排序) public void displayAllStudentsSorted() { if (studentMap.isEmpty()) { System.out.println("暂无学生信息。"); return; } // 将Map的Value转为List以便排序 List<Student> studentList = new ArrayList<>(studentMap.values()); // 使用Collections.sort和Lambda表达式按平均分降序排序 studentList.sort((s1, s2) -> Double.compare(s2.getAverageScore(), s1.getAverageScore())); System.out.println("=== 学生成绩排名(按平均分降序)==="); for (Student student : studentList) { System.out.println(student); } } // 根据学号查询学生 public void queryStudent(String id) { Student student = studentMap.get(id); if (student != null) { System.out.println("查询结果: " + student); } else { System.out.println("未找到学号为 " + id + " 的学生。"); } } // 主方法,模拟一个简单的控制台交互 public static void main(String[] args) { StudentGradeManager manager = new StudentGradeManager(); Scanner scanner = new Scanner(System.in); // 初始化一些测试数据 manager.addStudent("1001", "张三"); manager.addStudent("1002", "李四"); manager.addStudent("1003", "王五"); manager.addScoreForStudent("1001", 85); manager.addScoreForStudent("1001", 90); manager.addScoreForStudent("1002", 78); manager.addScoreForStudent("1002", 92); manager.addScoreForStudent("1003", 88); System.out.println("\n当前所有学生信息:"); manager.displayAllStudentsSorted(); System.out.println("\n--- 简单查询演示 ---"); manager.queryStudent("1001"); manager.queryStudent("9999"); // 不存在的学号 scanner.close(); } }7. 常见问题与排查思路
在学习和使用数组、集合、字符串时,你一定会遇到以下几个经典错误。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
java.lang.ArrayIndexOutOfBoundsException | 访问数组时,索引值超出了数组长度范围(index < 0或index >= array.length)。 | 1. 检查循环条件,确保索引从0开始,到array.length - 1结束。2. 在访问前,先判断索引是否有效。 |
java.lang.NullPointerException | 1. 调用null引用对象的方法或属性。2. 自动拆箱时包装类为 null。3. 数组元素未初始化就访问。 | 1. 在使用对象前,始终进行非空判断:if (obj != null)。2. 检查集合、数组的初始化代码。 3. 明确区分基本类型和包装类(如 intvsInteger)。 |
集合遍历时修改抛出ConcurrentModificationException | 在使用迭代器或增强for循环遍历ArrayList,HashMap等非线程安全集合时,直接调用集合自身的add,remove方法修改集合。 | 1. 使用迭代器自身的remove()方法进行删除。2. 遍历时,将需要修改的元素暂存到另一个集合,遍历完再统一处理。 3. 使用 CopyOnWriteArrayList等并发集合(高级主题)。 |
String比较使用==导致逻辑错误 | ==比较的是对象内存地址,对于String字面量和new String()创建的对象,地址可能不同。 | 永远使用equals()方法比较字符串内容:str1.equals(str2)。 |
向Set或作为Map的Key存入自定义对象后,无法正确去重或查找 | 自定义类没有正确重写hashCode()和equals()方法。 | 1. 使用 IDE(如 IDEA)自动生成hashCode()和equals()方法。2. 确保两个方法逻辑一致,使用相同的字段进行计算。 |
java.lang.OutOfMemoryError: Java heap space | 1. 内存泄漏(如静态集合持续增长)。 2. 加载了过大的文件到内存(如图片、视频)。 3. 堆内存设置过小。 | 1. 检查代码中是否有集合对象被静态引用,导致无法被GC回收。 2. 处理大文件时使用流(Stream)而非一次性加载。 3. 适当增加JVM堆内存参数(如 -Xmx1024m)。 |
8. 最佳实践与工程建议
集合初始化指定容量对于
ArrayList和HashMap,如果你能预估大致的大小,最好在创建时指定初始容量,避免多次扩容带来的性能损耗。// 预估有100个元素 List<String> list = new ArrayList<>(100); Map<String, Object> map = new HashMap<>(128);使用接口类型声明集合声明时使用
List,Set,Map等接口,而不是具体的实现类(如ArrayList)。这提高了代码的灵活性和可替换性,是面向接口编程的体现。// 推荐 List<String> names = new ArrayList<>(); // 不推荐 ArrayList<String> names = new ArrayList<>();字符串拼接用
StringBuilder在循环内或多次拼接字符串时,务必使用StringBuilder(单线程)或StringBuffer(多线程)。注意
equals和==的区别==:比较基本数据类型的值,或比较对象的内存地址。equals:比较对象的内容是否逻辑相等(默认比较地址,但如String,Integer等类已重写)。黄金法则:比较包装类对象和字符串,一律用equals。
使用
java.util.Arrays和java.util.Collections工具类它们提供了大量静态方法用于操作数组和集合,如排序、搜索、填充、反转等,比自己写循环更安全高效。int[] arr = {3,1,4,1,5}; Arrays.sort(arr); // 排序 int index = Arrays.binarySearch(arr, 4); // 二分查找(必须先排序) List<Integer> list = Arrays.asList(1,2,3); // 数组转List(固定大小) List<String> myList = new ArrayList<>(); Collections.sort(myList); // 排序 Collections.reverse(myList); // 反转 String max = Collections.max(myList); // 最大值为自定义的集合
Key重写hashCode和equals如果你打算将自定义类的对象放入HashSet或作为HashMap的Key,必须正确重写hashCode()和equals()方法。IDEA 的Alt+Insert可以一键生成。生产环境慎用
System.out.println本文示例大量使用System.out.println是为了演示。在实际项目中,应该使用日志框架(如 SLF4J + Logback)来记录信息,便于控制输出级别、格式和目的地。
数组、集合和字符串是 Java 世界的基石,几乎所有的业务逻辑都围绕着它们展开。理解数组的定长与高效,掌握集合框架中ArrayList,LinkedList,HashSet,HashMap这四大金刚的特性和选用场景,牢记String的不可变性并善用StringBuilder,是每一位 Java 开发者入门的基本功。
建议你将本文中的代码全部手动敲一遍,并尝试修改和扩展那个学生成绩管理系统,例如增加按姓名查询、删除学生、将数据保存到文件等功能。在练习中,你会更深刻地体会到不同数据结构的选择对程序的影响。接下来,你可以继续学习异常处理、IO流和面向对象的高级特性,这些内容将帮助你构建更健壮、更复杂的应用程序。如果在实践中遇到问题,多查阅官方文档(Oracle Java Docs)和利用 IDE 的调试功能,这是成长最快的途径。
