Java基础之【方法详解】

117 阅读14分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

哈喽,大家好!我是Why,一名在读学生,目前刚刚开始进入自己的编程学习生涯。虽然学习起步较晚,但我坚信做了才有0或1的可能。学了一段时间以后也是选择在掘金上分享自己的日常笔记,也希望能够在众多道友的大家庭中打成一片。 本文主要讲解java方法,如果大家读后觉得有用的话,还请大家多多支持博主:欢迎 ❤️点赞👍、收藏⭐、留言💬 ✨✨✨个人主页:JinHuan

方法

 对于一个java程序来说,如果没有“方法”,会存在什么问题?
     代码无法得到复用。(怎么提高复用性,可以定义方法,然后需要
     使用该功能的时候,直接调用一下方法即可。这样代码就得到复用了。)

栗子:

 public class MethodTest01{
     // 入口主方法。
     public static void main(String[] args){
 ​
     // 需求1:请编写程序,计算100和200的求和。
     int x = 100;
     int y = 200;
     int z = x + y;
     System.out.println(x + "+" + y + "=" + z);
 ​
     // 需求2:请编写程序,计算666和888的求和。
     // 这个需求2实际上和需求1是完全相同的,只不过具体求和时的“数据不同”
     int a = 666;
     int b = 888;
     System.out.println(a + "+" + b + "=" + c);
 ​
     // 需求3:请编写程序,计算111和222的和
     int m = 111;
     int n = 222;
     int k = m + n;
     System.out.println(m + "+" + n + "=" + k);
 ​
     /*
         需求1和需求2本质上相同,只不过参与运算的数值不同,
         代码编写了两份,显然代码没有得到重复利用,专业术语
         叫做“复用性”差。
 ​
         功能/业务逻辑既然相同,为什么要重复编写代码,代码能不能
         写一次,以后要是需要再次使用该“业务/需求”的时候,直接调用
         就可以了。
 ​
         如果想达到代码复用,那么需要学习java语言中的方法机制。
     */
 ​
 }
 ​
 }

方法定义及语法机制

     [修饰符列表] 返回值类型 方法名(形式参数列表){
         方法体; 
     }
 ​
 注意:
         [] 符号叫做中括号,以上中括号[]里面的内容表示不是必须的,是可选的。
         方法体由Java语句构成。
         方法定义之后需要去调用,不调用是不会执行的。
     
 1.1、关于修饰符列表:
         修饰符列表不是必选项,是可选的。目前为止,大家统一写成:public static
         后面你就理解应该怎么写了。
 ​
 1.2、关于返回值类型:
 ​
 第一:     返回值类型可以是任何类型,只要是java中合法的数据类型就行,数据类型包            括基本数据类型和引用数据类型,也就是说返回值类型可以是:byte                short int long float double boolean char String......
 ​
 第二:什么是返回值?
             返回值一般指的是一个方法执行结束之后的结果。
             结果通常是一个数据,所以被称为“值”,而且还叫
             “返回值”。
             方法就是为了完成某个特定的功能,方法结束之后
             大部分情况下都是有一个结果的,而体现结果的一般
             都是数据。数据得有类型。这就是返回值类型。
 ​
             main{
                 // 调用a方法
                 a();..如果a方法执行结束之后有返回值,这个返回值返回给main
             }
 ​
             a(){}
 ​
             方法执行结束之后的返回值实际上是给调用者了。谁调用就返回给谁。
         
 第三:   当一个方法执行结束不返回任何值的时候,返回值
         类型也不能空白,必须写上void关键字。所以void表示该
         方法执行结束后不返回任何结果。
 ​
 第四:   如果返回值类型“不是void”,那么你在方法体执行结束的时候必须使用"return         值;"这样的语句来完成“值”的返回,如果没有“return 值;”这样的语句
         那么编译器会报错。
         
         return 值; 这样的语句作用是什么?
                 作用是“返回值”,返回方法的执行结果。
         
 第五:    只要有“return”关键字的语句执行,当前方法必然结束。
         return只要执行,当前所在的方法结束,
         记住:不是整个程序结束。
 ​
 第六:   如果返回值类型是void,那么在方法体当中不能有“return 值;”这样的语句。但        是可以有“return;”语句。这个语句“return;”的作用就是用来终止当前方的。
 ​
 第七:   除了void之外,剩下的都必须有“return 值;”这样的语句。
 ​
 1.3、方法名
         方法名要见名知意。(驼峰命名方式)
         方法名在标识符命名规范当中,要求首字母小写,后面每个单词首字母大写。
         只要是合法的标识符就行。
     
 1.4、形式参数列表
         简称:形参
         注意:形式参数列表中的每一个参数都是“局部变量”,方法结束之后内存释放。
         形参的个数是:0~N个。
         public static void sumInt(){}
         public static void sumInt(int x){}
         public static void sumInt(int x, int y){}
         public static void sum(int a, int b, double d, String s){}
         形参有多个的话使用“逗号,”隔开。逗号是英文的。
         形参的数据类型起决定性作用,形参对应的变量名是随意的。
     
 1.5、方法体:
         由Java语句构成。java语句以“;”结尾。
         方法体当中编写的是业务逻辑代码,完成某个特定功能。
         在方法体中的代码遵循自上而下的顺序依次逐行执行。
         在方法体中处理业务逻辑代码的时候需要数据,数据来源就是这些形参。
 ​
 2、方法定义之后怎么调用呢?
         方法必须调用才能执行。
         怎么调用,语法是什么?
         类名.方法名(实际参数列表);
     
     实参和形参的类型必须一一对应,另外个数也要一一对应。

