Lesson09_方法
作业题讲解
-
生成四位数的验证码—> 验证码要求由 0-9 .a-z A-Z组成
/** * 生成四位数的验证码---> 验证码要求由 0-9 .a-z A-Z组成 * 思路: * Random 生成随机数 --> 随机字符 --> 借助字符数组,把字符和下标对应起来。随机数就是随机下标 * 用一个char[]保存4位随机验证码 * * 去重 * 生成随机数时与前面的各个位进行比较,如果重复则重新生成 */ import java.util.Random; import java.util.Arrays; public class Hw1{ public static void main(String[] args){ Random random = new Random(); char[] res = new char[4]; // 保存验证码 char[] code = new char[62]; // 保存0~9,A~Z,a~z // 给code[]赋值 int index = 0; for(char c = '0'; c <= '9'; c ++){ code[index++] = c; } for(char c = 'A'; c <= 'Z'; c ++){ code[index++] = c; } for(char c = 'a'; c <= 'z'; c ++){ code[index++] = c; } // 测试代码:检测初始化结果 System.out.println(Arrays.toString(code)); // 开始生成验证码 // i 表示当前给哪一位生成随机字符 for(int i = 0; i < res.length;){ int ran = random.nextInt(code.length); // 随机数(随机下标) char c = code[ran]; // 随机字符 // 准备存入res数组 // 先去重(与前面的元素依次比较) boolean isRepeat = false;// 标记是否重复 for(int j = 0; j < i; j ++){ if(res[j] == c){ // 重复 isRepeat = true; break; } } if(!isRepeat){ // 不重复 res[i] = c; // 存入数组 i ++ ; // 有效字符+1,可以进行到下一位 } } // end of for // 输出验证码 System.out.println(Arrays.toString(res)); } }
-
十个幸运儿
/** * 编程大赛即将拉开序幕, * 由于人选有限,将选出10人参加全国大赛, * 为了体现公平的原则,采用如下的方法实现抽签: * 随机生成0到1000的整数,其中能被3整除的就是幸运儿之一 * 并将其存储起来,直到第十个幸运儿产生为止, * 最后将这10个人的幸运号按从小到大排序, * 并按照逆序打印出来。 * 思路: * int[] arr = new int[10]; * Random random = new Random(); int lucky = random.nextInt(1001); * %3 == 0 * 去重:思路参考上一题 * Arrays.sort(arr); * for(int i = arr.length - 1; i >= 0; i --) */ import java.util.Random; import java.util.Arrays; public class Hw2{ public static void main(String[] args){ int[] arr = new int[10]; // 保存十个幸运儿的编号 Random random = new Random(); // i表示当前生成哪一个幸运儿 for(int i = 0; i < arr.length; ){ while(true){ int lucky = random.nextInt(1001); // [0,1000] // 判断合法性 if(lucky % 3 != 0){ continue;// 重新生成 } // 能执行到这里,说明生成的随机数能被3整除 // 去重(和已经生成的幸运儿比较) boolean isRepeat = false; for(int j = 0; j < i; j ++){ if(arr[j] == lucky){ // 已存在,是重复幸运儿 isRepeat = true; break; // 跳出的是for循环,重新生成随机数 } } if(!isRepeat){ // 如果不重复 arr[i] = lucky; // 有效幸运儿,收入囊中 i ++; // 下一位 break;// 跳出while(true) } } } // 升序排序 Arrays.sort(arr); // 倒序输出 for(int i = arr.length - 1; i >= 0; i --){ System.out.print(arr[i]+" "); } } }
方法
语句块
-
语句块(有时叫做复合语句),是用花括号扩起的任意数量的简单Java语句。块确定了局部变量的作用域。块中的程序代码,作为一个整体,是要被一起执行的。块可以被嵌套在另一个块中,但是不能在两个嵌套的块内声明同名的变量。语句块可以使用外部的变量,而外部不能使用语句块中定义的变量,因为语句块中定义的变量作用域只限于语句块。
-
代码块的封装(打包),用花括号把代码括起来,便于重复使用
定义
- 方法就是一段用来完成特定功能的代码片段,类似于其它语言的函数。方法是对现实功能的一个抽象,便于对功能的复用。在一个类中可以有多个方法,多个方法是平等关系。
方法用于定义该类或该类的实例的行为特征和功能实现。 方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
-
给这段代码起个名字
-
格式
[修饰符1 修饰符2 …] 返回值类型 方法名([形式参数列表]){ Java语句;… … … return 返回值; }
Arrays.sort(arr); // 排序 Scanner对象.nextInt(); // 获取键盘输入的一个整数
-
详解
- 修饰符:方法的修饰符比较多,有对访问权限进行限定,有静态修饰符static,还有最终修饰符final等,这些修饰符在后面的学习过程中会逐步介绍。
- 返回值类型:用于限定方法返回值的数据类型。
- 参数类型:用于限定调用方法时传入参数的数据类型。
- 参数名:是一个变量,用于接收调用方法时传入的数据。
- return关键字:用于结束方法以及返回方法指定类型的值。
- 返回值:被return语句返回的值,该值会返回给调用者,这里值一定要与方法的返回值数据类型一致。
-
注意
需要特别注意的是,方法中的“参数类型 参数名1,参数类型 参数名2”被称作参数列表,它用于描述方法在被调用时需要接收的参数,如果方法不需要接收任何参数,则参数列表为空,即()内不写任何内容。
方法的返回值必须为方法声明的返回值类型,如果方法中没有返回值,返回值类型要声明为void,此时,方法中return语句可以省略。
-
演示
public class MethodDemo{ public static void main(String[] args){ int[] arr = {1,3,5,7,9}; int[] brr = {2,3,4,5,6}; int[] crr = {1,2,3,4,5}; printArr(arr); // 方法调用:调用自己定义的方法打印数组 printArr(brr); // 重复使用,减少代码异味 printArr(crr); } // 方法定义:打印数组 public static void printArr(int[] arr){ // arr是形参名,便于描述方法的功能 for(int i = 0; i < arr.length; i ++){ if(i < arr.length-1){ // 前面部分带逗号 System.out.print(arr[i]+ ","); }else{ // 最后一个换行 System.out.println(arr[i]); } } } }
方法的三要素
-
方法名 : 见名知意
void printArr(int[] arr) 中的蓝色部分:printArr
-
参数列表 : 需要我们提供什么
void printArr(int[] arr)中的:int[] arr
-
返回类型 : 想要通过该方法得到什么
void printArr(int[] arr)中的:void void表示该方法没有任何返回数据
- 方法与参数列表合称方法签名。
方法的四种分类
-
有参有返回
Random random = new Random(); int num = random.nextInt(10); // 生成[0,9]的随机数
-
有参无返回 (返回类型写void)
int[] arr = {1,9,2,8,3,7,4,6,5}; Arrays.sort(arr); // 对数组排序
-
无参有返回
Scanner input = new Scanner(System.in); int age = input.nextInt(); // 接收键盘输入的整数
-
无参无返回
System.out.println(); // 输出换行符
static关键字
静态,静态方法只能调用方法外的静态方法或是静态变量。非静态不能调用。
形参、实参
弄明白这两个概念之前,先明确什么是方法定义,什么是方法调用,所有的方法定义出来,都是为了让别的方法使用的。永远不被别人调用的方法,其定义是没有意义的。
-
方法的调用
- 类名.方法名(参数)或者是对象.方法名(参数);
- 同类中省略类名,直接写方法名(参数);
- 当一个类中有多个方法,多个方法之间可以相互直接调用,static与普通方法之间的调用也可,都无需创建对象,但注意是普通方法调用静态方法,调用普通方法必须创建对象。
-
注意:
- 方法必须先定义再使用
- 方法的定义顺序跟调用无关
-
形式参数:在方法声明时用于接收外界传入的数据。也就是定义方法时,参数列表中的变量
-
实际参数:调用方法时实际传给方法的数据。也就是调用方法时,传入给方法的数值
-
返回值:方法在执行完毕后返还给调用它的环境的数据。结束方法的同时如果定义的返回值类型不是void,则同时将结果返回给调用者。返回值的数据类型一定要与返回值类型统一;
-
方法的返回值用return关键字返回。当定义的返回值类型不为void时,必须返回对应的值。当返回值类型为void时,return后可以不跟返回值;当返回值类型为void时,可以省略,Java会自动补齐。
-
返回值类型:事先约定的返回值的数据类型,可以返回任意类型,包含基本数据类型与引用数据数据类型,如无返回值,必须显示指定为为void。
-
在调用方法的时候一定要保证方法的参数列表、返回值保持一致。这里的保证参数列表一致是指参数的类型、个数一致。返回值保持一致是指返回值的数据类型。
-
当一个类中定义了多个方法时,在方法A中定义的局部变量无法在方法B中直接访问。此时可以将变量定义在成员位置(类中方法外),供多个方法同时访问。
使用static修饰的方法只能访问被static修饰的成员变量。
方法的特点
- 将实现某一个功能的代码封装起来,可以多次调用,重用代码
- 一个方法只做一件事
- 方法只有被调用时才会执行
- 方法中不能定义方法
- 根据需求提取方法
- 方法没有具体返回值的情况,返回值类型用关键字void表示,如果方法中的return语句如果在最后一行可以省略不写。
方法调用时代码的执行顺序
/**
* 方法调用时,代码的执行顺序
*/
public class MethodDemo2{
public static void main(String[] args){
learn();
}
public static void learn(){
System.out.println("正在做第一个作业题"); // 1
System.out.println("正在做第二个作业题"); // 2
lol(); // 有人找你开黑了
System.out.println("正在做第三个作业题"); // 11
System.out.println("做完作业了,睡觉"); // 12
}
public static void lol(){
System.out.println("推了一塔"); // 3
System.out.println("推了二塔"); // 4
System.out.println("推了高地塔"); // 5
call(); // 打电话
System.out.println("推门牙塔"); // 9
System.out.println("推水晶"); // 10
}
public static void call(){
System.out.println("哈喽,达令"); // 6
System.out.println("省略一万字……"); // 7
System.out.println("多喝热水,晚安。"); // 8
}
}
方法的值传递(重难点)
值传递也叫值拷贝
-
基本数据类型
/** * 方法的值传递 * 基本数据类型 */ public class Demo{ public static void main(String[] args){ int a = 3; add(a); // 把a的值传给n,n和a的值相同,但是是两个变量 System.out.println("a = "+a); // 3 } public static void add(int n){ n ++; System.out.println("n = "+n); // 4 } }
-
引用数据类型
/** * 方法的值传递 * 引用数据类型 : 引用 + 数据 */ public class Demo2{ public static void main(String[] args){ int[] arr = {3}; add(arr); // 把arr的值(数组的地址)给nrr,arr和nrr都指向同一个数组 System.out.println("arr[0] = "+arr[0]); // 4 } public static void add(int[] nrr){ nrr[0] ++; // 数组中第一个元素自增1 System.out.println("nrr[0] = "+nrr[0]); // 4 } }
总结:值传递实质是把实参的值拷贝给形参,形参和实参是两份数据。
如果参数是基本数据类型,则形参和实参是两份数据源,修改其中一个不会影响另一个;
如果参数是引用数据类型,则实参和形参都是引用(地址),指向的是同一份数据源,通过任何一个修改了数据源,都会给另一方造成影响。
注意事项
- 实参的数目、数据类型和次序必须和所调用的方法声明的形式参数列表匹配。
- return 语句终止方法的运行并指定要返回的数据。
- Java中进行方法调用中传递参数时,遵循值传递的原则(传递的都是数据的副本):
- 基本类型传递的是该数据值的copy值。
- 引用类型传递的是该对象引用的copy值,但指向的是同一个对象。
定义方法
在定义方法前,我们需要了解我们定义这个方法有什么作用?因此在定义方法之前我们需要明确我们的目标。在定义方法的过程中需要两个明确。
- 明确要定义的功能最后的结果是什么?确定返回值类型。
- 明确在定义该功能的过程中,是否需要未知内容参与运算?确定参数列表。
方法的重载
在同一个类中,不能出现两个完全一样的方法。但是如果有多个功能,而这些功能大致相同只是某些已知量不同时,可以将两个方法的名称定义成相同的,而参数不同。这些相同名称不同参数的方法之间是重载(overloading)关系。
-
概念:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可(参数类别不同)即同类中,同名不同参。
-
特点:与返回值类型无关,只与参数列表有关。
public static int test(double a,double b){ return 0; } public static int test(int a,int b){ return 0.0; }
-
好处:方便阅读,优化了程序设计。
-
注意:
- 重载的方法参数列表必须不同
- 参数个数不同,如method(int x)与method(int x,int y)不同
- 参数类型不同,如method(int x)与method(double x)不同
- 参数顺序不同,如method(int x,double y)与method(double x,int y)不同
- 重载只与方法名与参数类型相关与返回值无关,如void method(int x)与int method(int y)不是方法重载,不能同时存在
- 重载与具体的变量标识符无关,如method(int x)与method(int y)不是方法的重载。
- 重载的方法,实际是完全不同的方法,只是名称相同而已!
- 重载的方法参数列表必须不同
案例
-
李先生岁数的平方与他的夫人的岁数之和是1053,而他的夫人的岁数的平方与他的岁数之和是873,请编写程序计算李先生及其夫人的岁数各是多少,(先创建方法,然后调用)。
public class MetholdTest { public static void main(String[] args){ getAge(); } //创建方法 public static void getAge() { for (int a = 1;a < 40; a++) { for (int b = 1;b < 40; b++) { if (a*a+b==1053&&b*b+a==873) { System.out.println("李先生的年龄为:"+a+"\t李夫人的年龄为:"+b); } } } } }
-
判断数组中是否有重复元素(作业题2——使用方法简化)
/** * 编程大赛即将拉开序幕, * 由于人选有限,将选出10人参加全国大赛, * 为了体现公平的原则,采用如下的方法实现抽签: * 随机生成0到1000的整数,其中能被3整除的就是幸运儿之一 * 并将其存储起来,直到第十个幸运儿产生为止, * 最后将这10个人的幸运号按从小到大排序, * 并按照逆序打印出来。 * 思路: * int[] arr = new int[10]; * Random random = new Random(); int lucky = random.nextInt(1001); * %3 == 0 * 去重:思路参考上一题 * Arrays.sort(arr); * for(int i = arr.length - 1; i >= 0; i --) */ import java.util.Random; import java.util.Arrays; public class Hw2Method{ public static void main(String[] args){ int[] arr = new int[10]; // 保存十个幸运儿的编号 Arrays.fill(arr,-1);// 数组元素的默认值是0,设置为-1,避免影响0号幸运儿 Random random = new Random(); // 生成随机数,筛选出幸运儿,存入数组中 for(int i = 0; i < arr.length;){ // 生成随机数 int lucky = random.nextInt(1001); // 筛选:能被3整除,且不重复 if(lucky%3==0 && !isExist(arr,lucky)){ arr[i] = lucky; // 幸运儿,收入囊中 i ++; // 下一个 } } // 升序排序 Arrays.sort(arr); // 倒序输出 for(int i = arr.length - 1; i >= 0; i --){ System.out.print(arr[i]+" "); } } /** * 判断数组arr中是否包含指定元素num * 如果包含,则返回true;否则返回false */ public static boolean isExist(int[] arr, int num){ for(int i = 0; i < arr.length; i ++){ if(arr[i] == num){ // 存在 return true; // 将结果返回,return会结束该方法 } } // 代码能执行到这里,说明循环体里的return没有执行 return false; // 不存在 } }
-
定义方法,遍历二维数组
/** * 定义方法,遍历二维数组 */ public class Hw3{ public static void main(String[] args){ int[][] arr ={{1,2},{3,4,5},{6,7,8,9}}; printArr(arr); } /** * 参数列表:给方法提供一个int二维数组 * 返回类型:遍历的方法,打印出来即可,不需要返回数据,所以void * 方法名:见名知意 * 单一职能原则:该你做的事情做完整,不该你做的事情,不要掺和 */ public static void printArr(int[][] arr){ for(int i = 0; i < arr.length; i ++){ // 内层循环遍历一维数组 for(int j = 0; j < arr[i].length; j ++){ System.out.print(arr[i][j]+" "); } System.out.println();// 换行 } } }
-
封装一份方法,接受两个整数和一个操作符,根据操作符做相应的和差积商,并返回结果
/** * 封装一份方法,接收两个整数和一个操作符, * 根据操作符做相应的和差积商,并返回结果。 */ import java.util.Scanner; public class Hw4{ public static void main(String[] args){ Scanner input = new Scanner(System.in); System.out.println("请输入一个整数"); int a = input.nextInt(); System.out.println("请输入一个操作符(+ - * /)"); char c = input.next().charAt(0); // 取出字符串中的第一个字符 System.out.println("请再输入一个整数"); int b = input.nextInt(); double res = calc(a,b,c); System.out.println("res = "+ res); } /** * 参数列表:两个int,一个char * 返回类型:因为涉及到除法,所以double * 方法名:calc */ public static double calc(int a, int b, char c){ switch(c){ case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return 1.0 * a / b; // 整数相除:① 小数部分会丢失;② 0不能作除数 default : System.out.println("Are you kidding?"); return -99999999; // 因为目前知识有限,所以处理方式简陋,后期用异常来处理 } } }
-
写一个方法,从键盘输入一个整数,如果输入的不是整数,则提示输入有误,请重新输入,直到输入正确为止
/** * 写一个方法,从键盘输入一个整数, * 如果输入的不是整数,则提示输入有误,请重新输入, * 直到输入正确为止 */ import java.util.Scanner; public class Hw5{ public static void main(String[] args){ int num = inputNum(); System.out.println("num = "+ num); } /** * 功能:获取键盘输入的整数,如果不是整数,则没完 * 参数列表:键盘输入,不需要外部传入,无参 * 返回类型:int * 方法名:inputNum */ public static int inputNum(){ Scanner input = new Scanner(System.in); System.out.println("请输入一个\"数字\""); do{ String str = input.next(); // 判断num是否全由数字组成 boolean res = isNum(str); if(res == true){ // * 把字符串转化为数字 int num = Integer.parseInt(str); return num; }else{ // 提示用户重新输入 System.err.println("请重新输入!"); } }while(true); } // 判断一个字符串是否全由数字组成 public static boolean isNum(String str){ // String --> char[] char[] cs = str.toCharArray(); // "abc" --> {'a','b','c'} for(int i = 0; i < cs.length; i ++){ if(cs[i]<'0' || cs[i]>'9'){ // 包含数字之外的字符 return false; // 不是数字 } } return true; // 该字符串全是由数字字符'0'~'9'组成的 } }
练习题:三要素 + 逻辑
-
1、求斐波那契数列中第n个数
/** * 功能:求斐波那契数列中第n项的值 * 参数列表:需要我们提供什么 —— 第几项 n int类型 * 返回类型:我们想要得到什么 —— 斐波那契数列第n个值 int类型 * 方法名:起个一目了然的名字 —— fibo 代表fibonacci */ public static int fibo(int n){ int[] arr = new int[n]; arr[0] = 1; arr[1] = 1; for(int i = 2; i < arr.length; i ++){ arr[i] = arr[i-1] + arr[i-2]; } return arr[n-1]; // 第20个数的下标是19,所以-1 }
2、输入宽高,调用方法打印出空心矩形
比如输入3,5,则输出3行5列的空心矩形
* * * * *
* *
* * * * *
public static void print(int row, int col){ // 行数,列数
for(int i = 0; i < row; i ++){
// 打印一行星星
for(int j = 0; j < col; j ++){
// 如果是四条边:第一行、最后一行、第一列、最后一列,都是打印星
if( i == 0 || i == row-1 || j == 0 || j == col-1){
System.out.print("* ");
}else{ // 其它部分,打印空格
System.out.print(" ");
}
}
System.out.println();// 换行
}
}
3、求某个年份是否闰年
3、求某年某月有几天
// 年、月 ==> 天数
public static int getDay(int y, int m){
switch(m){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
return y%4==0&&y%100!=0 || y%400==0 ? 29 : 28;
default :
System.err.println("Are you kidding me?");
return -1;
}
}
4、求某数的阶乘
// 10 ==> 3628800
public static int fact(int n){
int res = 1;// 相乘,所以是1; 如果是相加求和,应该是0
for(int i = 1; i <= n; i ++){
res *= i;
}
return res;
}
5、输入两个整数和一个操作符,根据操作符做相应的和差积商
6、打印九九乘法表
7、产生10个5-9之间的随机数
8、求一个对称二维数组对角线所有元素的和
/**
* 求一个对称二维数组(n行n列)对角线所有元素的和
*/
public class Ex3{
public static void main(String[] args){
int[][] arr = { // 3行3列
{1,2,3},
{4,5,6},
{7,8,9}
};
int[][] brr = { // 4行4列
{1,2,3,4},
{5,6,7,8},
{9,0,1,2},
{3,4,5,6}
};
int sum1 = sum(arr);
int sum2 = sum(brr);
System.out.println("sum1 = "+sum1); // 应该为25 1 + 5 + 9 + 3 + 7
System.out.println("sum2 = "+sum2); // 应该为28 1+6+1+6+4+7+0+3
}
public static int sum(int[][] arr){
int sum = 0;
for(int i = 0; i < arr.length; i ++){
for(int j = 0; j < arr[i].length; j ++){
// 【遍历】双层循环可以罗列出二维数组的每一个元素
// 【筛选】从所有元素中筛选出两条对角线上的元素,相加
if(i == j || i + j == arr.length-1){
sum += arr[i][j];
}
}
}
return sum;
}
}
9、输入正整数,返回十六进制形式的结果。用户输入28,输出的是0x1C
// 28 ==> 0x1C
/**
* 输入正整数,返回十六进制形式的结果。
* 用户输入28,输出的是0x1C
* 思路:
* 十进制如何转化为十六进制
* 转化为十六进制时,得到的余数是0~15,如何转化为0~F?
*/
import java.util.Scanner;
public class Ex4{
public static void main(String[] args){
/*
* 数据输入阶段
*/
Scanner input = new Scanner(System.in);
System.out.println("请输入一个正整数");
int num = input.nextInt();
/*
* 数据处理阶段
*/
String res = toHex(num);
/*
* 结果反馈阶段
*/
System.out.println("十六进制:"+res);
}
public static String toHex(int num){
int[] yuArr = new int[8]; // 长度是几合适呢?
//分析:int 32个bit位,一个十六进制位==4bit位,int == 8个十六进制位
// 十 --> 十六
int i = 0;
while(num > 0){
int yu = num%16;// 取余
num /= 16;
yuArr[i++] = yu;
//System.out.print(yu+" ");
// 由于先得到的余数是最低位,因此需要倒着输出。所以先暂存到数组中,然后倒序该数组
}
// 0~15 --> 0~F
char[] cs = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
// 第一个非0字符前面的0都要去掉(不打印),之后的0都要打印
// 开头应该加前缀
String res = "0x";
boolean isPrint = false;// 标记是否可以开始打印
for(int j = 7; j >= 0; j --){
if(yuArr[j] != 0){
isPrint = true;// 可以开始打印了
}
if(isPrint){
res += cs[yuArr[j]];
}
}
return res;
}
}
10、*李白街上走,提壶去买酒.遇店加一倍,见花喝一斗,三遇店和花,喝光壶中酒.借问此壶中,原有多少酒?
11、*24点游戏:从扑克牌中随便抽出4张牌(不含大小王),通过加减乘除四则运算,求出结果为24点的表达 式。备注:不考虑四则运算顺序,从前往后依次运算即可。
比如1+2+3*4 等价于 ((1+2)+3)*4 == 24
【提示:4个扑克牌坑(允许重复的13选4),3个运算符坑(允许重复的4选3)】