方法
方法是一个功能模块的集合。将多行代码放在一个{}中,组成一个代码块
语法结构
public static 返回类型 方法名称([参数列表]){
方法体代码;
return 返回值;
}
在定义方法的时候有两种返回类型:
- void :代表无返回值
- 数据类型(基本数据类型,引用类型):返回对应类型的返回值
使用
方法声明在类中,main方法外;要使用时在main方法中通过方法的名称调用
参数列表
- 将方法声明的参数列表是形式参数;对于调用者而言,传入的参数是实际参数。
- 方法声明的参数列表,只存在声明,不需要初始化就可以使用。
- 调用方法是不只是看方法名称,还要看参数列表,这样才能准确调用方法。
方法的优点
- 提高代码的复用性
- 提高后期代码的拓展性,延展性
- 提高后期代码的维护性
方法的重载
定义:在同一个类中,存在同名,参数列表不同的方法
重载的前提 :方法名相同,参数列表的个数,顺序,类型不同
tips:方法的返回类型与方法的重载无关。
方法的使用用例:
package com.mage.method;
import java.util.Scanner;
public class Method02 {
static final double PI=3.14;
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.println("请输入半径:");
int r=input.nextInt();
System.out.println("请输入高:");
int height=input.nextInt();
double sumArea=sumArea(r, height);
System.out.println("半径为"+r+"高为"+height+"的圆柱的面积为:"+sumArea);
}
public static double circleArea(int r) {
double area=PI*r*r;
return area;
}
public static double circleRe(int r) {
double re=PI*2*r;
return re;
}
public static double sumArea(int r,int height) {
double circleArea=circleArea(r);
double circleRe=circleRe(r);
double sumArea=circleArea*2+circleRe*height;
return sumArea;
}
}
方法的重载用例
public class Method08 {
public static void main(String[] args) {
add(1,2);
}
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);
}
}
变量
变量的分类
变量三要素:数据类型,变量名,声明周期。
按照变量声明的位置分为:成员变量,局部变量。
局部变量
局部变量声明在方法中或者代码块中,只在当前的方法或者代码块中有效,一定要先声明再赋值之后才能使用
成员变量
成员变量声明在类中方法外,在当前类中都有效,声明时要么用static修饰要么通过创建当前类的对象去访问该变量,无需初始化就能使用,每个不同类型的变量都存在默认值
public class Method04 {
static int num=20;
public static void main(String[] args) {
System.out.println(num);
int num2=10;
System.out.println(num2);
}
}
递归
递归是一种编程技巧,在程序中自己调用自己,在递归程序中存在一个出口
计算斐波那契数列
public class Test{
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;
}
}
通过比较递归和for循环求斐波那契数列,可以看出通过递归求斐波那契数列的方法随着要求的数越来越大时,他所消耗的时间也越来越长。
递归耗时的原因:
递归耗时的原因是,他需要不断的调自己,比如求斐波那契数列,在你求第50位的数是多少时,你需要求第49位的数是多少,这样他就需要等待前面的数都求出来才能算,所以等待的时间长,而且他还需要不断地去开辟空间,所以递归程序不但耗时,还非常的吃内存。
尾递归
因为递归耗时耗内存,所以就会进行优化,最终尾递归出现了,尾递归其实只是一种对递归的特殊写法,当编译器检测到一个函数调用的是尾递归时,他就覆盖当前的栈帧而不是在栈中创建新的,所以尾递归比递归要快,内存占用小。
public class Feibo {
public static void main(String[] args) {
int N = 50;
long start = System.currentTimeMillis();
long result = feiBo(N,1L,1L);
long end = System.currentTimeMillis();
System.out.println("尾递归耗时:"+(end-start)+",第50项的值是:"+result);
}
public static long feiBo(int num,long ret1,long ret2) {
if(num==1||num==2) {
return ret2;
}
return feiBo(num-1,ret2,ret1+ret2);
}
}
- 能够用递归写得,肯定能用循环写;能用递归写的,不一定能用尾递归写。
- 凡是要用的递归程序80%以上都是基于数据结构的。