栗子:

 public class MethodTest03{
 //方法定义在这里可以。
 ​
 // main方法结束之后不需要给JVM返回任何执行结果。
 public static void main(String[] args){
     // 调用方法
     //错误: 不兼容的类型: String无法转换为int
     //MethodTest03.divide("abc", 200); // int a = "abc";
 ​
     //错误原因: 实际参数列表和形式参数列表长度不同
     //MethodTest03.divide();
 ​
     // (10, 2)叫做实际参数列表,简称实参。
     // 注意:实参和形参必须一一对应,类型要对应,个数要对应。
     MethodTest03.divide(10, 2);
 ​
     // 调用sum方法
     // 怎么去接收这个方法的返回结果????
     // 使用变量来接收这个方法的返回值。
     // 注意:变量的定义需要指定变量的数据类型。
     // 变量的数据类型是什么呢?
     int jieGuo = MethodTest03.sum(100, 200);
     System.out.println(jieGuo); //300
 ​
     // jieGuo变量可以是double类型吗?
     // double是大容量。int是小容量。自动类型转换。
     double jieGuo2 = MethodTest03.sum(100, 200);
     System.out.println(jieGuo2); //300.0
 ​
     // 对于没有返回值的方法,变量能接收吗?
     // divide方法结束没有返回值。不能接收。
     // 错误: 不兼容的类型: void无法转换为int
     //int i = MethodTest03.divide(100, 50);
 ​
     // 当一个方法有返回值的时候,我可以选择不接收吗?
     // 你可以返回值,但是我可以选择不要你这个值。这是允许的。
     // 只不过这样没有意义,一般程序返回了执行结果,都是需要接收这个结果的。
     // 我们可以不接收,但是这个返回值该返回还是会返回的。只不过不用变量接收。
     // 以下代码虽然没有使用变量接收这个返回值,但是这个值还是返回了。
     // 返回之后内存马上释放,因为没有使用变量接收。
     MethodTest03.sum(100, 200);
 ​
     byte b1 = 10;
     //int a = b1;
     byte b2 = 20;
     int result = sum(b1, b2); // (b1,b2)是实参。自动类型转换。
     System.out.println(result);
 ​
 }
 ​
 // 计算两个int类型数据的和
 /*
 public static String sum(int a, int b){
     // 错误: 不兼容的类型: int无法转换为String
     return a + b;
 }
 */
 ​
 public static int sum(int a, int b){
     return a + b;
 }
 ​
 // 方法定义到这里也可以。没有顺序要求。
 // 业务是什么?计算两个int类型数据的商
 // 方法执行结束之后返回执行结果。
 ​
 //错误: 缺少返回语句
 /*
 public static int divide(int x, int y){
     int z = x / y;
 }
 */
 ​
 //错误: 不兼容的类型: String无法转换为int
 /*
 public static int divide(int x, int y){
     int z = x / y;
     return "abc";
 }
 */
 ​
 //可以
 /*
 public static int divide(int x, int y){
     int z = x / y;
     return z;
 }
 */
 ​
 //可以
 /*
 public static int divide(int x, int y){
     return x / y;
 }
 */
 ​
 // 可以
 /*
 public static int divide(int a, int b){
     return a / b;
 }
 */
 ​
 // 如果我不需要执行结束之后的返回值?
 // 这个结果我希望直接输出。
 //错误: 不兼容的类型: 意外的返回值
 /*
 public static void divide(int a, int b){
     return a / b;
 }
 */
 ​
 //可以
 /*
 public static void divide(int a, int b){
     return; // 用来终止这个方法的
 }
 */
 ​
 // 可以
 /*
 public static void divide(int a, int b){
 }
 */
 ​
 // 可以
 public static void divide(int a, int b){
     System.out.println(a / b); // 5
 }
 }

在方法调用的时候,什么时候“类名.”是可以省略的。什么时候不能省略?

 a()方法调用b()方法的时候,ab方法都在同一个类中,“类名.”可以省略。
 如果不在同一个类中“类名.”不能省略。

栗子:

 public class MethodTest04{
 ​
     public static void daYin3(){
         System.out.println("动力节点-口口相传的Java黄埔军校!");
     }
     
     // 入口
     public static void main(String[] args){
         // 调用println()方法。
         MethodTest04.daYin();
         MethodTest04.daYin2();
         MethodTest04.daYin3();
 ​
         // “类名. ”可以省略吗?
         daYin();
         daYin2();
         daYin3();
 ​
         // 第一次跨类调用。
         // 像这种情况下:“类名.”就不能省略了。
         MyClass.daYin();
         //daYin();
     }
 ​
     public static void daYin(){
         System.out.println("hello world!");
     }
 ​
     public static void daYin2(){
         System.out.println("hello world2!!!");
     }
 }
 ​
 // 类2
 class MyClass{
 ​
     public static void daYin(){
         System.out.println("打印1");
     }
 ​
     public static void daYin2(){
         System.out.println("打印2");
     }
 ​
     public static void daYin3(){
         System.out.println("打印3");
     }
 }

任何一个方法体当中的代码都是遵循自上而下的顺序依次逐行执行的

 /*
     推测执行结果:
         main begin
         m1 begin
         m2 begin
         m3 begin
         T's m3 method execute!
         m3 over
         m2 over
         m1 over
         main over
 ​
         main方法最先执行,并且main方法是最后一个结束。
         main结束,整个程序就结束了。
 ​
 */
 public class MethodTest05{
 ​
     public static void main(String[] args){
         System.out.println("main begin");
         // 调用m1方法
         m1();   
         System.out.println("main over");
     }
 ​
     public static void m1(){
         System.out.println("m1 begin");
         // 调用程序不一定写到main方法中,不要把main方法特殊化。
         // main方法也是一个普通方法。
         m2();
 ​
         System.out.println("m1 over");
     }
 ​
     // m2方法可以调用T类的m3()方法吗?
     public static void m2(){
         System.out.println("m2 begin");
         T.m3();
         System.out.println("m2 over");
     }
 }
 ​
 class T{
     public static void m3(){
         System.out.println("m3 begin");
         System.out.println("T's m3 method execute!");
         System.out.println("m3 over");
     }
 }

