1. 方法
1.1 什么是是方法
方法就是一个功能模块的集合,讲很多行代码放置在一组{}中,形成一个代码块
可以提高代码的复用性.
注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法。
1.2 方法的格式
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…) {
方法体语句;
return 返回值;
}
- 修饰符:public protect 缺省 private
- 返回值类型:就是功能结果的数据类型
- 方法名:就是起了一个名字,方便我们调用该方法。
- 参数类型:就是参数的数据类型
- 参数名:就是变量
- 参数分类:
实参:实际参与运算的数据
形参:方法上定义的,用于接收实际参数的变量 - 方法体语句:就是完成功能的代码块
- return:结束方法
- 返回值:就是功能的结果,由return带给调用者。
1.3 参数列表
1.3.1完成两个数相加
public class Method02 {
public static void main(String[] args) {
add();
}
public static void add() {
int num1 = 20;
int num2 = 30;
int sum = num1+num2;
System.out.println("累加的和是:"+sum);
}
}
但是,這样只能对20和30进行加法计算,无法计算任意两个数,该方法的复用性不强,但是可以借助参数列表来完成.
1.3.2参数列表的使用
参数列表声明在方法名后的小括号中,可以声明0个或者是多个.
public class Method03 {
public static void main(String[] args) {
add(40,20);
}
//声明一个add方法 需要两个int类型的参数
public static void add(int num1,int num2) {
System.out.println(num1+num2);
}
}
- 参数列表的注意事项
- 将方法声明的参数列表称之为形式参数
- 对于调用者而言,传入的具体参数的值称之为实际参数
- 方法声明的参数列表中只存在声明不需要初始化就可以使用,原因是由于该方法被调用之后一定会将实际参数进行赋值.
- 方法调用者而言,在调用方法时不能只看方法名称,而且还需要查看方法的参数列表,只有这样才可以正确的调用到需要被调用的方法.
- 在一个类中确定方法通过方法签名完成.方法签名(方法名称+参数列表)
- 对于参数列表而言,具体长的参数类型、个数、顺序都有一定的要求,要求取决于业务逻辑
1.3 返回值
被调用的方法可以将自己最后的计算结果返回给调用处,方便后续的业务逻辑执行。返回值对于某些方法而言是极其有必要的。
public class Method06 {
public static void main(String[] args) {
int r = 10;//1:
double area = getCircleArea(r);//2 //8
}
public static double getCircleArea(int r) {//3
double pi = 3.14;//4
double area = pi*r*r;//5
System.out.println("半径"+r+"的圆的面积是:"+area);//6
return area;//7
}
}
- void:方法没有返回值
- 一个方法可以不存在void,但是一定要有内容去代替void所在的位置
- 一个方法存在返回值,该方法一定有return语句,return返回具体值
- 调用main方法,调用完成某个具有返回值的方法之后,可以通过变量接受该值.
1.4 方法的注意事项
- 方法的调用(有具体返回值)
- 单独调用,一般来说没什么意义
- 输出调用,但是不够好,因为可能选哟针对结果进行进一步操作
- 复制调用(推荐)
- 方法不调用不执行
- 方法与方法是平级关系,不能嵌套定义
- 方法定义的时候参数之间用逗号隔开
- 方法调用的时候不用在传递数据类型
- 如果方法有明确返回值,一定要有return语句
- 方法的功能尽可能单一,否则不利于后期维护
1.5 方法的重载
在同一个类中,同名的两个或者是多个方法,参数列表不同,我们称该多个方法为方法重载。
重载在编码过程中是有意义的,针对于不同的参数做相同的功能。
两同三不同:同类 同名 参数列表不同(个数、类型、顺序) 注意返回类型和重载无关。
附加知识:在jvm中确定一个方法的方式是:返回值类型+方法名称+参数列表。java编程规范和JVM规范。
public class Method08 {
public static void main(String[] args) {
add(1,2);
}
//计算10和20的和
public static void add() {
int num1 = 10;
int num2 = 20;
System.out.println(num1+num2);
}
//计算传入的两个参数的和
public static void add(int num1,int num2){
System.out.println(num1+num2);
}
public static void add(int num1){
System.out.println(num1+20);
}
public static void add(int num1,byte num2){
System.out.println(num1+num2);
}
public static void add(byte num1,int num2){
System.out.println(num1+num2);
}
}
2.变量的分类
变量的三要素:数据类型 变量名 生命周期(作用范围)
按照变量声明的位置不同,将变量分为局部变量和成员变量
变量的分类 | 变量的声明 | 作用范围 | 注意事项 |
---|---|---|---|
局部变量 | 声明在方法中或者是代码块中。方法参数列表是属于该方法的局部变量。 | 当前声明的{}中有效 | 生命周期一定要先声明然后赋值,最后才能使用。 |
成员变量 | 声明在类中,方法外的变量。 | 当前类中都有效 | 生命周期调用时需要:要么将当前的成员变量前加static修饰;要么就是通过创建当前类的所属对象,通过对象访问。无需初始化,每个不同类型的变量都存在默认值。 |
局部变量
定义在方法中或者是代码块中的变量,称之为局部变量,局部变量的生命周期只能在声明的{} 中有效。出了这个位置就没有任何效果。方法的参数列表中的变量属于当前方法的局部变量。
public class Test01 {
public static void main(String[] args) {
//int num = 10;
//System.out.println("main"+num);
{
int num = 10;
System.out.println("代码块"+num);
}
int num = 10;
System.out.println("访问代码块"+num);
}
}
代码块而言,通过一组大括号括起来 {} 代码块也分为:局部代码块、初始化块、静态代码块。
局部代码块:声明在方法中的代码块。局部代码块中声明的变量只能在当前局部代码块中有效。
局部代码块的优势:
1:缩减了变量的生命周期。
2:提高内存的使用率,降低内存开销
成员变量
声明在类中,方法外的变量称之为成员变量
public class Test02 {
static int num = 10;//堆
int rt = 20;
public static void main(String[] args) {
System.out.println("访问1:"+num);
int num = 20;
System.out.println("访问2:"+num);
Test02 t = new Test02();
System.out.println(t.rt);
}
public static void method() {
System.out.println(num);
}
}
- 成员变量可以不初始化就能够直接使用
- 所有的整数(byte、short、int、long) ----> 默认值是0
- 所有的小数(float、double) -----> 默认值是0.0
- 字符类型(char) -----> 默认值是空格 ( \u0000 )
- boolean 类型 ------> 默认值是false
- 所有的引用类型的默认值 ------> 默认值是null
3.递归
递归是一种编程技巧,程序中自己调用自己。在递归程序中最重要的问题是:何时出递归程序。在递归程序中存在一个出口–>递归头。
递归程序的最大优势在于编写时简单。
例如:
计算阶乘
public static int fun(int n) {
if(n==1) {
return 1;
}
return fun(n-1)*n;
}
计算斐波那契数列
public static int method(int n) {
if(n==1||n==2) {
return 1;
}
return method(n-1)+method(n-2);
}
与for循环比较
public class Test02 {
public static void main(String[] args) {
int N = 50;
long start = System.currentTimeMillis();
long rt =0; method01(N);
long end = System.currentTimeMillis();
System.out.println("递归调用所耗时:"+(end-start)+",计算结果是:"+rt);
start = System.currentTimeMillis();
rt = method02(N);
end = System.currentTimeMillis();
System.out.println("for循环调用所耗时:"+(end-start)+",计算结果是:"+rt);
}
public static long method01(int n) {
if(n==1||n==2){
return 1;
}
return method01(n-1)+method01(n-2);
}
public static long method02(int n) {
long num1 = 1;
long num2 = 1;
long num3 = num1+num2;
for(int i = 4;i<=n;i++){
num1 = num2;
num2 = num3;
num3 = num1+num2;
}
return num3;
}
}
打印结果:递归虽然代码简单,但是耗时
递归调用所耗时:42248,计算结果是:12586269025
for循环调用所耗时:0,计算结果是:12586269025
从上图可知:递归不但耗时,而且极其吃内存