方法也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元。
把一个功能封装为方法的目的是,可以实现代码重用,从而简少代码量。
方法的使用原则:
(1)必须先声明后使用
类,变量,方法等都要先声明后使用
(2)不调用不执行,调用一次执行一次。调用一次,在栈中压入一个方法栈。
成员方法分为两类:
1、语法格式
修饰符 返回值类型 方法名(【参数列表:参数类型1 参数名1,参数类型2 参数名, ...... 】){ 方法体; 【return 返回值;】 }
2、方法声明的位置必须在类中方法外(方法中不能声明方法)
正确示例:
类{ 方法1(){ } 方法2(){ } }
错误示例:
类{ 方法1(){ 方法2(){ //错误 } } }
方法调用的位置:在另一个方法中调用。
正确示例:
类{ 方法1(){ 调用其他方法; } }
方法调用的分类:
单独调用,格式如下:
对象名.方法名(参数);
输出或返回调用,格式如下:
System.out.println(对象名.方法名(参数));//直接输出方法调用后的返回值 或 return 对象名.方法名(参数);//直接返回方法调用后的返回值作为当前方法的返回值
赋值调用,格式如下:
数据类型 变量名 = 对象名.方法名(参数);
如果实例方法是在本类的另一个实例方法中调用,那么可以省略“对象名.”
class Count { /* 定义计算两个整数和的方法 返回值类型,计算结果是int 参数:不确定数据求和,定义int参数.参数又称为形式参数 */ public int getSum(int a, int b) { return a + b; } /* 定义计算两个整数差的方法 返回值类型,计算结果是int 参数:不确定数据求差,定义int参数.参数又称为形式参数 */ public int getSubtract(int a, int b){ return getSum(a,-b);//直接返回getSum(a,-b)方法调用的结果作为getSubtract(a,b)的结果 } } public class Method_Demo1 { public static void main(String[] args) { // 创建对象 Count c = new Count(); // 通过单独调用方式调用方法 c.getSum(3,4); // 通过输出调用方式调用方法 System.out.println(c.getSum(3,4)); // 通过赋值调用方式调用方法 int sum = c.getSum(3,4); System.out.println(sum); } }
总结:
(1)调用时,需要通过方法名来识别调用哪个方法
(2)调用时,需要传“实参”,实参的个数、类型、顺序顺序要与形参列表一一对应
如果方法没有形参,就不需要也不能传实参。
(3)调用时,如果方法有返回值,可以接受或处理返回值结果。
如果方法的返回值类型是void,不需要也不能接收和处理返回值结果。
class Account{ String id; double balance; public void save(double money){ if(money > 0){ balance += money; }else{ System.out.println("参数有误"); } } public void withdraw(double money){ if(money <0){ System.out.println("参数有误"); }else if(money > balance){ System.out.println("余额不足"); }else{ balance -= money; } } } class Customer{ String name; String tel; String cid; Account account; } class BankClerk{ public void open(Customer c, Account a){ c.account = a; } } public class Method_Exer6 { public static void main(String[] args) { //创建客户对象 Customer c = new Customer(); c.name = "柴林燕"; c.tel = "10086"; c.cid = "111111111111111111"; //创建银行卡账号对象 Account a = new Account(); a.id = "12345678910"; a.balance = 0; //银行对象 BankClerk b = new BankClerk(); b.open(c, a); System.out.println("姓名:" + c.name + ",电话:" + c.tel + ",身份证号:" + c.cid + ",账号:" + c.account.id + ",余额:" + c.account.balance); //存款 c.account.save(1000); System.out.println("姓名:" + c.name + ",电话:" + c.tel + ",身份证号:" + c.cid + ",账号:" + c.account.id + ",余额:" + c.account.balance); //取款 c.account.withdraw(2000); //显示信息 System.out.println("姓名:" + c.name + ",电话:" + c.tel + ",身份证号:" + c.cid + ",账号:" + c.account.id + ",余额:" + c.account.balance); } }
方法不调用不执行,调用一次执行一次,每次调用会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。
栈结构:先进后出,后进先出。
class Test18_Invoke_Memory{ public static void main(String[] args){ Count c = new Count(); int x = 1; int y = 2; int sum = c.getSum(x,y); System.out.println(x + " + " + y + " = " + sum); } } class Count{ public int getSum(int a, int b){ return a + b; } }
在JDK1.5之后,如果我们定义一个方法时,此时某个形参的类型可以确定,但是形参的个数不确定,那么我们可以使用可变参数。
格式:
修饰符 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){ 方法体; }
要求:
(1)一个方法只能有一个可变参数
(2)可变参数必须是形参列表的最后一个
(3)其实这个书写“等价于”
修饰符 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){ 方法体; }
只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,其实编译成的class文件,将这些元素先封装到一个数组中,在进行传递。这些动作都在编译.class文件时,自动完成了。
好处:
同样是代表数组,但是在调用这个带有可变参数的方法时,不用创建数组(这就是简单之处),直接将数组中的元素作为实际参数进行传递,其实编译成的class文件,将这些元素先封装到一个数组中,在进行传递。这些动作都在编译.class文件时,自动完成了。
代码演示:
public class ChangeArgs { public static void main(String[] args) { // 创建对象 Count c = new Count(); int[] arr = { 1, 4, 62, 431, 2 }; int sum1 = c.getSum1(arr); System.out.println(sum1); int sum2 = c.getSum2(arr); System.out.println(sum2); int sum3 = c.getSum2(1, 4, 62, 431, 2); System.out.println(sum3); } } class Count { // 完成数组 所有元素的求和 // 原始写法 public int getSum1(int[] arr) { int sum = 0; for (int i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; } // 可变参数写法 public int getSum2(int... arr) { int sum = 0; for (int i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; } }
定义求1-n个整数中的最大值
public class ChangeArgs_Exer1 { public static void main(String[] args) { Count c = new Count(); System.out.println(c.max(1)); System.out.println(c.max(5,3,2,6)); } } class Count{ public int max(int num, int... others){ int max = num; for (int i = 0; i < others.length; i++) { if(max < others[i]){ max = num; } } return max; } }
定义将n个字符串进行拼接,如果没有传入字符串,那么返回空字符串
public class ChangeArgs_Exer2 { public static void main(String[] args) { StringUtil su = new StringUtil(); System.out.println(su.concat()); System.out.println(su.concat("hello","world")); } } class StringUtil{ public String concat(String... args){ String str = ""; for (int i = 0; i < args.length; i++) { str += args[i]; } return str; } }
比较两个数据是否相等。参数类型分别为两个byte
类型,两个short
类型,两个int
类型,两个long
类型,并在main
方法中进行测试。
public class Method_Demo6 { public static void main(String[] args) { //创建 Count c = new Count(); //定义不同数据类型的变量 byte a = 10; byte b = 20; short c = 10; short d = 20; int e = 10; int f = 10; long g = 10; long h = 20; // 调用 System.out.println(c.compare(a, b)); System.out.println(c.compare(c, d)); System.out.println(c.compare(e, f)); System.out.println(c.compare(g, h)); } } class Count { // 两个byte类型的 public boolean compare(byte a, byte b) { System.out.println("byte"); return a == b; } // 两个short类型的 public boolean compare(short a, short b) { System.out.println("short"); return a == b; } // 两个int类型的 public boolean compare(int a, int b) { System.out.println("int"); return a == b; } // 两个long类型的 public boolean compare(long a, long b) { System.out.println("long"); return a == b; } }
示例代码1:
class Test{ public static void swap(int a, int b){ int temp = a; a = b; b = temp; } public static void main(String[] args){ int x = 1; int y = 2; swap(x,y);//调用完之后,x与y的值不变 } }
陷阱实例1:
/* 陷阱1:在方法中,形参 = 新new对象,那么就和实参无关了 */ class Test{ public static void change(MyData my){ my = new MyData();//形参指向了新对象 my.num *= 2; } public static void main(String[] args){ MyData m = new MyData(); m.num = 1; change(m);//调用完之后,m对象的num属性值仍然为1 } } class MyData{ int num; }
陷阱实例2:
public class Test { public static void main(String[] args) { StringUtil util = new StringUtil(); String str = "尚硅谷"; util.change(str); System.out.println(str); } } class StringUtil{ public void change(String str){ str += "你好";//String对象不可变,一旦修改就会产生新对象 } }
通过命令行给main方法的形参传递的实参称为命令行参数
public class TestCommandParam{ //形参:String[] args public static void main(String[] args){ System.out.println(args); System.out.println(args.length); for(int i=0; i<args.length; i++){ System.out.println("第" + (i+1) + "个参数的值是:" + args[i]); } } }
运行命令:
java TestCommandParam
java TestCommandParam 1 2 3
java TestCommandParam hello atguigu
public class RecursionMethod1{ public static void main(String[] args) { Count c = new Count(); int sum = c.sum(100); System.out.println("1-100的和:" + sum); } } class Count{ public int sum(int n){ if(n == 1){ return 1; }else{ return n + sum(n-1); } } }
规律:一个数等于前两个数之和,
f(0) =1,
f(1) = 1,
f(2) = f(0) + f(1) =2,
f(3) = f(1) + f(2) = 3,
f(4) = f(2) + f(3) = 5
…
f(n) = f(n-2) + f(n-1);
public class RecursionMethod3{ public static void main(String[] args) { Count c = new Count(); System.out.println("f(10):" + c.f(10)); System.out.println("f方法被调用的总次数:" + c.total); } } class Count{ int total = 0; public int f(int n){ total++; if(n <= 1){ return 1; }else{ return f(n-2) + f(n-1); } } }