break;语句和return;语句有什么区别

 不是一个级别。
         break;用来终止switch和离它最近的循环。
         return;用来终止离它最近的一个方法。

栗子:

 public class MethodTest06{
 ​
     //main方法的返回值类型是void,表示没有返回值。
     public static void main(String[] args){
 ​
         for(int i = 0; i < 10; i++){
             if(i == 5){
                 //break; // 终止for循环
                 return; // 终止当前的方法,和break;不是一个级别的。
                 //错误: 不兼容的类型: 意外的返回值
                 //return 10;
             }
             System.out.println("i = " + i);
         }
 ​
         System.out.println("Hello World!");
     }
 ​
 ​
 }

关于返回语句的经典实例:

 public class MethodTest07{
 ​
     public static void main(String[] args){
         // 调用方法
         int result = m();
         System.out.println(result); // 1
 ​
         // 调用x方法
         int result1 = x(true);
         System.out.println("result1 = " + result1);
 ​
         // 再次调用x方法
         int result2 = x(false);
         System.out.println("result2 = " + result2);
     }
 ​
     
     //错误: 缺少返回语句
     /*
     public static int m(){
         boolean flag = true; //编译器不负责运行程序,编译器只讲道理。
         // 对于编译器来说,编译器只知道flag变量是boolean类型
         // 编译器会认为flag有可能是false,有可能是true
         if(flag){
             // 编译器觉得:以下这行代码可能会执行,当然也可能不会执行
             // 编译器为了确保程序不出现任何异常,所以编译器说:缺少返回语句
             return 1;
         }
     }
     */
 ​
     // 怎么修改这个程序呢?
     // 第一种方案:带有else分支的可以保证一定会有一个分支执行。
     /*
     public static int m(){
         boolean flag = true;
         if(flag){
             return 1;
         }else{
             return 0;
         }
     }
     */
 ​
     // 第二种方案:该方案实际上是方案1的变形。
     // return语句一旦执行,所在的方法就会结束。
     /*
     public static int m(){
         boolean flag = true;
         if(flag){
             return 1;
         }
         return 0;
     }
     */
 ​
     /*
     // 在同一个域当中,"return语句"下面不能再编写其它代码。编写之后编译报错。
     public static int m(){
         boolean flag = true;
         if(flag){
             return 1;
             //错误: 无法访问的语句
             //System.out.println("hello1");
         }
         // 这行代码和上面的代码hello1的区别是:不在同一个域当中。
         //System.out.println("hello2");
         return 0;
         // 错误: 无法访问的语句
         //System.out.println("hello3");
     }
     */
 ​
     // 三目运算符有的时候会让代码很简练。
     public static int m(){
         boolean flag = true;
         return flag ? 1 : 0;
     }
 ​
     // 带有一个参数的方法。
     public static int x(boolean flag){
         return flag ? 1 : 0;
     }
 }

关于方法的执行:

