一、方法
1 方法的概述
我们在学习运算符的时候,都为每个运算符单独的创建一个新的类和main方法,我们会发现这样编写代码非常的繁琐,而且重复的代码过多。能否避免这些重复的代码呢,就需要使用方法来实现。
方法(method):就是将一个功能抽取出来,把代码单独定义在一个大括号内,形成一个单独的功能。
当我们需要这个功能的时候,就可以去调用。这样即实现了代码的复用性,也解决了代码冗余的现象。
2 方法的定义
定义格式:
修饰符 返回值类型 方法名 (参数列表){//方法的声明
代码… //方法体
}
或者
修饰符 返回值类型 方法名 (数据类型 变量名, 数据类型 变量名…){//方法的声明
代码… //方法体
return 返回值
}
定义格式解释:
方法名:为我们定义的方法起名,满足标识符的规范,用来调用方法。
参数列表: 目前无参数。
举例:
public static void methodName() {
System.out.println("这是一个方法");
}
//main方法:这是java程序的入口地址,java虚拟机运行程序的时候首先找的就是main方法
public static void main(String[] args) {
}
public static void main(String args[]){
}
//两种写法都是一样的,都表示字符串数组args,其中args只是普通变量名,可以随意定义(前提是符合变量名规则)
main方法参数必须为字符串数组(String [ ]),变量名可以随意,通常使用args即是arguments(”参数“的复数形式)的缩写。
public:表示的这个程序的访问权限,表示的是任何的场合可以被引用,这样java虚拟机就可以找到main()方法,从而来运行javac程序
static:表明方法是静态的,不依赖类的对象的,是属于类的,在类加载的时候main()方法也随着加载到内存中去
void:main()方法是不需要返回值的 main:约定俗成,规定的 String[] args:从控制台接收参数
3 方法的调用
方法在定义完毕后,方法不会自己运行,必须被调用才能执行,我们可以在主方法main中来调用我们自己定义好的方法。在主方法中,直接写要调用的方法名字就可以调用了。
public static void main(String[] args) {
//调用定义的方法method
method();
}
//定义方法,被main方法调用
public static void method() {
System.out.println("自己定义的方法,需要被main调用运行");
}
4 方法的注意事项
方法定义注意事项:
方法必须定义在一个类中方法外
方法不能定义在另一个方法的里面
public class Demo {
public static void main(String[] args){
}
//正确写法,类中,main方法外面可以定义方法
public static void method(){}
}
public class Demo {
public static void main(String[] args){
//错误写法,一个方法不能定义在另一方法内部
public static void method(){}
}
}
2.2 定义方法的格式详解
修饰符 返回值类型 方法名(数据类型 变量名, 数据类型 变量名…) {
代码;
return 返回值;
}
修饰符: public static 固定写法
返回值类型: 表示方法运行的结果的数据类型(包括Void,string,基本数据类型和引用数据类型)
方法名: 满足标识符规范,见名知意。
(数据类型 变量名, 数据类型 变量名…): 参数列表,未知数据作为参数列表。
参数列表:方法在运算过程中的未知数据(可定义为形参变量),调用者调用方法时传递的已知数据(可定义为实参变量);注意参数的数据类型
return:将方法执行后的结果带给调用者,方法执行到 return ,整体方法运行结束
(return 返回值; 1.结束方法 2.将结果返回到方法调用的地方)
小贴士:return 结果; 这里的"结果"在开发中,我们正确的叫法成为方法的返回值
实参(实际参数): 在调用方法的时候传入的值,是具体的值
形参(形式参数): 在方法定义的地方写参数, 没有具体的值
2.3 定义方法的两个明确
需求:定义方法实现两个整数的求和计算。
明确返回值类型:方法计算的是整数的求和,结果也必然是个整数,返回值类型定义为int类型。
明确参数列表:计算哪两个整数的和,并不清楚,但可以确定是整数,参数列表可以定义两个int类型的变量,由调用者调用方法时传递
定义一个方法最主要关注的2点:
1.返回值类型: 根据方法的功能,方法的结果是什么类型,就返回什么类型
2.参数列表: 根据方法的功能,未知数据作为参数列表
/*
定义方法实现两个整数的求和
定义方法的2个明确
1.明确返回值类型, 2个整数求和,返回值是整数
2.明确参数列表, 不知道哪2个数求和.int a, int b
调用方法(有返回值的方法):
1.单独调用没有意义
2.保存结果(推荐)
*/
public class Demo04 {
public static void main(String[] args) {
// 单独调用
// getSum(5, 6);
// 保存结果
int sum = getSum(5, 6);
System.out.println("sum = " + sum);
}
public static int getSum(int a, int b) {
int c = a + b;
return c;
}
}
程序执行,主方法 main 调用 getSum 方法,传递了实际数据 5和6 ,两个变量 a和b 接收到的就是实际参数,并
将计算后的结果返回,主方法 main 中的变量 sum 接收的就是方法的返回值。
2.4 调用方法的流程图解
2.5 调用方法的三种形式
直接调用:直接写方法名调用
直接调用: 方法名(参数); 没有对返回值进行处理
注意:没有返回值的方法,只能直接调用
赋值调用:调用方法,在方法前面定义变量,接收方法返回值
赋值调用: 数据类型 变量名 = 方法名(参数); 会保存方法的结果,可以打印,也可以做其他操作。
注意:方法返回值是什么类型,我们就用什么类型的变量来接收
输出语句调用:在输出语句中调用方法, System.out.println(方法名()) 。
输出调用: System.out.println(方法名(参数)); 打印出方法的结果
注意:不能用输出语句调用 void 类型的方法。
因为方法执行后没有结果,也就打印不出任何内容,出现编译时错误,若运行,则出现此处不允许使用 ‘空’ 类型的错误提示。
2.6 定义方法练习
练习一
比较两个整数是否相同
明确返回值:比较整数,结果只有两种可能,相同或不同,因此结果是布尔类型。
明确参数列表:比较的两个整数不确定,所以默认定义两个int类型的参数。
练习二
计算1+2+3…+100的和
明确返回值:1~100的求和,计算后必然还是整数,返回值类型是int
明确参数:需求中已知到计算的数据,没有未知的数据,不定义参数
练习三
实现不定次数打印HelloWorld
明确返回值:方法中打印出 HelloWorld 即可,没有计算结果,返回值类型 void 。
明确参数:打印几次不清楚,参数定义一个整型参数
2.7 定义方法的注意事项
定义位置,类中且其他方法的外面。
调用方法时写错方法名字。
调用方法时写错了参数列表。
返回值类型,必须要和 return 语句返回的类型相同,否则编译失败 。
不能在 return 后面写代码, return 意味着方法结束,所有后面的代码永远不会执行,属于无效代码,出现编译时错误。
2.8 方法重载
定义2个int数求和,定义3个int数求和
我们发现2个数求和,3个数求和功能是一样的.如果定义不同的方法名使用起来不方便.最好取相同的名称,就像人的吃饭功能.不管是吃面,还是吃米饭.都叫吃饭功能。
方法重载(overload):指在同一个类中,方法名相同,参数列表不同,与修饰符和返回值类型无关。
参数列表:个数不同,数据类型不同(看类型,不看变量名),顺序不同;和参数的变量名无关。
重载方法调用:JVM通过方法的参数列表,调用不同的方法。
重载方法的执行:根据传入参数的类型,去找到对应的方法
public class Demo07 {
public static void main(String[] args) {
add((byte)10 ,(byte)20); // byte byte
add(10 ,20); // int int
add(10, 20, 30); // int int int
}
/* public static double add(byte x, int y) {
int sum = x + y;
return sum;
}*/
// 定义2个byte数求和
public static double add(byte a, int b) {
int sum = a + b;
return sum;
}
// 定义2个byte数求和
public static int add(int a, byte b) {
int sum = a + b;
return sum;
}
// 定义2个byte数求和
public static int add(byte a, byte b) {
System.out.println("byte byte");
int sum = a + b;
return sum;
}
// 定义2个int数求和
public static int add(int a, int b) {
System.out.println("int int");
int sum = a + b;
return sum;
}
// 定义3个int数求和
public static int add(int a, int b, int c) {
System.out.println("int int int");
int sum = a + b + c;
return sum;
}
// 定义4个int数求和
public static int add(int a, int b, int c, int d) {
int sum = a + b + c + d;
return sum;
}
}
2.9 方法重载练习
练习一
比较两个数据是否相等。参数类型分别为两个 byte 类型,两个 short 类型,两个 int 类型,两个 long 类型,并在 main 方法中进行测试。
练习二
判断哪些方法是重载关系。
//判断哪些方法是重载关系
public class MethodDemo03 {
public static void open(){}
public void open(int a){}
public void open(int a,int b){}
public void open(double a,int b){}
public static void open(int a,double b){}//和上一个方法的参数的数据类型顺序不同,和下一个方法的参数的数据类型相同。
// public void open(int i,double d){}//和上一个方法的参数列表相同.都是 int,double,编译失败
public static void OPEN(){}//方法名不同
}
第三章 java中常用的方法
https://blog.csdn.net/qq15577969/article/details/84315479
第四章 方法的扩展
1、方法中的变量作用域:
- 成员变量:整个类。
- 局部变量:定义起到方法块结束为止。
- 方法参数:整个方法或者构造方法。
- 异常处理参数:参数传递给异常处理方法。
2、Java中的方法分类
https://www.cnblogs.com/bless2016/p/4531533.html
4、方法的重写
重写 (Override)。
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写或者覆盖。方法声明不变,方法体重新实现。
第五章 可变参数
在JDK1.5之后,如果我们定义⼀个⽅法需要接受多个参数,并且多个参数类型⼀致,我们可以对其简化成如下格式:
修饰符 返回值类型 ⽅法名(参数类型… 形参名){ }
其实这个书写完全等价与:修饰符 返回值类型 ⽅法名(参数类型[] 形参名){ }
只是后⾯这种定义,在调⽤时必须传递数组,⽽前者可以直接传递数据即可。
JDK1.5以后。出现了简化操作。… ⽤在参数上,称之为可变参数。
同样是代表数组,但是在调⽤这个带有可变参数的⽅法时,不⽤创建数组(这就是简单之处),直接将数组中的元素作为实际参数进⾏传递,其实编译成的class⽂件,将这些元素先封装到⼀个数组中,在进⾏传递。这些动作都在编译.class⽂件时,⾃动完成了。
可变参数概述
* 方法的参数个数可以是任意个,0到n个
* JDK1.5新特性
* 格式:数据类型…变量名
* 本质:数组
注意事项
* 一个方法的参数列表中最多只能有一个可变参数且可变参数必须是参数列表的最后一个
代码演示:
package 方法.可变参数;
public class ChangeArgsDemo01 {
public static void main(String[] args) {
int[] arr = { 1, 4, 6, 1, 2 };
int sum = getSum(arr);
System.out.println(sum);//14
int sum2 = getSum(1, 4, 6, 1, 2);
System.out.println(sum2);//14
}
//定义一个方法完成数组所有元素的求和
//原始写法
/* public static int getSum(int[] arr) {
int sum = 0;
*//* for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}*//*
for (int num : arr) {
sum += num;
}
return sum;
}*/
//可变参数写法
public static int getSum(int... arr) {
int sum = 0;
for (int a : arr) {
sum += a;
}
return sum;
}
}
tips: 上述getSum⽅法在同⼀个类中,只能存在⼀个。因为会发⽣调⽤的不确定性
int… arr相当于int[] arr = new arr[0]
注意:如果在⽅法书写时,这个⽅法拥有多参数,参数中包含可变参数,可变参数⼀定要写在参数列表的末尾位置。
可变参数判空的注意事项
public class Test {
public static void main(String[] args) {
int a = 1;
String b = null;
//testA(a,b);
testA(a);
}
private static void testA(int a, String… b) {
System.out.println(b == null);//false
System.out.println(b.length) ;//1
System.out.println(b[0] == null);//true
}
}
如果不传实参b,则长度为0:
可以通过循环可变参数数组判断是否为null。
第六章 方法递归
6.1 概述
递归的概念
* 方法内部调用方法自身
指在当前方法内调用自己的现象
递归的分类
* 直接递归:方法A调用方法A
* 间接递归:方法A调用方法B,方法B调用方法C,方法C调用方法A
递归的使用注意事项
* 递归必须要有出口:结束递归的条件
* 递归次数不要太多
java.lang.StackOverflowError:栈内存溢出错误
用递归编写程序时一定要牢记两点:1. 递归公式;2. 收敛条件(什么时候就不再继续递归)。
package 方法.方法递归;
/**
-
直接递归
*/
public class DGDemo04 {static int index = 0;
public static void main(String[] args) {
System.out.println(“main =”+index++);//0
testA();
System.out.println(“main =”+index++);//7
}private static void testA() {
if (index >=4) return;
System.out.println(“testA=”+index++);//1
testB();
System.out.println(“testA=”+index++);//6
}private static void testB() {
System.out.println(“testB=”+index++);//2
testC();
System.out.println(“testB=”+index++);//5
}private static void testC() {
System.out.println(“testC=”+index++);//3
testA();
System.out.println(“testC=”+index++);//4
}
}
package 方法.方法递归;
/**
-
直接递归
*/
public class DGDemo05 {
static int index = 0;
public static void main(String[] args){
System.out.println("main = " + index++); // 0
testA();
System.out.println("main = " + index++); // 7
}public static void testA(){
if (index >= 4) return;
System.out.println("testA = " + index++); // 1 2 3 4
testA();//1 2 3 / 2 1 注意:返回之前调用的方法处继续执行下面的代码
System.out.println("testA = " + index++); // 5 6
}
}
6.2 递归累和
package 方法.方法递归;
/**
递归练习:求1到n的和
比如n = 5,求1到5之和
sum(5) = 1 + 2 + 3 + 4 + 5 = sum(4) + 5;
sum(4) = 1 + 2 + 3 + 4 = sum(3) + 4;
sum(3) = 1 + 2 + 3 = sum(2) + 3;
sum(2) = 1 + 2 = sum(1) + 2;
sum(1) = 1;
sum(n) = n + sum(n - 1)
*/
public class DGDemo01 {
public static void main(String[] args) {
System.out.println(sum(5));//15
System.out.println(sum2(5));//15
}
/*
求1到n的和
*/
public static int sum(int n) {
if (n == 1) {
return 1;
}
int result = n + sum(n - 1);
return result;
}
public static int sum2(int n) {
int sum = 0;
for (int i = 0; i <= n; i++) {
sum += i;
}
return sum;
}
}
6.3递归求阶乘
package 方法.方法递归;
public class DGDemo02 {
public static void main(String[] args) {
System.out.println(jc(5));//120
System.out.println(jc2(5));//120
}
/*
求1到n的和
*/
public static int jc(int n) {
if (n == 1) return 1;
int result = n * jc(n - 1);
return result;
}
public static int jc2(int n) {
if (n == 1) return 1;
int aa = 1;
for (int i = 2; i <= n; i++) {
aa *=i;
}
return aa;
}
}
6.4 递归打印多级目录
分析:多级目录的打印,就是当目录的嵌套。遍历之前,无从知道到底有多少级目录,所以我们还是要使用递归实现。
package 方法.方法递归;
import java.io.File;
public class DGDemo03 {
public static void main(String[] args) {
// 创建文件对象关联目标文件夹
File dir = new File(“c:/ccc/bbb”);
printFileName(dir);
}
/**
* 打印指定文件夹下所有的java文件名(包括子文件夹)
*/
public static void printFileName(File dir) {
// 判断是否是文件夹,不是,则直接返回
if (dir.isFile()) return;
// 获得文件夹dir下所有的文件
File[] files = dir.listFiles();
// 遍历文件数组
for (File file : files) {
// 判断是否是文件
if (file.isFile() && file.getName().endsWith(".java")) {
System.out.println(file.getName());
} else {
// file:文件夹
printFileName(file);
//System.out.println("xxx");
}
}
}
}
递归打印目录层级结构:
递归删除文件夹图解:
递归统计文件夹大小: