06-方法
- 6.1 引言
- 方法可以用于定义可重用的代码以及组织和简化编码。
- 6.2 定义方法
- 方法的定义由方法名称、参数、返回值类型以及方法体组成。
- 定义方法的语法如下所示:
修饰符 返回值类型 方法名(参数列表){ //方法体; }
- 方法头是指方法的修饰符、返回值类型、方法名和方法的参数。
- 方法可以返回一个值。有些方法只是完成某些要求的操作,而不返回值。在System.exit、System.out.println方法中返回值类型也是void。如果方法有返回值,则称为带返回值的方法,否则就称这个方法为void方法。
- 定义在方法头中的变量称为形式参数或者简称为形参。参数就像是占位符。当调用方法时,就给参数传递一个值,这个值称为实际参数或者实参。参数列表指明方法中参数的类型、顺序和个数。方法名和参数列表一起构成方法签名。参数是可选的,也就是方法可以不包含参数。
- 为使带返回值的方法能返回一个结果,必须要使用带关键字return的返回语句。执行return语句时方法终止。
- 在其他语言中,方法称为过程或函数。这些语言中,带返回值的方法称为函数,返回值类型是void的方法称为过程。
- 在方法头中,需要对每一个参数进行单独的数据类型声明。
- 定义是指被定义的项是什么,而声明通常是指被声明的项分配内存来存储数据。
- 6.3 调用方法
- 为了之用方法,必须使用它。根据方法是否有返回值,调用方法有两种途径。
- 如果方法返回一个值,对方法的调用通常就当做一个值处理。
- 如果方法返回void,对方法的调用必须是一条语句。
- 在Java中,带返回值的方法也可以当做语句调用。这种情况下,函数调用者只需要忽略返回值即可。虽然很少这么做,但是如果调用者对返回值不感兴趣,这样也是允许的。
- 当调用一个方法时,程序控制就转移到被调用的方法。当执行完return语句或执行到表示方法结束的右括号时,被调用的方法将程序控制返还给调用者。
package chapter06; public class TestMax { public static void main(String[] args){ int i = 5; int j = 2; int k = max(i,j); System.out.println("The maximum of " + i + " and " + j + " is " + k); } public static int max(int num1,int num2) { int result; if (num1 > num2) result = num1; else result = num2; return result; } }
- 方法能够带来代码的共享和重用。除了可以在TestMax中调用max方法,还可以在其他类中调用他。如果创建了一个新类,可以通过使用“类名.方法名”来调用max方法。
- 每当调用一个方法时,系统会创建一个活动记录(也称活动框架),用于保存方法中的参数和变量。活动记录置于一个内存区域中,称为调用栈。调用栈也称为执行栈、运行时栈,或者一个机器栈,常简称为栈。当一个方法调用另一个方法时,调用者的活动记录保持不变,一个新的活动记录被创建用于被调用的新方法。一个方法结束运行返回到调用者,其相应的活动记录也被释放。
- 调用栈以后进先出的方式来保存活动记录。
- 6.4 void方法与返回值方法
```java
package chapter06;
public class TestVoidMethod {
public static void main(String[] args){
System.out.print("The grade is ");
printGrade(78.5);
System.out.print("The grade is ");
printGrade(59.5);
}
public static void printGrade(double score){
if (score >= 90.0){
System.out.println('A');
}
else if (score >= 80.0){
System.out.println('B');
}
else if (score >= 70.0){
System.out.println('C');
}
else if (score >= 60.0){
System.out.println('D');
}
else {
System.out.println('F');
}
}
}
```
```java
package chapter06;
public class TestReturnGradeMethod {
public static void main(String[] args){
System.out.print("The grade is " + getGrade(78.5));
System.out.print("\nThe grade is " + getGrade(59.5));
}
public static char getGrade(double score){
if (score >= 90.0)
return 'A';
else if (score >= 80.0)
return 'B';
else if (score >= 70.0)
return 'C';
else if (score >= 60.0)
return 'D';
else
return 'F';
}
}
```
- return语句对于void方法不是必须的,但他能用于方法并返回到方法的调用者。他的语法是:
```java
return;
```
- 这种用法很少,对视对于改变void方法中的正常流程控制是很有用的。
-
6.5 按值传参
- 调用方法的时候是通过传值的方式将实参传递给形参的。
- 方法的最强大之处在于他处理参数的能力。调用方法时,需要提供参数,他们必须与方法签名中所对应的形参次序相同。这称为参数顺序匹配。
- 实参必须与方法签名中定义的形参在次序和数量上匹配,在类型上兼容。类型兼容是指不需要经过显式的类型转换,实参的值就可以传递给形参。
- 当调用参数的方法时,实参的值传递给形参,这个过程称为按值传递。如果实参是变量而不是字面值,则将该变量的值传递给形参。无论形参在方法中是否改变,该变量都不受影响。
package chapter06; public class Increment { public static void main(String[] args){ int x = 1; System.out.println("Before the call,x is " + x); increment(x); System.out.println("After the call,x is " + x); } public static void increment(int n){ n++; System.out.println("n inside the method is " + n); } }
package chapter06; public class TestPassByValue { public static void main(String[] args){ int num1 = 1; int num2 = 2; System.out.println("Before invoking the swap method,num1 is " + num1 + "and num2 is " + num2); swap(num1,num2); System.out.println("After invoking the swap method,num1 is " + num1 + "and num2 is " + num2); } public static void swap(int n1,int n2){ System.out.println("\tInside the swap method"); System.out.println("\t\tBefore swapping, n1 is " + n1 + "and n2 is " + n2); int temp = n1; n1 = n2; n2 = temp; System.out.println("\t\tAfter swapping, n1 is " + n1 + "and n2 is " + n2); } }
-
6.6 模块化代码
- 模块化的代码是的代码易于维护和调试,并且是的代码可以被调用。
package chapter06; import java.util.Scanner; public class GreatestCommonDivisorMethod { public static void main(String[] args){ Scanner input = new Scanner(System.in); System.out.print("Enter first integer: "); int n1 = input.nextInt(); System.out.print("Enter second integer: "); int n2 = input.nextInt(); System.out.println("The greatest common divisor for " + n1 + " and " + n2 + " is " + gcd(n1,n2)); } public static int gcd(int n1,int n2){ int gcd = 1; int k = 2; while (k <= n1 && k <= n2){ if (n1 % k == 0 && n2 % k == 0) gcd = k; k++; } return gcd; } }
- 通过将求最大公约数的代码封装在一个方法中,这个程序就具备以下几个优点:
- 1、他将计算最大公约数的问题和main方法中的其他代码分隔开,这样做会使得逻辑更加清晰而且程序的可读性更强。
- 2、将计算最大公约数的错误限定在gcd方法中,这样就缩小了调试的范围。
- 3、现在,其他程序可以重复使用gcd方法。
package chapter06; public class PrimeNumberMethod { public static void main(String[] args){ System.out.println("The first 50 prime numbers are \n"); printPrimeNumbers(50); } public static void printPrimeNumbers(int numberOfPrime){ final int NUMBER_OF_PRIME_PER_LINE = 10; int count = 0; int number = 2; while (count < numberOfPrime){ if (isPrime(number)){ count++; if (count % NUMBER_OF_PRIME_PER_LINE == 0){ System.out.printf("%-5d\n",number); } else System.out.printf("%-5d",number); } number++; } } public static boolean isPrime(int number){ for (int divisor = 2;divisor <= number / 2;divisor++){ if (number % divisor == 0){ return false; } } return true; } }
- 模块化的代码是的代码易于维护和调试,并且是的代码可以被调用。
-
6.7 示例学习:将十六进制数转换为十进制数
package chapter06; import java.util.Scanner; public class Hex2Dec { public static void main(String[] args){ Scanner input = new Scanner(System.in); System.out.print("Enter a hex number: "); String hex = input.nextLine(); System.out.println("The decimal value for hex number " + hex + " is " + hexToDecimal(hex.toUpperCase())); } public static int hexToDecimal(String hex){ int decimalValue = 0; for (int i = 0;i < hex.length();i++){ char hexChar = hex.charAt(i); decimalValue = decimalValue * 16 + hexCharToDecimal(hexChar); } return decimalValue; } public static int hexCharToDecimal(char ch){ if (ch >= 'A' && ch <= 'F') return 10 + ch - 'A'; else return ch - '0'; } }
-
6.8 重载方法
- 重载方法使得你可以使用同样的名字来定义不同方法,只要他们的参数列表是不同的。
package chapter06; public class TestMethodOverloading { public static void main(String[] args){ System.out.println("The maximum of 3 and 4 is " + max(3,4)); System.out.println("The maximum of 3.0 and 5.4 is " + max(3.0,5.4)); System.out.println("The maximum of 3.0, 5.4 and 10.14 is " + max(3.0,5.4,10.14)); } public static int max(int num1,int num2){ if (num1 > num2) return num1; else return num2; } public static double max(double num1,double num2){ if (num1 > num2) return num1; else return num2; } public static double max(double num1,double num2,double num3){ return max(max(num1,num2),num3); } }
- 重载方法可以使得程序更加清晰,以及更加具有可读性。执行同样功能但是具有不同参数类型的方法应该使用同样的方法。
- 被重载的方法必须具有不同的参数列表。不能基于不同修饰符或返回值类型来重载方法。
- 有时调用一个方法时,会有两个或更多可能的匹配,但是,编译器无法判断哪个是最精确的匹配。这称为歧义调用。歧义调用会产生一个编译错误。
- 重载方法使得你可以使用同样的名字来定义不同方法,只要他们的参数列表是不同的。
-
6.9 变量的作用域
- 在方法中定义的变量称为局部变量。局部变量的作用域是从变量声明的地方开始,知道包含该变量的块结束为止。局部变量都必须在使用之前进行声明和赋值。
- 可以在一个方法中的不同块里声明同名的局部变量,但是,不能再嵌套块中或同意块中两次声明同一个变量。
- 一种常见的错误是在for循环中国声明一个变量,然后试图在循环外使用它。
-
6.10 示例学习:生成随机字符
package chapter06; public class TestRandomCharacter { public static void main(String[] args){ final int NUMBER_OF_CHARS = 175; final int CHARS_PER_LINE = 25; for (int i = 0;i < NUMBER_OF_CHARS;i++){ char ch = RandomCharacter.getRandomLowerCaseLetter(); if ((i + 1) % CHARS_PER_LINE == 0) System.out.println(ch); else System.out.print(ch); } } }
package chapter06; public class RandomCharacter { public static char getRandomCharacter(char ch1,char ch2){ return (char)(ch1 + Math.random() * (ch2 - ch1 + 1)); } public static char getRandomLowerCaseLetter(){ return getRandomCharacter('a','z'); } public static char getRandomUpperCaseLetter(){ return getRandomCharacter('A','Z'); } public static char getRandomDigitCharacter(){ return getRandomCharacter('0','9'); } public static char getRandomCharacter(){ return getRandomCharacter('\u0000','\uFFFF'); } }
-
6.11 方法抽象和逐步求精
方法抽象是通过将方法的使用和他的实现分离来实现的。
当编写一个程序时,可以使用“分治”策略,也称为逐步求精,将大问题分解成小问题,子问题又分解成更小、更容易处理的问题。- 6.11.1 自顶向下的设计
- 6.11.2 自定向下和自顶向上的实现
- 6.11.3 实现细节
- 6.11.4 逐步求精的优势
- 1、更简单的程序
- 2、重用方法
- 3、易于开发、调试和测试
- 4、更方便团队合作