企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
# Java方法 [TOC] ## 导学 什么是方法,其实我们从一开始就接触到了方法。这个方法就是我们的主方法。主方法是一个比较特殊的方法,它是程序执行的入口。之前我们还提到可以使用`.`去调用方法,像`System.out.println();`中,`println()`就是一个方法。 所谓方法(函数),**就是就是用来解决一类问题的代码的有序组合,是一个功能模块。** ## 方法声明 语法: ~~~ 访问修饰符 返回类型 方法名(参数列表) { 方法体 } ~~~ 示例: ~~~ public static void main(String[] args) { System.out.println("Hello,World!"); } ~~~ 访问修饰符就是方法允许被访问的范围;返回类型可以是void和其他任何类型的数据(包括自己创造的数据类型);方法名需要满足标识符的全部规则外还需要满足驼峰原则;参数列表可以省略,既没有参数,同样参数可以有多个,每个参数之间使用逗号间隔,参数由数据类型和参数名构造,类似变量的定义; 根据参数和返回值,方法可以分为四类: 1. 无参无返回值 2. 无参有返回值 3. 带参无返回值 4. 带参有返回值。 本节课我们就根据这四个分类来给大家介绍方法的具体信息。 ## 方法类型 ### 无参无返回值方法 首先我们来看一道例题,打印如下所示的图形 ![](https://img.kancloud.cn/dc/ff/dcff55ca04a92c1935bdc52d6f46100b_558x130.png) 这样的图形只需要使用`System.out.println()`就可以打印输出出来,但是我们发现该例题会要求我们进行重复的打印输出该图形。对于这样一种重复的行为,我们希望将这条打印语句放置在一个方法里面,然后每次遇到同样的要求,只需要调用方法就可以了。 那么,方法的使用意义就出来了,我们希望使用方法来减少代码的量!就如同我们之前给大家讲过冒泡排序的问题,如果我们每次遇到要冒泡排序的问题,只需要调用一个方法,是不是就方便很多。 ~~~ public class One { // 打印输出星号的方法 public void printStar() { System.out.println("********************************"); } // 一行打印输出一串星号 public static void main(String[] args) { //创建一个One类的对象MyOne One MyOne=new One(); //使用对象名.方法名()去调用方法 MyOne.printStar(); System.out.println("欢迎来到Java的世界!"); MyOne.printStar(); } } ~~~ 在本章节中,我们会碰到很多的概念和语法,这些概念和语法需要我们同学反复记忆。其实关于这些概念和语法的问题没有为什么,Java的语法规则就是这么规定的,编译器就只认这些语法。 ### 无参有返回值的方法 我们依旧通过一个例题完成: **求一个长宽都是整数的长方形面积?** ~~~ public class Rectangle { public int area() { int length=10; int width=5; int area=length*width; return area;//返回语句,变量名和方法名可以一致,同时注意方法返回值需要和规定的返回值一致。 } public static void main(String[] args) { Rectangle rc=new Rectangle(); System.out.println("长方形的面积为:"+rc.area()); } } ~~~ 什么是返回值,返回值其实是本方法求得的结果,这个结果最终可能为其他方法或代码块所需要,那么为了将该结果传递出去,就需要使用返回值将得出的结果传递出去。 ### 带参无返回值方法 例题: **定义一个求两个float类型的数据最大值的方法,在方法中将最大值打印输出** ~~~ public class MaxDemo { public void max(float a, float b) {//形式参数(形参) float max; if(a > b) { max = a; } else { max = b; } System.out.println("最大值为:" + max); } public static void main(String[] args) { MaxDemo md = new MaxDemo(); md.max(1.1, 1.3);//实际参数(实参) } } ~~~ 局部变量的范围只限于定义它的大括号中,传递数值时主方法中可以是变量,也可以是一个字面值,不同类型传递会出现类型转换。 ### 带参有返回值的方法 例题: 定义一个求n!的方法,然后再求1!+ 2!+3!+4!+5! n!是指阶乘,5的阶乘就是`1*2*3*4*5` ~~~ public class Four { //方法不能嵌套定义 //求阶乘的方法 public int fac(int n) { int s=1; for(int i=1;i<=n;i++) { s*=i;//s=s*i; } return s; } public static void main(String[] args) { Four four=new Four(); int fac=four.fac(3); System.out.println("3!="+fac); int sum=0; //求1!+2!+3!+4!+5! for(int i=1;i<=5;i++){ fac=four.fac(i); sum+=fac; } System.out.println("1!+2!+3!+4!+5!="+sum); } } ~~~ 方法的定义必须定义在类的里面,但是不能定义在另外一个方法的里面。方法不能嵌套,带有返回值的方法是为了参与进一步的运算 ## 数组作为方法参数 ### 示例一 例题: **定义方法,打印输出数组元素的值。** ~~~ public class Five { //打印输出数组元素的值 public void printArry(int[] arr) { for(int i=0;i<arr.length;i++) { System.out.print(arr[i]+" "); } System.out.println(); } public static void main(String[] args) { int[] arr= {10,20,30,40,50,}; Five am=new Five(); am.printArry(arr); } } ~~~ ### 示例二 例题: **查找数组元素的值:** ~~~ public class ArraySearch { //方法参数:数组、要查找的元素 //返回值:Boolean类型 public boolean search(int n,int[] arr) { boolean flag = false; for (int i = 0; i < arr.length; i++) { if(arr[i]==n) { flag=true; } } return flag; } public static void main(String[] args) { int[] a= {10,20,30,40,50,60}; int b = 30; ArraySearch as = new ArraySearch(); boolean flag = as.search(b, a); if(flag) { System.out.println("存在数据"); } else { System.out.println("存在数据"); } } } ~~~ ## 方法重载 方法重载简单概括就是方法名相同,参数列表不同。 ![](https://img.kancloud.cn/0f/c4/0fc46df14c82f638e3585587670ad1bd_543x269.png) 例题: **定义三个方法,实现int、double和数组类型求和的问题** ~~~ public class MathDemo { //求两个int类型数的和 public int plus(int m,int n){ return m+n; } //求两个double类型数的和 public double plus(double m,double n){ return m+n; } //求数组元素的累加和 public int plus(int[] arr){ int sum=0; for(int i=0;i<arr.length;i++){ sum=sum+arr[i]; } return sum; } public static void main(String[] args) { int m=5,n=10; int[] arr={1,2,3,4,5,6}; MathDemo mathDemo=new MathDemo(); System.out.println("int类型的和:"+mathDemo.plus(m,n)); System.out.println("double类型的和:"+mathDemo.plus(5.6,7.8)); System.out.println("数组元素的和:"+mathDemo.plus(arr)); } } ~~~ ## 方法的传值 ### 基本数据类型的传值 例题: **对两个变量的值进行交换并打印输出(传值问题)** ~~~ public class ExchangeDemo { //交换方法 public void swap(int a,int b){ int temp; System.out.println("交换前:a="+a+","+"b="+b); temp=a; a=b; b=temp; System.out.println("交换后:a="+a+","+"b="+b); } public void swapTest(){ //ExchangeDemo ex=new ExchangeDemo(); //普通方法调用方法不需要定义对象,直接调用即可 方法名(实参); int m=4,n=5; System.out.println("交换前:m="+m+","+"n="+n); swap(m,n); System.out.println("交换后:m="+m+","+"n="+n); } public static void main(String[] args) { ExchangeDemo ex=new ExchangeDemo(); ex.swapTest(); /*int m=4,n=5; System.out.println("交换前:m="+m+","+"n="+n); ex.swap(m,n); System.out.println("交换后:m="+m+","+"n="+n);*/ } } ~~~ 在方法运行之后,我们会发现,m与n的值并没有发生改变。 ![](https://img.kancloud.cn/58/dc/58dc8b2c4ff9dc1ebf32ab333afdfcae_286x350.png) 这是因为首先创建m,n变量,会在内存中开辟空间存储对应的值,然后在方法调用的时候把m和n的值传给变量a,b,这时候只是把4和5这两个值传过去了。并不是把m和n的内存地址传递过去了。 实际上,这道题目告诉我们,如果方法的参数是基本数据类型,那么在方法内对参数进行修改,不会影响到传递的实际参数。 ### 数组的传值 例题: **定义一个用于修改某个数组元素的方法** ~~~ public class Ten { //定义一个用于修改某个数组元素值的方法 public void updateArry(int[] a) { a[3]=15; System.out.println("数组a的元素为:"); for(int n:a) { System.out.print(n+" "); } System.out.println(); } public static void main(String[] args) { Ten b=new Ten(); int[] a1= {1,2,3,4,5}; System.out.println("方法调用前数组a1元素为:"); for(int n:a1) { System.out.print(n+" "); } System.out.println(); b.updateArry(a1); System.out.println("方法调用后数组a1元素为:"); for(int n:a1) { System.out.print(n+" "); } } } ~~~ 总结: 主方法中声明变量并传值到方法中,基本数据类型传值是把值传过去,没有传变量的地址,所以如果在普通方法中修改了变量的值,对主方法中的普通变量没有影响。但是如果主方法中声明的是数组(引用数据类型),则传值是把变量地址传过去了(传过去的是数组的第一个元素的地址),在普通方法中修改变量会影响主方法的变量。传值都是传的的变量里的值,基本数据类型的是值本身,引用类型的是对象的地址。但是数组可以修改对象里的东西,字符串不可以。 ## 可变参数列表 ### 什么是可变参数列表 示例: ~~~ public void sum(int...n) { } ~~~ 可变参数列表指的是参数的数量不固定,但是参数的类型是固定的,参数列表规定了是哪一种类型,随后的参数就只能是哪一种类型。 示例一: ~~~ public class Demo { //求和 public void sum(int...n) { int sum = 0; for(int i:n) {//其实我们可以将可变参数列表看作为一个数组 sum = sum + i; } System.out.println("sum="+sum); } public static void main(String[] args) { Demo de = new Demo(); de.sum(1); de.sum(1,2); de.sum(1,2,3); //de.sum(1,1.2);传入的必须是int类型 } } ~~~ 示例二: ~~~ public class ArgsDemo1 { //查找 public void search(int n,int...a){//参数列表中如果有两个或两个以上的参数,可变参数一定是在最后的。 boolean flag=false; for(int a1:a){ if(a1==n){ flag=true; break; } } if(flag){ System.out.println("找到了"+n); } else{ System.out.println("没找到"+n); } } /*public void search(int n, int[] a) { //可变参数方法换成数组是不算重载的,算重复定义 }*/ /*public void search(int n, int... a, int...b) { //一个方法中只能有一个可变参数。 }*/ public static void main(String[] args) { ArgsDemo1 ad1=new ArgsDemo1(); ad1.search(3,1,2,3,4,5); int[] a={1,2,3,4,5}; ad1.search(3,a);//可变参数列表可以和数组进行兼容,可以将数组传递给可变参数列表 } } ~~~ 总结: 1. 可变参数列表指的是参数数量是不确定的,可以随时变化。有时候也称可变原参数。 2. 参数列表中如果有两个或两个以上的参数,可变参数一定是在最后的。例如:`public void a(int a,int... b){ }`是正确的,但是如果把`int... b`写前面则是错误的。 3. 可以将数组传递给可变参数。 4. 一个方法中只能有一个可变参数。 5. 可变参数方法换成数组是不算重载的,算重复定义 ### 可变参数列表作为方法参数的重载问题 本节课,我们来看一下当进行方法重载时,可变参数列表方法,调用顺序的问题。 ~~~ public class Demo { public int sum(int a, int b) { System.out.println("不带可变参数列表的方法被调用"); return a + b; } //求和 public int sum(int...n) { int sum = 0; for(int i:n) {//其实我们可以将可变参数列表看作为一个数组 sum = sum + i; } System.out.println("带可变参数列表的方法被调用"); return sum; } public static void main(String[] args) { Demo de = new Demo(); System.out.println("和为:" + de.sum(1,2)); System.out.println("和为:" + de.sum(3,4)); System.out.println("和为:" + de.sum(3,4,5)); } } ~~~ 总结: 若有多个重载方法,则可变参数列表所在的方法是最后被访问的(如果主方法所传参数其他重载方法可以满足,则调用其他方法,只有其他方法都不满足,才会调用可变参数列表所在的方法) ## 再议文档注释 至此,对于方法的学习,我们已经完成的差不多了,接下来,我们再来看一看文档注释对于整个类使用的帮助 在 javadoc 中也提供了丰富的标记 * @author:指定程序的作者 * @version:指定源代码的版本 * @param:在方法中指定参数 * @return:在方法中指定返回值 ~~~ /** * <h2>可变参数列表方法重载的应用</h2> * @author 作者 * @version 版本号 */ public class Demo { /** * <p style="color:red">求和</p> * @param a 参数 * @param b * @return 返回值 */ public int sum(int a, int b) { System.out.println("不带可变参数列表的方法被调用"); return a + b; } } ~~~ 在文档注释中可以使用html标签,但是不能用自封闭的标签。 使用javadoc命令生成**API文档**,-d指定生成的目录地址。 ~~~ cmd中执行命令: javadoc -encoding utf-8 -d apidoc -version -author Demo.java ~~~ 在eclipse中执行生成doc文档 1. 在工具栏project选项中右键选择Generate Javadoc选项 ![](https://img.kancloud.cn/b7/a7/b7a7973187adb1687688d21acee2f3c0_589x46.png) 2. 可以选择生成整个项目的帮助文档和单独一个类的帮助文档,以及选择输出地址 ![](https://img.kancloud.cn/9c/0d/9c0d990eab98437d3ce9b697892a1720_616x609.png) 3. 生成标题 ![](https://img.kancloud.cn/57/f0/57f0918ce0f0eccad0e2fefa256e7630_616x609.png) 4. 输出文档 各位同学可以尝试学习Java jdk的帮助文档:[https://tool.oschina.net/apidocs/apidoc?api=jdk-zh](https://tool.oschina.net/apidocs/apidoc?api=jdk-zh) ## 方法的调试 在方法调用处打上断点。 ~~~ F5进入方法内部执行 F6单步执行 F7由方法内部跳回调用处 ~~~ ## 练习 一、选择 1. 下列代码的运行结果为: ![](https://img.kancloud.cn/17/48/1748882bce22720dbeaabae5ecb4e990_451x198.png) ~~~ A. 没有任何输出 B. 编译错误 C. 晓明今年7岁了 D. 晓明 ~~~ 2. 下列代码运行的结果是() ![](https://img.kancloud.cn/39/e8/39e8777af67bf81803969408fa5f92fc_448x296.png) ~~~ A. Hello,My name is Tom. B. Hello,My name is Peter. C. Hello,My name is Peter.My name is Tom. D. My name is Peter. ~~~ 3. 下列语句的执行结果为() ![](https://img.kancloud.cn/30/2d/302d5a8417882eaed4b998dbe77bed6f_447x245.png) ~~~ A. 运行异常 B. 运行错误 C. 我的英文名字叫Tom D. 什么都不输出 ~~~ 4. 下面这段程序的执行结果为: ![](https://img.kancloud.cn/d3/06/d306877ef0c2d19168c5a78ab5bb3f27_448x251.png) ~~~ A. 12 B. a+b+c=12 C. a+b+c=16 D. 16 ~~~ 5. 已知如下代码,则位置(1)处正确的方法调用代码为? ![](https://img.kancloud.cn/f7/c6/f7c64f58c3111b25733d9b5f8d0f3119_450x252.png) ~~~ A. method.display(arr); B. method.display(arr[0]); C. method.display(a); D. method.display(a[0]); ~~~ 6. 已知方法的定义形式如下:`public void plus(int a,int b){}` 下列选项中哪两个是合法的重载方法?(多选) ~~~ A. public int plus(int a){} B. public int plus1(int m,int n){} C. public void plus(float a,float b){} D. public int plus(int a,int b){} ~~~ 7. 下列代码,前者与后者是重载关系的是: ~~~ A. public void show(){}和public void show(int num){} B. public void show(){}和public void print(int num){} C. public void show(){}和public int show(){} D. public void show(int a){}和    public void show1(int b){} ~~~ 8. 以下代码的输出结果是什么? ![](https://img.kancloud.cn/06/15/0615e915e2a01c5556d311858cf93346_450x288.png) ~~~ A. 40 B. 8 C. 4 D. 10 ~~~ 9. 以下代码的输出结果是什么? ![](https://img.kancloud.cn/e5/1e/e51e43bbce98359ad4c4177d92beb004_446x349.png) ~~~ A. 2 B. 3 C. 4 D. 6 ~~~ 10. 关于可变参数列表的描述正确的是 ~~~ A. 当可变参数列表作为方法参数时,不能将数组传递给可变参数列表 B. 一个方法中,只能有一个可变参数列表作为参数 C. 重载的方法中,可变参数列表作为参数的重载方法不会优先被调用 D. 数组作为方法参数时,可以将多个值同时传递给数组 ~~~ 二、编程 1. 定义一个方法,根据商品总价,计算出对应的折扣并输出。折扣信息如下: * 总价<100,不打折 * 总价在100到199之间,打9.5折 * 总价在200以上,打8.5折 任务: 1、定义一个方法,根据商品总价输出折后总价 2、在主方法中定义对象 3、使用对象调用定义的方法 ~~~ public class DisCountDemo { //根据商品总价输出折后总价 public static void main(String[] args) { //定义对象 //定义商品总价存放到变量中 //调用方法,输出折后商品总价 } } ~~~ 2. 编写方法,求数组元素的平均值。 任务: 1、定义一个方法,求数组的平均值 2、在主方法中定义对象,并初始化一个float类型的数组,调用方法求数组元素的平均值,并将平均值打印输出 ~~~ public class AverageDemo { //求数组元素的平均值 public static void main(String[] args) { //定义对象 //创建float类型的数组并初始化 //调用方法求平均值并打印输出 } } ~~~ 3. 定义两个重载的方法,分别求圆和长方形的面积。 任务: 1、 定义两个求面积的重载方法,圆周率可以使用`Math.path`这个常量代替 2、在主方法中调用方法并输出 ~~~ public class AreaDemo { //求圆形面积 //求长方形面积 public static void main(String[] args) { //定义对象 //定义一个double类型的变量存放半径,并初始化 //定义两个变量存放长和宽,并初始化 //调用方法,求圆的面积并打印输出 //调用方法,求长方形面积并打印输出 } } ~~~