Java 基础 03. Java 方法
1. 何谓方法
-
Java 方法是语句的集合,它们在一起执行一个功能。
- 方法是解决一类问题的步骤的有序组合;
- 方法包含于类或对象中;
- 方法在程序中被创建,在其他地方被引用。
-
设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是 一个方法只完成 1 个功能,这样利于我们后期的扩展。
package github.method; public class Demo01 { // main方法 public static void main(String[] args) { int sum = add(1, 2); System.out.println(sum); } // 加法 public static int add(int a,int b){ return a+b; } }
2. 方法的定义及调用
-
Java 的方法类似于其它语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:
-
方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
-
修饰符:是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
-
返回值类型:方法可能会返回值。 returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下, returnValueType 是关键字 void。
-
方法名:是方法的实际名称。方法名和参数表共同构成方法签名。(首字母小写,驼峰命名)
-
参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
- 形式参数:在方法被调用时用于接收外界输入的数据。
- 实参:调用方法时实际传给方法的数据。
-
方法体:方法体包含具体的语句,定义该方法的功能。
修饰符 返回值类型 方法名(参数类型 参数名){ ... 方法体 ... return 返回值; }
-
-
调用方法:对象名.方法名(实参列表)
-
Java 支持两种调用方法的方式,根据方法是否返回值来选择,当方法返回一个值的时候,方法调用通常被当做一个值。例如:
int larger = max(30,40);
-
如果方法返回值是 void ,方法调用一定是一条语句。
System.out.println("Hello,World!");
-
示例:
package github.method; public class Demo02 { public static void main(String[] args) { int max = max(10, 20); System.out.println(max); } // 比大小 public static int max(int num1,int num2){ int result = 0; if(num1==num2){ System.out.println("num1==num2"); return 0; // 终止方法 } if(num1>num2){ result = num1; } else { result = num2; } return result; } }
值传递 (Java)和引用传递
- 方法可以修改 传递引用所对应的 变量值,而 不能修改传递值调用 所对应的变量值,这句话相当重要,这是按值调用与引用调用的根本区别,以下为分析:
- 按值调用 (call by value) 表示方法接受的时调用者 提供的值。
package github.method; public class Demo03 { private static int x = 10; public static void updateValue(int value) { value = 3 * value; System.out.println("value的值:" + value); } public static void main(String[] args) { System.out.println("调用前的值:" + x); updateValue(x); System.out.println("调用后的值:" + x); } }

分析:
-
value 被初始化,为 x 值的一个拷贝(也就是10)
-
value 被乘以 3 后等于30,但注意此时 x 的值仍为10!
-
这个方法结束后,参数变量 value 不再使用,被回收。
结论:当传递方法参数类型为基本数据类型(数字以及布尔值)时,一个方法是不可能修改一个基本数据类型的参数。
-
按引用调用 (call by reference)
-
按引用调用,则表示方法接收的是 调用者提供的变量地址 (如果是 C 语言,就是指针,Java 并没有指针的概念)
-
当然 Java 中除了 基本数据类型,还有 引用数据类型,也就是 对象引用,那么对于这种数据类型又是怎么样的情况呢?我们还是一样先来看一个例子:
- 先声明一个 User 对象类型:
package github.method; public class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
- 执行 class
package github.method; public class Test02 { public static void updateUser(User student) { student.setName("Liu"); student.setAge(22); } public static void main(String[] args) { User user = new User("USER", 20); System.out.println("调用user前的值:" + user.getName() + "," + user.getAge()); updateUser(user); System.out.println("调用user后的值:" + user.getName() + "," + user.getAge()); } }
分析一下这个过程:
分析:
- student 变量被初始化为 user 值的拷贝,这里是一个对象的引用。
- 调用 student 变量的 set 方法作用在这个引用对象上,user 和 student 同时引用的 User 对象内部值 被修改。
- 方法结束后,student 变量不再使用,被释放,而 user 还是没有变,依然指向User 对象。
结论:显然,User 的值被改变了,但是这是将最开始所对应得值改变了,把 User 的本身属性改变了,才会进行值得变化,虽然看似是按引用传递值,但是实际上是将值改变了。
- 下面通过一个反例来说明:
package github.method; /** * java 中的按值调用 */ public class Test03 { /** * 交换两个对象 * * @param x * @param y */ public static void swap(User x, User y) { User temp = x; x = y; y = temp; } public static void main(String[] args) { User user = new User("user", 26); User stu = new User("stu", 18); System.out.println("调用前user的值:" + user.getName() + "," + user.getAge()); System.out.println("调用前stu的值:" + stu.getName() + "," + stu.getAge()); swap(user, stu); System.out.println("调用后user的值:" + user.getName() + "," + user.getAge()); System.out.println("调用后stu的值:" + stu.getName() + "," + stu.getAge()); } }
-
通过程序发现:user 和 stu 的值并没有发生变化,也就是方法并没有改变存储在变量 user 和 stu 中的对象引用。swap 方法的参数 x 和 y 被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝的值而已,最终,所做的事都是白费力气罢了。在方法结束后 x,y 将被丢弃,而原来的变量 user 和 stu 仍然引用这个方法调用之前所引用的对象。
-
这个过程也充分说明了,Java 程序设计语言对
对象
采用的不是引用调用,实际上是 对象引用进行的是值传递,当然在这里我们可以简单理解为这就是按值调用和引用调用的区别,而且必须明白即使 Java 函数在传递引用数据类型时,也只是拷贝了引用的值罢了,之所以能修改引用数据是因为它们同时指向了一个对象,但这仍然是按值调用而不是引用调用。总结
-
一个方法不能修改一个基本数据类型的参数(数值型和布尔型)。
-
一个方法可以修改一个引用所指向的对象状态,但这仍然是按值调用而非引用调用。
-
上面两种传递都进行了值拷贝的过程。
-
3. 方法重载
-
重载就是在一个类中,有相同的函数名称,但形参不同的函数。
-
方法的重载的规则
- 方法名称必须相同。
- 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)
- 方法的返回类型可以相同也可以不相同。
- 仅仅返回类型不同,不足以成为方法的重载。
-
实现理论:
- 方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
package github.method; public class Demo02 { public static void main(String[] args) { int max = max(10, 20); System.out.println(max); double max2 = max(10.0, 20.0); System.out.println(max2); } // 比大小 public static int max(int num1, int num2) { int result = 0; if (num1 == num2) { System.out.println("num1==num2"); return 0; // 终止方法 } if (num1 > num2) { result = num1; } else { result = num2; } return result; } // 比大小 方法重载,参数类型不同 public static double max(double num1, double num2) { double result = 0; if (num1 == num2) { System.out.println("num1==num2"); return 0; // 终止方法 } if (num1 > num2) { result = num1; } else { result = num2; } return result; } }
package github.method; public class Demo01 { // main方法 public static void main(String[] args) { int sum = add(1, 2); System.out.println(sum); int sum2 = add(1, 2, 3); System.out.println(sum2); } // 加法 public static int add(int a,int b){ return a+b; } // 方法重载,参数个数不同 public static int add(int a,int b,int c){ return a+b+c; } }
4. 命令行传参
package github.method;
public class Demo03 {
public static void main(String[] args) {
// args.length 数组长度
for(int i=0;i < args.length;i++){
System.out.println("args[" + i + "]:" + args[i]);
}
}
}

5. 可变参数
- JDK 1.5 开始,Java 支持传递同类型的可变参数给一个方法。
- 在方法声明中,在指定参数类型后加一个省略号(...)。
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
package github.method;
public class Demo04 {
public static void main(String[] args) {
Demo04 demo04 = new Demo04(); // 另一种调用方式:对象
demo04.test(1,2,3,4,5);
}
public void test(int... i){
System.out.println(i[0]);
System.out.println(i[1]);
System.out.println(i[2]);
System.out.println(i[3]);
System.out.println(i[4]);
}
}
package github.method;
public class Demo05 {
public static void main(String[] args) {
// 调用可变参数的方法
printMax(34,3,3,2,56.5);
printMax(new double[]{1,2,3});
}
public static void printMax(double... numbers){
// 判断是否有参数传入
if(numbers.length==0){
System.out.println("没有数据!");
return;
}
double result = numbers[0];
// 排序
for(int i=1;i<numbers.length;i++){
if(numbers[i] > result){
result = numbers[i];
}
}
System.out.println("The max Value is " + result);
}
}
6. 递归
-
A 方法调用 B 方法,我们很容易理解!
-
递归就是:A 方法调用 A 方法!就是自己调用自己。
-
利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述岀解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
-
递归结构包括两个部分:
- 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环;
- 递归体:什么时候需要调用自身方法。
package github.method; import java.util.Scanner; public class Demo05 { // 5! 5*4*3*2*1 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个数:"); int number = scanner.nextInt(); int test = test(number); System.out.println(number + "的阶乘:" + test); scanner.close(); } public static int test(int n){ if(n==1){ return 1; }else{ return n*test(n-1); } } }
-
写一个计算器,要求实现加减乘除功能,井且能够循环接收新的数据,通过用户交互实现。
package github.method; import java.util.Scanner; public class Demo06 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); double sum = 0; while (true) { System.out.println("请输入第一个整数:"); double a = scanner.nextDouble(); System.out.println("请输入第二个整数:"); double b = scanner.nextDouble(); System.out.println("请输入要运算的字符(+:表示加法,-:表示减法,*:表示乘法,/:表示除法)"); String temp = scanner.next(); switch (temp) { case "+": sum = a + b; System.out.println("结果是:" + sum); continue; case "-": sum = a - b; System.out.println("结果是:" + sum); continue; case "*": sum = a * b; System.out.println("结果是:" + sum); continue; case "/": sum = a / b; System.out.println("结果是:" + sum); continue; default: System.out.println("请输入正确的运算符号!!"); } } } }