数组是Java中最基础且重要的数据结构之一。想象你有一个书架,数组就像是这个书架上固定数量的格子,每个格子只能放同一类型的书(数据)。与单独声明多个变量相比,数组的优势在于:
声明数组的四种经典方式:
java复制// 方式1:仅声明不初始化(此时数组为null)
int[] arr1;
// 方式2:声明并指定长度
int[] arr2 = new int[10]; // 10个int元素,默认值0
// 方式3:声明并初始化值
int[] arr3 = new int[]{1, 2, 3};
// 方式4:简化初始化(仅限声明时使用)
int[] arr4 = {1, 2, 3};
关键细节:数组长度一旦确定不可改变,这与后续介绍的集合类有本质区别。实际开发中如果遇到需要动态扩容的场景,应该考虑使用ArrayList等集合类。
java复制// 数组克隆示例
String[] original = {"A", "B"};
String[] cloned = original.clone();
System.out.println(original == cloned); // false,是新对象
System.out.println(Arrays.equals(original, cloned)); // true,内容相同
传统for循环:
java复制for(int i=0; i<arr.length; i++) {
System.out.println(arr[i]);
}
增强for循环:
java复制for(int num : arr) {
System.out.println(num);
}
Arrays.toString():
java复制System.out.println(Arrays.toString(arr));
性能提示:在需要高频访问数组元素的场景(如游戏开发、算法实现),传统for循环通常比增强for循环有轻微的性能优势,因为避免了迭代器的创建开销。
二维数组实际上是"数组的数组"。可以把二维数组想象成一个表格,第一个维度代表行,第二个维度代表列。但Java中的二维数组更加灵活——每一行的长度可以不同。
声明方式对比:
java复制// 规则二维数组(3行4列)
int[][] matrix1 = new int[3][4];
// 不规则二维数组
int[][] matrix2 = {
{1, 2},
{3, 4, 5},
{6, 7, 8, 9}
};
// 只指定第一维长度
int[][] matrix3 = new int[3][];
matrix3[0] = new int[2]; // 第一行2列
matrix3[1] = new int[3]; // 第二行3列
嵌套增强for循环是最优雅的遍历方式:
java复制for(int[] row : matrix) {
for(int num : row) {
System.out.print(num + " ");
}
System.out.println();
}
内存布局示意图:
code复制matrix → [row0, row1, row2]
| | |
v v v
[1,2] [3,4,5] [6,7,8,9]
开发经验:在处理数学矩阵运算时,规则的二维数组更高效;而当需要表示不规则数据结构(如树形结构的邻接表)时,不规则数组更有优势。
可变参数本质上是语法糖,编译器会将其转换为数组。以下两种方法签名在字节码层面是等价的:
java复制void printNumbers(int... nums);
void printNumbers(int[] nums);
使用规范:
java复制// 调用示例
sum(1, 2, 3); // 离散值
sum(new int[]{1, 2, 3}); // 数组形式
两种创建方式的本质区别:
java复制String s1 = "abc"; // 字符串常量池
String s2 = new String("abc"); // 堆内存新对象
内存示意图:
code复制常量池:"abc" ← s1
堆内存:新String对象 → "abc" ← s2
重要规律:
substring的陷阱:
java复制String str = "hello";
String sub = str.substring(0,3); // "hel"
注意:在JDK7之前,substring会共享原字符数组,可能导致内存泄漏。现代JDK已修复此问题。
split的正则威力:
java复制String csv = "a,b,c";
String[] parts = csv.split(","); // 简单分割
String log = "2023-01-01 10:00:00 INFO [main]";
String[] logParts = log.split("\\s+"); // 按空白符分割
性能对比实验:
java复制// 测试字符串拼接性能
long start = System.currentTimeMillis();
String result = "";
for(int i=0; i<10000; i++) {
result += i; // 每次循环创建新对象
}
System.out.println("+用时:" + (System.currentTimeMillis()-start));
// 使用StringBuilder优化
start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for(int i=0; i<10000; i++) {
sb.append(i);
}
System.out.println("StringBuilder用时:" + (System.currentTimeMillis()-start));
空白处理三剑客:
java复制String s = " hello ";
s.strip(); // "hello"(前后)
s.stripLeading(); // "hello "(仅前)
s.stripTrailing(); // " hello"(仅后)
空白检查:
java复制"".isEmpty(); // true(长度0)
" ".isBlank(); // true(纯空白)
重复字符串:
java复制"abc".repeat(3); // "abcabcabc"
处理多行字符串的革命性改进:
java复制// 传统方式(需要转义和拼接)
String html = "<html>\n" +
" <body>\n" +
" <p>Hello</p>\n" +
" </body>\n" +
"</html>";
// 文本块方式
String htmlBlock = """
<html>
<body>
<p>Hello</p>
</body>
</html>
""";
文本块处理规则:
量词匹配:
java复制"a".matches("a?"); // true(0或1次)
"aa".matches("a+"); // true(1次以上)
"".matches("a*"); // true(0次以上)
字符类:
java复制"a".matches("[abc]"); // true(a或b或c)
"d".matches("[^abc]"); // true(非abc)
"a".matches("\\w"); // true(字母数字下划线)
邮箱验证:
java复制String emailRegex = "^[\\w.-]+@[\\w.-]+\\.[a-z]{2,6}$";
"test@example.com".matches(emailRegex); // true
密码强度校验:
java复制// 要求:至少8位,包含大小写和数字
String passwordRegex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[\\w]{8,}$";
"Pass1234".matches(passwordRegex); // true
提取日志信息:
java复制String log = "2023-01-01 10:00:00 [ERROR] System failure";
Pattern p = Pattern.compile("\\[(\\w+)\\] (.+)");
Matcher m = p.matcher(log);
if(m.find()) {
String level = m.group(1); // "ERROR"
String message = m.group(2); // "System failure"
}
传统写法与模式匹配对比:
java复制// 传统写法
if(obj instanceof String) {
String s = (String)obj;
System.out.println(s.length());
}
// 模式匹配写法
if(obj instanceof String s) {
System.out.println(s.length());
}
switch表达式中的类型匹配:
java复制String type = switch(obj) {
case String s -> "String长度:" + s.length();
case Integer i -> "Integer值:" + i;
case null -> "空对象";
default -> "其他类型";
};
when子句实现复杂条件:
java复制String grade = switch(score) {
case Integer i when i >= 90 -> "A";
case Integer i when i >= 80 -> "B";
case Integer i when i >= 70 -> "C";
default -> "D";
};
记录类定义:
java复制record Point(int x, int y) {}
模式匹配解构:
java复制String desc = switch(obj) {
case Point(int x, int y) -> String.format("坐标(%d,%d)", x, y);
// 其他case...
};
嵌套模式匹配:
java复制record Box(Object content) {}
String desc = switch(obj) {
case Box(String s) -> "字符串盒子:" + s;
case Box(Integer i) -> "数字盒子:" + i;
case Box(Point p) -> "坐标盒子:" + p;
// ...
};
最佳实践:模式匹配特别适合处理异构数据(如解析JSON、处理AST等场景),可以大幅减少类型检查和强制转换的样板代码。