面试(二)——流程、方法与数组深入
在上集我们初步了解了 Java 的语法基础与数据类型,这一集将深入讲解程序流程控制、函数(方法)以及数组,帮助你更全面地掌握 Java 语法。
一、程序流程控制
程序流程控制用于控制程序执行的顺序,包括分支判断和循环结构。
(一)if - else 分支判断
根据条件的真假来执行不同的代码块。
- 简单 if:只有
if
部分,当条件为true
时执行if
后的代码块。int score = 85; if (score >= 60) {System.out.println("及格"); }
- if - else 判断:
if
条件为true
时执行if
后的代码块,否则执行else
后的代码块。if (score >= 60) {System.out.println("及格"); } else {System.out.println("不及格"); }
- else if 判断:用于多条件分支判断。
if (score >= 90) {System.out.println("优秀"); } else if (score >= 80) {System.out.println("良好"); } else if (score >= 60) {System.out.println("及格"); } else {System.out.println("不及格"); }
(二)Switch 分支判断
根据表达式的值,匹配对应的 case
分支执行代码,若没有匹配的 case
,则执行 default
分支(default
可选)。switch
表达式的类型可以是 byte
、short
、int
、char
、枚举(JDK 5+)、String
(JDK 7+)。
char grade = 'B';
switch (grade) {case 'A':System.out.println("优秀");break;case 'B':System.out.println("良好");break;case 'C':System.out.println("及格");break;default:System.out.println("不及格");
}
注意:switch
语句的执行逻辑是--根据表达式的值匹配对应的 case
标签,从该标签处开始执行代码,直到遇到 break
语句或 switch
语句结束。如果某个 case
分支中没有 break
,程序会继续执行下一个 case
分支的代码,这种 “跳过后续 case
判断直接执行” 的行为,就是穿透现象。每个 case
分支后通常要加 break
,否则会发生 “穿透” 现象,即执行完当前 case
后,会继续执行下一个 case
的代码,直到遇到 break
或 switch
结束。
eg.没有 break 导致的穿透
int num = 2;
switch (num) {case 1:System.out.println("执行 case 1");case 2:System.out.println("执行 case 2");case 3:System.out.println("执行 case 3");default:System.out.println("执行 default");
}
输出结果:
执行 case 2
执行 case 3
执行 default
(三)循环结构
循环结构用于重复执行一段代码。
- while:先判断条件,若条件为
true
,则执行循环体,否则不执行。int i = 0; while (i < 5) {System.out.println(i);i++; }
- do - while:先执行一次循环体,然后再判断条件,若条件为
true
,继续执行循环体,否则停止。无论条件是否成立,循环体至少执行一次。int j = 0; do {System.out.println(j);j++; } while (j < 5);
- for:格式为
for(初始化表达式; 条件表达式; 更新表达式)
,初始化表达式在循环开始前执行一次;条件表达式每次循环前判断,为true
则执行循环体;更新表达式在每次循环体执行后执行。for (int k = 0; k < 5; k++) {System.out.println(k); }
二、函数(方法)
方法是一段可重复使用的代码块,用于完成特定的功能。
(一)static
static
(静态)是 Java 中用于修饰类成员的关键字,其核心作用是将成员与类本身关联,而非与类的实例(对象)关联。static
可用于修饰以下类型:
(1)修饰成员变量(静态变量)
- 特点:静态变量属于类,所有对象共享同一个值,在类加载时初始化(仅一次),无需创建对象即可访问。
- 使用场景:存储所有对象共享的数据(如常量、计数器等)。
class Student {// 静态变量:所有学生共享的学校名称static String schoolName = "阳光中学";// 实例变量:每个学生的姓名(不共享)String name;
}public class Test {public static void main(String[] args) {// 直接通过类名访问静态变量,无需创建对象System.out.println(Student.schoolName); // 输出:阳光中学Student s1 = new Student();Student s2 = new Student();s1.name = "张三";s2.name = "李四";// 所有对象共享静态变量System.out.println(s1.schoolName); // 输出:阳光中学System.out.println(s2.schoolName); // 输出:阳光中学}
}
(2)修饰成员方法(静态方法)
- 特点:静态方法属于类,可直接通过类名调用,无需创建对象;静态方法中只能访问静态成员(变量 / 方法),不能直接访问非静态成员(因非静态成员依赖对象存在)。
- 使用场景:工具类方法(如
Math.random()
)、不需要访问实例状态的通用功能。
class MathUtil {// 静态方法:计算两数之和public static int add(int a, int b) {return a + b;}
}public class Test {public static void main(String[] args) {// 直接通过类名调用静态方法int result = MathUtil.add(3, 5);System.out.println(result); // 输出:8}
}
(3)修饰代码块(静态代码块)
- 特点:静态代码块在类加载时执行(仅一次),用于初始化静态变量或执行类级别的预处理操作,执行顺序早于构造方法。
- 使用场景:初始化静态资源(如加载配置文件、注册驱动等)。
class Database {static String url;// 静态代码块:初始化数据库连接地址static {url = "jdbc:mysql://localhost:3306/test";System.out.println("静态代码块执行,初始化url");}
}public class Test {public static void main(String[] args) {// 首次访问类时,静态代码块执行System.out.println(Database.url); // 输出:jdbc:mysql://localhost:3306/test}
}
(4)修饰内部类(静态内部类)
- 特点:静态内部类不依赖外部类的实例,可直接创建;静态内部类中可访问外部类的静态成员,但不能直接访问外部类的非静态成员。
- 使用场景:当内部类与外部类的实例无关,仅作为外部类的 “辅助工具类” 时使用。
class Outer {static int outerStaticVar = 10;int outerInstanceVar = 20;// 静态内部类static class Inner {void print() {// 可访问外部类的静态变量System.out.println(outerStaticVar); // 输出:10// 不能直接访问外部类的非静态变量(需通过外部类实例)// System.out.println(outerInstanceVar); // 编译错误}}
}public class Test {public static void main(String[] args) {// 直接创建静态内部类实例,无需外部类对象Outer.Inner inner = new Outer.Inner();inner.print();}
}
(5)static 不适用的场景
- 不能修饰局部变量(方法内的变量);
- 不能修饰构造方法;
- 不能修饰外部类(
static
仅可修饰内部类)。
(二)final
final
final
是修饰符,用于声明 “不可变” 的元素,可修饰类、方法、变量,核心作用是限制修改:
- 修饰类:该类不能被继承。
- 修饰方法:该方法不能被重写。
- 修饰变量:该变量成为常量,只能赋值一次,之后不能再修改。例如
final int MAX_VALUE = 100;
。
注意:
finally
是异常处理结构的一部分,仅用于 try-catch-finally
语句中,作用是定义无论是否发生异常都必须执行的代码块。
核心特点:
- 通常用于释放资源(如关闭文件、断开数据库连接等);
- 即使
try
或catch
中存在return
语句,finally
仍会执行(return
前执行)。
import java.io.FileReader;
import java.io.IOException;public class Test {public static void main(String[] args) {FileReader reader = null;try {reader = new FileReader("test.txt");// 可能发生异常的操作} catch (IOException e) {e.printStackTrace();} finally {// 无论是否发生异常,都必须关闭资源if (reader != null) {try {reader.close();} catch (IOException e) {e.printStackTrace();}}System.out.println("资源已释放");}}
}
(三)访问控制
访问控制修饰符用于控制类、变量、方法的访问权限,包括:
- private:私有的,只能在本类中访问。
- public:公共的,在任何地方都可以访问。
- protected:受保护的,在本类、同包其他类、子类中可以访问。
- default(默认):没有修饰符时的默认访问权限,在本类和同包其他类中可以访问。
三、数组
数组是用于存储多个相同类型数据的容器,数组一旦创建,长度不可改变。
(一)一维数组
一维数组的声明、创建和初始化:
- 声明:
数据类型[] 数组名;
或数据类型 数组名[];
,例如int[] arr;
。 - 创建:
数组名 = new 数据类型[长度];
,例如arr = new int[5];
。 - 初始化:可以在声明时直接初始化,例如
int[] arr = {1, 2, 3, 4, 5};
。
访问一维数组元素通过索引(从 0 开始),例如 arr[0]
表示数组的第一个元素。
(二)二维数组
二维数组可以看作是数组的数组,用于表示表格型数据等。声明、创建和初始化:
// 声明并初始化
int[][] arr2D = {{1, 2}, {3, 4}, {5, 6}};
// 也可以先声明再创建
int[][] arr2D;
arr2D = new int[3][2];
arr2D[0][0] = 1;
arr2D[0][1] = 2;
// 以此类推给其他元素赋值
访问二维数组元素通过两个索引,例如 arr2D[0][0]
表示第一行第一列的元素。
(三)引用数据类型之数组补充
数组本身是对象,数组变量存储的是数组对象在内存中的地址。数组可以存储基本数据类型的元素,也可以存储引用数据类型的元素。例如,创建一个存储字符串的数组:
String[] strArr = {"Java", "Python", "C++"};
for (String str : strArr) {System.out.println(str);
}