Java 入门笔记:核心知识点整理
1. Java 简介
Java 是由 Sun Microsystems 公司于 1995 年推出的一门面向对象程序设计语言。2010 年 Oracle 公司收购 Sun Microsystems,之后由 Oracle 公司负责 Java 的维护和版本升级。Java 也是一个平台,由 Java 虚拟机(JVM)和 Java 应用编程接口(API)构成,提供了独立于操作系统的标准接口,实现了"一次编写,到处运行"的跨平台特性。
2. Java 分类
按应用范围,Java 可分为 3 个体系:
- Java SE(标准版):Java 技术的核心和基础,包含 Java 基础语法、面向对象、常用 API、集合、IO 流、多线程、反射等。
- Java EE(企业版):企业级应用开发解决方案,在 Java SE 基础上构建,提供 Web 服务、组件模型、管理和通信 API,如 Spring、JSP、Servlet、JavaBean 等。
- Java ME(微型版):针对移动设备和嵌入式设备的解决方案,如手机、PDA、电视机顶盒等。(现在基本不再使用)
3. Java 语言的特点
Java 语言的风格很像 C 语言和 C++ 语言,是一种纯粹的面向对象语言,它继承了 C++ 面向对象的技术核心,但抛弃了容易引起错误的指针以及多继承等缺点,增加了垃圾回收机制。主要特点包括:
- 面向对象:支持类、对象、继承、封装、多态、接口、包等,只支持单继承但可通过接口实现多继承。
- 平台无关性:通过 JVM 机制屏蔽具体平台信息,实现"一次编写,到处运行"。
- 简单性:舍弃了操作符重载、多继承等复杂特性,不使用指针,加入垃圾回收机制。
- 解释执行:Java 程序编译成字节码文件,由 JVM 解释执行。
- 多线程:支持多个线程同时执行,并提供多线程同步机制。
- 健壮性:强类型机制、异常处理、垃圾回收机制保证程序健壮性。
- 安全性:提供安全机制防止恶意代码攻击,包含安全管理机制。
4. JDK、JRE、JVM 关系
JDK(Java Development Kit)是 Java 标准开发工具包,包含 Java 程序开发的工具和资源,面向程序员。JRE(Java Runtime Environment)是 Java 运行时环境,包含 JVM 所需要的类库。JVM(Java 虚拟机)用于运行字节码文件,是 Java 实现跨平台的核心。三者关系为:JDK 包含 JRE,JRE 包含 JVM。代码通过 javac 编译器编译成字节码文件,交由 JVM 运行。
5. 变量与数据类型
变量是向内存申请空间用于存储数据的容器。定义格式为:数据类型 变量名 = 变量值。变量命名需符合标识符语法要求,大小写敏感,不能使用保留字,建议采用驼峰命名法。
Java 有 8 种基本数据类型:
| 类型 | 大小 | 范围 | 示例 |
|---|---|---|---|
| byte | 1 字节 | -128~127 | byte b = 10 |
| short | 2 字节 | -32768~32767 | short s = 100 |
| int | 4 字节 | -21亿~21亿 | int age = 20 |
| long | 8 字节 | 较大整数 | long num = 100L |
| float | 4 字节 | 小数 | float price = 3.14f |
| double | 8 字节 | 小数 | double pi = 3.14 |
| char | 2 字节 | 单字符 | 'A' |
| boolean | 1 字节 | true/false | true |
类型转换规则:byte、short、char 进行计算默认结果为 int 类型;小范围类型赋值给大范围类型自动转换,大范围类型赋值给小范围类型需要强制类型转换。
6. 字符串与注释
String 是引用类型,不属于八大基本类型,使用双引号定义。字符串拼接使用 + 号。Java 注释分为单行注释(//)和多行注释(/* */),快捷键为 Ctrl+/ 和 Ctrl+Shift+/。
7. 运算符
Java 中的运算符用于对变量和常量执行运算操作,主要包括以下几类:
7.1 算术运算符
算术运算符包括 +、-、*、/、%(取余)。其中 % 常用于判断奇偶性或倍数关系。
int x = 5, y = 5;
int result = x + y; // 10
result = x - y; // 0
result = x * y; // 25
result = x / y; // 1
result = x % y; // 0(取余数)
System.out.println(result);
7.2 自增自减运算符
++ 和 -- 用于变量自增 1 或自减 1。运算符在变量之前时先自增再参与运算,在变量之后时先参与运算再自增。
int n = 2;
int y = n++; // y=2, n=3(先赋值再自增)
int m = 5;
int z = ++m; // z=6, m=6(先自增再赋值)
System.out.println("y=" + y + ",n=" + n);
System.out.println("z=" + z + ",m=" + m);
7.3 扩展赋值运算符
扩展赋值运算符包括 +=、-=、*=、/=、%=,用于简化赋值操作。
int id = 123;
id -= 10; // 等价于 id = id - 10;
id += 10; // 等价于 id = id + 10;
id *= 10; // 等价于 id = id * 10;
id %= 10; // 等价于 id = id % 10;
7.4 关系运算符
关系运算符包括 >、<、>=、<=、==、!=,用于比较两个数的关系,结果为 boolean 类型(true 或 false)。
boolean boo;
boo = 4 < 3; // false
boo = 3 >= 3; // true
boo = 5 != 9; // true
boo = 21 == 21; // true
System.out.println(boo);
7.5 逻辑运算符与逻辑短路
逻辑运算符 &&(与)和 ||(或)具有短路特性:&& 左侧为 false 时右侧不再执行;|| 左侧为 true 时右侧不再执行。而 & 和 | 没有短路特性。
int i = 100, j = 200;
boolean b1 = (i > j) && (i++ > 100); // 短路,i++ 不执行
System.out.println("b1==" + b1 + ", i==" + i);
boolean b2 = i > 0 || j++ > 200; // 短路,j++ 不执行
System.out.println("b2==" + b2 + ", j==" + j);
7.6 字符串连接运算符
+ 作为连接符时,可以让字符串和任意类型的数据相连接,组成一个新的字符串。
int id = 1001;
int age = 20;
System.out.println("学号:" + id + ",年龄:" + age);
System.out.println("年龄:" + (age + 10));
System.out.println("[学号=" + id + ",年龄=" + age + "]");
7.7 三目运算符
三目运算符格式为 boolean 表达式 ? 表达式1 : 表达式2。如果 boolean 表达式成立,结果为表达式1,否则为表达式2。
int n = 2 < 1 ? 10 : 20; // 结果为 20
System.out.println(n);
// 判断闰年
int year = 2008;
String str = year % 4 == 0 && year % 100 != 0 || year % 400 == 0
? year + "是闰年" : year + "是平年";
System.out.println(str);
8. Scanner 键盘输入
Scanner 是 Java 提供的键盘输入函数,允许用户通过键盘输入值,变量可以接收这些输入的值。
8.1 使用步骤
- 导入 Scanner 类:
import java.util.Scanner; - 创建 Scanner 对象:
Scanner scanner = new Scanner(System.in); - 调用相关方法读取输入。
8.2 常用方法
| 方法名 | 说明 |
|---|---|
nextInt() |
输入整数 |
nextDouble() |
输入小数 |
next() |
输入字符串 |
Scanner scanner = new Scanner(System.in);
// 输入整数
System.out.println("请输入一个整数:");
int a = scanner.nextInt();
// 输入小数
System.out.println("请输入分数:");
double score = scanner.nextDouble();
// 输入字符串
System.out.println("请输入字符串:");
String info = scanner.next();
9. 分支结构
9.1 if 单分支
格式:if (boolean 表达式) { 语句 }。当 boolean 表达式成立时执行 if 语句中的代码,否则不执行。
if (4 < 2) {
System.out.println("我是 if 语句");
}
// 输入成绩判断等级
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个分数:");
double score = scanner.nextDouble();
if (score >= 90) { System.out.println("A"); }
if (score >= 80) { System.out.println("B"); }
if (score >= 70) { System.out.println("C"); }
if (score >= 60) { System.out.println("D"); }
if (score < 60) { System.out.println("不及格"); }
9.2 if-else 分支
格式:if (boolean 表达式) { 语句1 } else { 语句2 }。成立时执行语句1,否则执行语句2。
// 判断两个数的大小关系
int m = 5, n = 5;
if (m > n) {
System.out.println("m > n");
} else if (m < n) {
System.out.println("m < n");
} else {
System.out.println("m == n");
}
// 成绩等级判断(多分支)
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 80) {
System.out.println("良好");
} else if (score >= 70) {
System.out.println("中等");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
9.3 嵌套 if
if 语句内部可以嵌套另一个 if 语句,用于多条件判断。
// 登录验证
int id = 1001, password = 123456;
System.out.println("请输入学号:");
int stu_id = scanner.nextInt();
System.out.println("请输入密码:");
int stu_password = scanner.nextInt();
if (stu_id == id) { // 学号正确
if (stu_password == password) { // 密码正确
System.out.println("登录成功");
} else {
System.out.println("密码错误");
}
} else {
System.out.println("学号错误");
}
9.4 switch 分支
switch-case 是一种特殊的分支结构,通过表达式的值与每个 case 的值进行比较,匹配后执行对应语句。表达式支持 byte、short、int、char、String 类型。
int select = 1;
switch (select) {
case 1:
System.out.println("开始游戏"); break;
case 2:
System.out.println("设置"); break;
case 3:
System.out.println("存档"); break;
case 4:
System.out.println("退出"); break;
default:
System.out.println("输入有误!");
}
// 显示月份对应天数
System.out.println("请输入月份:");
int month = scanner.nextInt();
switch (month) {
case 1: case 3: case 5: case 7:
case 8: case 10: case 12:
System.out.println(month + "有31天"); break;
case 2:
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
System.out.println(month + "有29天");
} else {
System.out.println(month + "有28天");
}
break;
case 4: case 6: case 9: case 11:
System.out.println(month + "有30天"); break;
default:
System.out.println("月份输入错误");
}
9.5 字符串比较
字符串比较使用 equals() 方法,不能直接使用 ==。
String str = "hello";
str.equals("world"); // 比较字符串内容是否相同
// 用户登录示例
String username = "admin";
String password = "123456";
System.out.println("请输入用户名:");
String inputUsername = scanner.next();
System.out.println("请输入密码:");
String inputPassword = scanner.next();
if (username.equals(inputUsername)) {
if (password.equals(inputPassword)) {
System.out.println("登录成功");
} else {
System.out.println("密码错误");
}
} else {
System.out.println("用户名不存在");
}
10. 转义字符
转义字符用于表示不方便直接输出的特殊字符,以反斜杠 \ 开头。常用转义字符如下:
| 转义字符 | 说明 |
|---|---|
\n |
换行符 |
\r |
回车符 |
\t |
制表位,实现对齐功能 |
\\ |
反斜杠 \ |
\' |
单引号 |
\" |
双引号 |
String str = " 你好\r吗 ";
System.out.println(str);
System.out.println("学号\t\t姓名\t年龄\t性别");
System.out.println("2023\07\19");
System.out.println("2023-07-19");
// 姓名:'张三'
String name = "张三";
System.out.println("姓名:'张三'");
System.out.println("姓名:'" + name + "'");
System.out.println("姓名:'" + name + "'");
// 姓名:"张三"
System.out.println("姓名:"" + name + """);
11. Random 随机数
Random 是 java.util 包下提供的工具类,用于生成随机数。
使用格式:
Random random = new Random(); // 定义随机数对象
int rand = random.nextInt(10); // 生成 0-9 之间的随机数
12. 循环结构
循环结构用于重复执行一段代码,Java 提供了 while、do-while 和 for 三种循环语句。
12.1 while 循环
格式:while (boolean 表达式) { 循环体 }。只要 boolean 表达式为 true,循环中的语句就会执行,直到条件不成立时循环结束。
循环三要素:
- 循环初始值:记录循环的次数
- 循环体:要重复执行的代码
- 循环结束条件:循环次数达到要求时结束
// 输出 1~10
int n = 1; // 1. 循环初始值
while (n <= 10) { // 3. 循环结束条件
System.out.println(n); // 2. 循环体
n++;
}
// 计算 1+2+3+...+10
int sum = 0;
int num = 1;
while (num <= 10) {
sum = sum + num;
num++;
}
System.out.println(sum); // 55
// 1-2+3-4+5-6+...+99-100
int sum2 = 0;
int i = 1;
while (i <= 100) {
if (i % 2 == 0) {
sum2 = sum2 - i;
} else {
sum2 = sum2 + i;
}
i++;
}
System.out.println(sum2); // -50
// 1/1 + 1/3 + 1/5 + ... + 1/99
double s = 0;
int j = 1;
while (j <= 50) {
s = s + 1.0 / (2 * j - 1);
j++;
}
System.out.println(s);
12.2 死循环
while(true) 会形成死循环,条件永远成立,循环中的代码会一直执行。
while (true) { // 死循环,条件永远成立
// 代码
}
12.3 break 关键字
break 用于提前结束整个循环。
// 定义随机数,允许用户无限次数猜,直到猜对或输入 -1 终止
Scanner scanner = new Scanner(System.in);
Random random = new Random();
int rand = random.nextInt(50) + 10;
System.out.println("随机数:" + rand);
while (true) {
System.out.println("请输入猜的数字,输入 -1 终止游戏:");
int guess = scanner.nextInt();
if (guess == -1) {
System.out.println("游戏终止!");
break;
}
if (guess > rand) {
System.out.println("猜大了");
} else if (guess < rand) {
System.out.println("猜小了");
} else {
System.out.println("猜对了");
break;
}
}
12.4 continue 关键字
continue 用于结束本次循环,进入下一次循环。
// 不输出 3 的倍数
int m = 1;
while (m <= 10) {
m++;
if (m % 3 == 0) {
continue; // 结束本轮循环,不再执行后面的代码,开始下一轮循环
}
System.out.println(m);
}
break 和 continue 总结:
| 关键字 | 作用 |
|---|---|
break |
结束整个循环 |
continue |
结束本次循环,进入下一次循环 |
12.5 do-while 循环
do-while 和 while 的区别:do-while 先执行后判断,while 先判断后执行。仅仅在第一次条件不满足时,do-while 比 while 多执行一次。如果第一次条件满足,两者执行次数和结果一模一样。
int n = 1;
do {
System.out.println(n);
n++;
} while (n <= 5);
12.6 for 循环
格式:for (表达式1; 表达式2; 表达式3) { 循环体 }
// 输出 1~10
for (int i = 1; i <= 10; i++) {
System.out.println(i);
}
// 死循环写法
for (;;) {
// 死循环
}
12.7 嵌套 for 循环
嵌套循环执行规则:内循环执行结束后,才会执行下一次外循环。
for (int i = 1; i <= 5; i++) { // 外循环
System.out.println("i=" + i);
for (int j = 1; j <= 6; j++) { // 内循环
System.out.println("j=" + j);
}
}
12.8 嵌套循环结束
break 关键字只能结束当前循环,并不能结束多个循环。可以使用标记的方式结束多层循环。
out: // 标记,使用 break + 标记终止多层循环
for (int i = 1; i <= 3; i++) {
System.out.println("i:" + i);
for (int j = 1; j <= 5; j++) {
if (j == 3) {
break out; // 终止外层循环
}
System.out.println("j:" + j);
}
}
12.9 嵌套 for 应用
使用嵌套 for 可以打印相关图形以及遍历复杂的数据。
矩形图形:
for (int i = 1; i <= 5; i++) { // 外循环控制行数
for (int j = 1; j <= 11; j++) { // 内循环控制列数
System.out.print("*");
}
System.out.println();
}
直角三角形:
for (int i = 1; i <= 6; i++) {
for (int j = 1; j <= 2 * i - 1; j++) {
System.out.print("*");
}
System.out.println();
}
九九乘法表:
for (int i = 1; i <= 9; i++) { // 9 行
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
等腰三角形:
Scanner scanner = new Scanner(System.in);
System.out.println("请输入打印行数:");
int line = scanner.nextInt();
for (int i = 1; i <= line; i++) {
for (int j = 1; j <= line - i; j++) { // 打印空格
System.out.print(" ");
}
for (int k = 1; k <= 2 * i - 1; k++) {
System.out.print("*");
}
System.out.println();
}
13. 数组
数组是一种数据结构,用于存储相同类型数据的集合。数组中的元素通过下标(索引)访问,下标从0开始。
13.1 数组定义与初始化
数组定义格式:数据类型[] 数组名 = new 数据类型[长度];
// 定义整型数组,存储3个数据
int[] arr = new int[3];
// 定义char数组
char[] arr2 = new char[10];
// 数组初始化方式一:定义时直接赋值
int[] arr2 = {1, 2, 3, 4, 5};
// 数组初始化方式二:先声明后赋值
int[] arr3;
arr3 = new int[5];
arr3[0] = 2;
// 另一种声明方式
int arr4[];
arr4 = new int[]{1, 3, 5, 7, 9};
13.2 数组在内存中的存储
数组元素是顺序排列的,在内存中的地址是连续的。通过下标访问数组元素:数组名[下标],下标范围从0到长度-1。
package day04;
public class BasicArr {
public static void main(String[] args) {
int[] arr = new int[3]; // 定义一个长度为3的整型数组
System.out.println(arr); // 打印数组地址
// 通过下标访问数组
System.out.println(arr[2]); // 访问第三个元素
// 给数组元素赋值
arr[0] = 5; // 给第一个元素赋值为5
arr[1] = 3;
arr[2] = 10;
// arr[3] = 6; // 错误:不能超过下标的最大范围(长度-1)
System.out.println(arr[2]); // 输出:10
}
}
13.3 数组长度与遍历
数组长度通过length属性获取,遍历数组可以使用普通for循环或增强for循环。
int[] arr = {10, 4, 2, 6, 8, 9, 3, 1};
// 获取数组长度
System.out.println(arr.length);
// 获取数组首元素
System.out.println(arr[0]);
// 获取数组尾元素
System.out.println(arr[arr.length - 1]);
// 普通for循环遍历
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 增强for循环遍历
for (int num : arr) {
System.out.print(num + " ");
}
13.4 数组默认值
不同类型的数组元素有默认初始值:
| 类型 | 默认值 |
|---|---|
| 整型(byte, short, int, long) | 0 |
| 浮点型(float, double) | 0.0 |
| 字符型(char) | 空字符(NUL) |
| 布尔类型(boolean) | false |
| 字符串(String) | null |
13.5 数组最值查找
查找数组最值的思想:先假设数组首位是最大或最小值,然后与数组后面的所有元素进行比较,找到更大或更小的值则更新。
package day04;
public class FindMax {
public static void main(String[] args) {
int[] arr = {20, 27, 5, 3, 18, 32, 16, 55, -10};
int max = arr[0]; // 假设第一个元素是最大值
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i]; // 找到更大的值,更新max
}
}
System.out.println("最大值:" + max);
}
}
13.6 数组元素交换
数组元素可以使用下标方式进行值交换,通常借助临时变量。
package day04;
public class Swap {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
// 交换第二个和第四个元素
int temp = arr[1];
arr[1] = arr[3];
arr[3] = temp;
for (int n : arr) {
System.out.print(n + " "); // 输出:1 4 3 2 5 6
}
}
}
13.7 数组复制
使用System.arraycopy()方法可以复制数组元素。
// 数组复制
int[] arr = {2, 3, 4, 1, 6, 5, 8}; // 源数组
int[] arr2 = new int[arr.length]; // 目标数组
// 从arr数组第2个元素开始复制,到arr2中起始位置开始粘贴,共复制5个长度
System.arraycopy(arr, 2, arr2, 0, 5);
for (int n : arr2) {
System.out.print(n + " "); // 输出:4 1 6 5 8 0 0
}
13.8 数组扩容
使用Arrays.copyOf()方法可以实现数组扩容。
package day04;
import java.util.Arrays;
public class GrowArr {
public static void main(String[] args) {
// 数组扩容
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
// 将arr数组中的元素复制到新数组,复制的个数取决于新数组的长度
int[] arr2 = Arrays.copyOf(arr, 5);
for (int n : arr2) {
System.out.print(n + " "); // 输出:1 2 3 4 5
}
System.out.println();
// 动态扩容:原数组增加5个长度
arr = Arrays.copyOf(arr, arr.length + 5);
arr[8] = 9; // 给新扩容的位置赋值
for (int n : arr) {
System.out.print(n + " "); // 输出:1 2 3 4 5 6 7 8 9 0 0 0 0 0
}
}
}
13.9 数组排序
13.9.1 冒泡排序
冒泡排序通过相邻元素比较和交换实现排序。
package day05;
public class PopSort {
public static void main(String[] args) {
// 冒泡排序(从小到大)
int[] arr = {20, 4, 16, 32, 12, 6, 18, 69, 34};
for (int i = 0; i < arr.length - 1; i++) { // 外循环:找最大值的次数
for (int j = 0; j < arr.length - 1 - i; j++) { // 内循环:每一轮比较的次数
if (arr[j] > arr[j + 1]) { // 前面比后面大,交换位置
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int n : arr) {
System.out.print(n + " "); // 输出排序后的数组
}
}
}
13.9.2 工具类排序
使用Arrays.sort()方法可以快速对数组排序。
int[] arr = {20, 4, 16, 32, 12, 6, 18, 69, 34};
Arrays.sort(arr); // 对数组从小到大排序
for (int n : arr) {
System.out.print(n + " ");
}
14. 方法
方法是 Java 程序中最基本的代码组织单元,用于封装一段具备独立功能、可重复调用的代码块。合理使用方法可以提升代码的复用性、可读性和可维护性。
14.1 方法的核心概念
方法的作用主要体现在以下四个方面:
- 代码复用:相同逻辑不用重复抄写。
- 简化代码结构:拆分复杂业务,可读性更强。
- 便于维护:修改功能只改一处,所有调用处同步生效。
- 实现逻辑解耦:一段代码只负责一件事。
14.2 方法完整语法定义
标准格式如下:
修饰符 返回值类型 方法名(形参列表) {
// 方法体:实现功能的代码
return 返回值; // 有返回值方法必须写
}
各部分详解:
- 修饰符:初学统一使用
public static,表示公共静态方法,可直接在 main 中调用。 - 返回值类型:有结果返回时写对应数据类型(byte、short、int、long、float、double、char、boolean、String、数组、自定义类等);无任何数据返回时固定写
void。 - 方法名:采用小驼峰命名,首字母小写,多个单词从第二个单词首字母大写;建议使用动词或动名词,见名知意,如
sum、printInfo、getUserName;不能数字开头、不能用关键字、不建议使用拼音。 - 形参列表:方法运行需要外部传入数据时,在括号内定义形参,格式为
数据类型 变量名,多个参数用逗号分隔;不需要外部数据时括号保留为空()。 - 方法体:方法的核心逻辑,循环、判断、运算都写在这里。
- return 返回值:有返回值方法必须写
return 数据;,数据类型必须和定义的返回值一致;void 无返回值方法可写单独的return;,作用是终止方法,不能带数据。
14.3 四种方法分类
按返回值与参数划分,方法可分为四种类型:
| 类型 | 格式 | 示例 | 适用场景 |
|---|---|---|---|
| 无返回值、无参数 | public static void printHello(){} |
固定执行一段固定逻辑,不需要传参、不需要结果 | 打印固定提示信息 |
| 无返回值、有参数 | public static void printNum(int n){} |
外部传数据,方法内部直接打印或操作,不返回结果 | 打印指定次数的内容 |
| 有返回值、无参数 | public static int getRandom(){} |
方法内部自行计算,只需要对外返回一个结果 | 生成随机数 |
| 有返回值、有参数 | public static int add(int a, int b){} |
外部传入数据,运算后返回最终结果 | 两数求和 |
public class MethodDemo {
public static void main(String[] args) {
// 1. 无返回无参
printHello();
// 2. 无返回有参
printCount(10);
// 3. 有返回无参
int num = getOneNum();
System.out.println(num);
// 4. 有返回有参
int res = add(3, 5);
System.out.println(res);
}
// 1. 无返回 无参数
public static void printHello() {
System.out.println("Hello Java 方法");
}
// 2. 无返回 有参数
public static void printCount(int count) {
for (int i = 0; i < count; i++) {
System.out.print(i + " ");
}
}
// 3. 有返回 无参数
public static int getOneNum() {
return 666;
}
// 4. 有返回 有参数
public static int add(int a, int b) {
return a + b;
}
}
14.4 方法调用规则
方法只有被调用才会执行,写在类中与 main 同级的方法不会自动运行,必须主动调用。
静态方法(public static)调用方式:
方式一:同个类内直接调用。
public static void main(String[] args) {
// 无返回值:直接写方法名(实参);
print();
printName("小明");
// 有返回值:两种写法
// ① 用对应类型变量接收(推荐,保留结果后续使用)
int sum = add(1, 2);
// ② 直接打印(临时使用,不保存结果)
System.out.println(add(10, 20));
}
方式二:不同类调用,使用 类名.静态方法()。
// TestA.java
public class TestA {
public static void test() {
System.out.println("跨类调用");
}
}
// TestB.java
public class TestB {
public static void main(String[] args) {
TestA.test(); // 类名.静态方法()
}
}
调用关键限制:
- void 无返回方法不能用变量接收,编译直接报错。
- 有返回值方法不接收不会报错,但返回结果直接丢弃,失去调用意义。
- 调用时实参个数、类型、顺序必须和形参完全匹配,否则编译报错。
14.5 形参与实参
形参:定义方法时写在小括号里的变量,仅形式占位,没有真实数据。作用是指定调用时必须传入什么类型、多少个数据。作用域仅限当前方法内部,方法执行结束自动销毁。
实参:调用方法时括号中传入真实的值或变量,用来给形参赋值。可以是常量、变量、表达式、方法返回值。匹配规则为个数相同、类型兼容、顺序一一对应。实参和形参变量名不需要一致,只看类型和顺序。
// int a、int b 是形参
public static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
int x = 10;
int y = 20;
// x、y 是实参,依次赋值给形参 a、b
add(x, y);
// 直接传常量实参
add(100, 200);
// 传表达式实参
add(2 + 3, 5 * 6);
}
形参与局部变量:
- 形参:方法括号内,属于方法局部,方法结束销毁。
- 局部变量:方法体、for/if 内部定义,无默认值,使用前必须赋值。
14.6 return 关键字两种用法
用法一:有返回值方法 return 数据;
- 返回的数据类型必须和方法声明的返回值完全匹配。
- 执行 return 后,立刻终止当前方法,后面代码不会执行。
- void 方法不能写带数据的 return,编译报错。
public static int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
用法二:void 方法单独 return;
不带任何数据,仅用于提前终止方法运行,后续代码不再执行。
public static void printSum() {
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i == 90) {
System.out.println("加到 90 停止,总和:" + sum);
return; // 直接结束方法,循环剩余数字不再执行
}
sum += i;
}
System.out.println("循环全部执行完毕");
}
return 补充细节:
- 有返回值方法所有逻辑分支必须保证一定能走到 return,否则编译报错。
- return 之后不能写代码(不可达代码)。
14.7 方法参数传递机制(值传递与地址传递)
Java 只有值传递,分为两种表现形式:基本类型副本传递、引用类型地址值传递。
基本数据类型 + String:传递副本(值传递)
基本类型(byte、short、int、long、float、double、char、boolean)传递的是变量拷贝副本,方法内部修改形参,不会影响外部实参原始数据。String 虽然是引用类型,但字符串不可变,修改会创建新对象,表现和基本类型一致。
public class ParamTest {
public static void changeNum(int num) {
num = 999; // 修改副本,外部不变
}
public static void main(String[] args) {
int a = 10;
changeNum(a);
System.out.println(a); // 输出 10,原始值没变化
}
}
除 String 外其他引用类型:传递地址值
数组、自定义类对象、集合等,传递的是对象内存地址副本,形参和实参指向同一个堆内存对象。方法内通过地址修改对象内部数据,外部原始变量会同步变化。
public class ArrayParam {
public static void changeArr(int[] arr) {
arr[0] = 888; // 修改堆中数组元素,外部同步变
}
public static void main(String[] args) {
int[] nums = {1, 2, 3};
changeArr(nums);
System.out.println(nums[0]); // 输出 888
}
}
14.8 可变参数(不定长参数)
当不确定调用时会传入多少个同类型参数时(求和、批量打印、批量判断),可以使用可变参数。语法格式为 数据类型... 参数名,底层本质是数组。
// 可变参数 nums 等价于 int[] nums
public static int getSum(int... nums) {
int sum = 0;
for (int n : nums) {
sum += n;
}
return sum;
}
public static void main(String[] args) {
System.out.println(getSum(1));
System.out.println(getSum(1, 2));
System.out.println(getSum(1, 2, 3, 4, 5));
}
语法规则:
- 一个方法最多只能有 1 个可变参数。
- 可变参数必须放在所有形参最后面。
// 正确:普通参数在前,可变参数最后
public static void test(String name, int... arr) {}
// 错误:可变参数不能放前面
// public static void test(int... arr, String name){}
// 错误:多个可变参数
// public static void test(int... a, double... b){}
调用时可以不传可变参数、传多个常量、直接传同类型数组。
14.9 方法重载 Overload
同一个类中,方法名完全相同、参数列表不同的多个方法,互为重载。
判断重载的核心标准:
- 方法名必须一模一样。
- 参数列表必须不同(满足任意一条即可):参数个数不同、参数类型不同、参数顺序不同(类型组合不同)。
无关条件:
- 返回值类型(仅返回值不同,参数完全一致不算重载,直接报错)。
- 修饰符、形参变量名。
public class OverLoadDemo {
public static void main(String[] args) {
test();
test(10);
test("张三");
test(20, "李四");
}
// 无参
public static void test() {}
// 1 个 int 参数
public static void test(int a) {}
// 1 个 String 参数
public static void test(String name) {}
// int + String
public static double test(int num, String name) {
return 1.1;
}
}
重载调用匹配规则:调用时传入实参,编译器自动匹配参数最贴合的重载方法:精确类型匹配优先,自动类型转换匹配次之,无匹配则编译报错。
重载实际开发意义:同一功能多种传参方式,对外只暴露同一个方法名,调用简单、可读性高。例如打印方法,可以传数字、字符串、数组,统一叫 print。
14.10 方法嵌套调用与递归
嵌套调用:方法内部可以调用其他方法,支持多层嵌套。执行流程为 A 暂停、执行 B、B 执行完回到 A 继续运行剩余代码。
public static void main(String[] args) {
printAll();
}
public static void printAll() {
printHeader();
printBody();
printFooter();
}
public static void printHeader() {
System.out.println("==== 头部 ====");
}
public static void printBody() {
System.out.println("内容正文");
}
public static void printFooter() {
System.out.println("==== 底部 ====");
}
递归调用(特殊嵌套):方法自己调用自己,用于解决重复性拆分问题(阶乘、斐波那契、遍历目录)。递归必备两个条件,缺一不可:
- 递归出口(终止条件):满足条件不再调用自己,否则死递归栈溢出。
- 递归递进公式:每次调用缩小问题规模。
public class RecursionDemo {
public static void main(String[] args) {
int res = factorial(5);
System.out.println(res);
}
public static int factorial(int n) {
// 递归出口
if (n == 1) {
return 1;
}
// 递进:自己调用自己,规模缩小
return n * factorial(n - 1); // 3*factorial(2)*factorial(1)
}
}
递归缺点:层数过多会出现 StackOverflowError 栈内存溢出,复杂循环场景优先使用 for 循环。
14.11 方法常见易错点总结
- void 方法写
return 10;编译报错,无返回值不能返回数据。 - 有返回值所有分支没有 return,编译报错。
- 调用方法实参类型、个数、顺序和形参不匹配,报错。
- 可变参数放在参数列表前面、多个可变参数,语法报错。
- 仅返回值不同、参数完全相同,不构成重载,编译冲突。
- 基本类型传参修改形参,外部实参不变;数组或对象传参会同步修改。
- 递归不写终止条件,运行时报栈溢出异常。
- 方法内部定义局部变量无默认值,使用前必须赋值;成员变量自带默认值。
- return 后书写代码,提示不可达代码,编译失败。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)