栗子:

 ​
 // 局部变量:只在方法体中有效,方法结束之后,局部变量的内存就释放了。
 // JVM三块主要的内存:栈内存、堆内存、方法区内存。
 // 方法区最先有数据:方法区中放代码片段。存放class字节码。
 // 堆内存:后面讲。
 // 栈内存:方法调用的时候,该方法需要的内存空间在栈中分配。
 // 方法不调用是不会在栈中分配空间的。
 ​
 // 方法只有在调用的时候才会在栈中分配空间,并且调用时就是压栈。
 // 方法执行结束之后,该方法所需要的空间就会释放,此时发生弹栈动作。
 ​
 // 方法调用叫做:压栈。分配空间
 // 方法结束叫做:弹栈。释放空间
 ​
 // 栈中存储什么?方法运行过程中需要的内存,以及栈中会存储方法的局部变量。
 ​
 public class MethodTest08{
     //主方法,入口
     public static void main(String[] args){
         
         //int a = 100;
         // 这个赋值原理是:将a变量中保存的100这个数字复制一份传给b变量。
         // 所以a和b是两个不同的内存空间,是两个局部变量。
         //int b = a;
 ​
         System.out.println("main begin");
         int x = 100;
         m1(x);
         System.out.println("main over");
     }
     public static void m1(int i){ // i是局部变量
         System.out.println("m1 begin");
         m2(i);
         System.out.println("m1 over");
     }
     public static void m2(int i){
         System.out.println("m2 begin");
         m3(i);
         System.out.println("m2 over");
     
     }
     public static void m3(int i){
         System.out.println("m3 begin");
         System.out.println(i);
         System.out.println("m3 over");
     }
 }

方法重载机制

 在同一个类中,将功能相似的方法,赋予同样的方法名,这样打的话代码更美观,也便于后期的代码编写
     例如:
         System.out.println();

栗子:

 public class OverloadTest{
     public static void main(String[] args){
         // 对于程序员来说,只需要记忆一个方法名即可。
         System.out.println(sum(10, 20));
         System.out.println(sum(10L, 20L));
         System.out.println(sum(10.0, 20.0));
     }
     // 定义一个计算int类型数据的求和方法
     public static int sum(int a, int b){
         System.out.println("int求和");
         return a + b;
     }
 ​
     // 定义一个计算long类型数据的求和方法
     public static long sum(long a, long b){
         System.out.println("long求和");
         return a + b;
     }
 ​
     // 定义一个计算double类型数据的求和方法
     public static double sum(double a, double b){
         System.out.println("double求和");
         return a + b;
     }
 }

什么时候回发生方法重载

 1、在同一个类中
 2、方法名相同
 3、参数列表不同
     参数个数不同
     参数类型不同
     参数顺序不同
     
     
 与方法的返回值类型无关
 与方法法的饰符列表无关
     

栗子:

 public class OverloadTest03{
     public static void main(String[] args){
         m1();
         m1(100);
 ​
         m2(10, 3.14);
         m2(3.14, 10);
 ​
         m3(100);
         m3(3.14);
 ​
     }
 ​
     public static void m1(){
         System.out.println("m1无参数的执行!");
     }
     
     // 这个方法的参数个数和上面的方法的参数个数不同。
     public static void m1(int a){
         System.out.println("m1有一个int参数执行!");
     }
 ​
     public static void m2(int x, double y){
         System.out.println("m2(int x, double y)");
     }
 ​
     // 参数的顺序不同,也算不同。
     public static void m2(double y, int x){
         System.out.println("m2(double y, int x)");  
     }
 ​
     public static void m3(int x){
         System.out.println("m3(int x)");
     }
 ​
     // 参数的类型不同。
     public static void m3(double d){
         System.out.println("m3(double d)");
     }
 ​
     //分析:以下两个方法有没有发生重载?
     // 编译器报错了,不是重载,这是重复了:呵呵。
     /*
     public static void m4(int a, int b){
     
     }
     public static void m4(int x, int y){
     
     }
     */
 ​
     // 这两个方法有没有发生重载呢?
     // 这不是重载,这是方法重复了。
     /*
     public static int m5(){
         return 1;
     }
     public static double m5(){
         return 1.0;
     }
     */
 ​
     //这两个方法重载了吗?
     // 这个方法没有修饰符列表
     // 这不是重载,是重复了。
     /*
     void m6(){
     
     }
     // 这个有修饰符列表
     public static void m6(){
     
     }
     */
 ​
 }
 ​
 class MyClass{
     // 不在同一个类当中,不能叫做方法重载。
     public static void m1(int x, int y){
     
     }
 }