Java基础教程 - 6 方法

更好的阅读体验:点这里 ( www.doubibiji.com
更好的阅读体验:点这里 ( www.doubibiji.com
更好的阅读体验:点这里 ( www.doubibiji.com

6 方法

方法也可以称之为功能,我们可以将一段实现特定功能的代码封装为一个方法。

为什么需要封装为方法呢?

举个栗子:

给定两个整数,我现在想获取其中的最大值。

于是乎,哐哐敲代码:

public class HelloJava {
    public static void main(String[] args) {
        int num1 = 24;
        int num2 = 12;

        int maxNum;
        if (num1 > num2) {
            maxNum = num1;
        } else {
            maxNum = num2;
        }

        System.out.println("较大的数为:" + maxNum); 	// 较大的数为:24
    }
}

一个地方需要这个功能,我在一个地方写了这个功能的代码,100个、1000个地方需要这个功能,那就需要写1000遍。万一这个功能需要修改,修改1000个地方不得崩溃。

所以我们可以将这个功能封装为一个方法,想要使用到这个功能的时候,直接调用这个方法即可。

所以通过使用方法,提高代码的复用性,减少重复代码,提高开发效率。

我们之前已经使用了很多 Java API 的方法,例如 System.out.println()Arrays.toString()等,现在我们主要学习如何自定义方法。


因为还没有讲解类和对象,所以这里学习的是静态方法,后面学习类和对象的时候,再学习成员方法。

方法在有的语言中又叫函数,两个基本是一个意思。

6.1 方法的定义

下面定义一个将两个数相加的方法

/**
 * 定义两个数相加的方法
 */
public static int add() {						// 定义方法
    return 3 + 5;
}
  • public 是权限修饰符,表示在哪里可以访问到这个方法,static 表示是静态方法,这里 public static 先不用管,固定写法就好。
  • int 表示返回值类型,int 表示这个方法返回一个整形的数据,方法的返回值可以是任何类型或者是void;
  • add 表示方法名,方法名按照标识符命名规则即可,推荐使用首字母小写的驼峰规则(xxxYyyZzz);
  • () 中可以传递参数,参数可以缺省;
  • return 用来返回结果,返回的结果要和返回值类型匹配,所以这里需要 return 一个整形数据;如果返回值类型为 void,那么 return 可以省略,不返回结果;
  • 方法必须先定义后调用。
  • 注意:return后面不能有语句。

下面来调用方法:

public class HelloJava {
    public static void main(String[] args) {
        int result = add();		              // 调用两个数相加的方法
        System.out.println(result); 				// 8
    }

    /**
     * 定义两个数相加的方法
     */
    public static int add() {						// 定义方法
        return 3 + 5;
    }
}

调用方法使用 方法名(); 这样的方式来调用,如果方法有返回值,也可以定义变量接收返回结果,当然不接收也可以。

上面定义的方法只能计算 3 + 5 的值,复用性太差,我们可以让方法接收两个参数,然后根据这两个参数来计算和。

6.2 方法的参数

方法的参数可以接收外面传递的值。

1 方法参数

通过传递参数,我们可以改写上面计算两个数的和的方法:

public class HelloJava {
    public static void main(String[] args) {
        int result = add(1, 2);		        // 调用方法		     
        System.out.println(result); 				// 输出3
    }

    /**
     * 定义两个数相加的方法
     */
    public static int add(int a, int b) {			// 定义方法
        return a + b;
    }
}

在调用的时候,传递了两个参数,12,根据传入的顺序,1 传递给了 a2 传递给了 b,调用方法的时候,需要根据方法定义时候的参数顺序来传递参数。

通过传递不同的参数,可以计算不同值的和,复用性更强。

方法名后面的参数为形式参数(形参),方法的参数个数不限,使用逗号分隔;

调用方法的时候,传递的是实际参数(实参),表示方法执行的时候的参数值。


加深印象,再举个栗子:

public class HelloJava {
    public static void main(String[] args) {
        String name = "doubibiji";
        int year = 13;
        sayHello(name, year);       // 调用方法
    }

    /**
     * 定义方法
     */
    public static void sayHello(String name, int years) {
        System.out.println(String.format("Hello, I am %s, I am %d years old.", name, years));
    }
}

上面定义了一个 sayHello() 方法,接收两个参数,分别是字符串和整形类型。方法没有返回值,所以返回值类型就是 void

2 可变参数

可变参数是一种特殊的参数类型,它允许在方法定义中传入可变数量的参数。这通过在类型名称后面添加三个点(…)来实现。可变参数使得方法的调用更加灵活,因为你可以传入任意数量的参数,而无需创建方法重载。

举个栗子:

public class HelloJava {
    public static void main(String[] args) {
        // 调用printNumbers方法,传入不同数量的参数
        printNumbers(1, 2, 3); // 输出:1 2 3
        printNumbers(6);      // 输出:6
        printNumbers();       // 输出:(无输出)
        printNumbers(new int[]{1, 2, 3, 4, 5}); // 1 2 3 4 5 
    }

    /**
     * 定义可变参数的方法
     */
    public static void printNumbers(int... numbers) {
        for (int num : numbers) {
            System.out.print(num + " ");
        }

        System.out.println();
    }
}

上面定义了一个方法 printNumbers(),方法的参数是一个可变参数,表示可以接收任意个参数。在 main() 方法中调用方法 printNumbers() 可以传递任意参数,也也可以不传递参数。

其实可变参数 int... numbers 就是一个数组,所以可以直接使用数组 new int[]{1, 2, 3, 4, 5} 来传递参数。当不传递参数的时候, int... numbers 为空数组,不是 null

需要注意:一个方法只能有一个可变参数,且它必须是方法参数列表中的最后一个参数。

3 参数值传递

在 Java 中调用方法传递参数是值传递,不是地址传递!

什么意思呢?举个栗子:

我们编写代码,交换 a 和 b 两个变量的值,代码如下:

public class HelloJava {
    public static void main(String[] args) {
        int a = 3;
        int b = 5;

        // 交换a和b的值
        int temp = a;
        a = b;
        b = temp;
        System.out.println(a); 		  // 5
        System.out.println(b); 		  // 3
    }
}

交换两个变量这个功能,可能其他地方也会用到,于是写一个方法来实现:

public class HelloJava {
    public static void main(String[] args) {
        int a = 3;
        int b = 5;

        // 调用交换方法
        swap(a, b);
        System.out.println(a); 		  // 3
        System.out.println(b); 		  // 5
    }

    /**
     * 交换两个变量
     */
    public static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }
}

运行代码,发现 main() 方法中 ab 的值并没有被交换,不科学啊,为什么呢。

首先 main 方法中执行:int a = 3; int b = 5; ,方法中的变量会在栈中开辟内存空间:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

继续执行,调用 swap 方法,swap 方法的形参 int a, int b 和 main 方法中的变量 ab 根本就不是同一个变量,只是这里恰巧名称相同而已,只是将 main 方法中的变量的值赋值给了 swap 方法的形参。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后执行 swap 方法中的代码,创建了 temp 变量,调换了方法中 ab 的值:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


再看一段代码:

import java.util.Arrays;

public class HelloJava {
    public static void main(String[] args) {
        int[] array = new int[]{3, 5};

        // 调用交换方法
        swap(array);
        System.out.println(Arrays.toString(array)); // [5, 3]
    }

    /**
     * 交换两个变量
     */
    public static void swap(int[] array) {
        int temp = array[0];
        array[0] = array[1];
        array[1] = temp;
    }
}

咋蒙圈了呢,为什么 main() 方法中的 array 数组中元素值被交换了呢?

这是因为数组变量是引用变量,存储的是数组的地址。

首先 main 方法中执行: int[] array = new int[]{3, 5}; ,会分别在栈中和堆中开辟内存空间:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后调用 swap 方法,将 main() 方法中的变量 array 的地址值传递给了 swap 方法的形参 array :

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里也是值传递,只是传递的是引用的地址,所以指向的是堆中同一块内存地址,此时在 swap() 方法中,修改 array 变量,修改的就是同一块内存地址了,所以 main 方法中的变量 array 数组就被修改了。

所以在 Java 中方法的传参是值传递。

6.3 方法的返回值

如果方法没有返回值,返回值类型为 void

public static void add(int a, int b) {
    System.out.println(a / b);
    return;		// 可以省略
}

return 语句如果在最后,那么可以省略,也可以提前返回:

public static void add(int a, int b) {
    if (b == 0) {
        return;		// 提前返回,方法终止
    }

    System.out.println(a / b);
}

方法 return 后,方法将终止执行。


如果方法有返回值,则在定义方法的时候,需要指定方法的返回值类型。

举个栗子:

public class MethodTest {
    /**
     * 返回值类型为int
     */
    public static int add(int a, int b) {
        // 定义方法
        return a + b;
    }

    public static void main(String[] args) {
        int sum = add(1, 2); 				// 调用方法
        System.out.println(sum);    // 3
    }
}

上面定义了一个方法,将两个数相加,然后将结果返回,并打印出来。

方法的返回值需要定义变量来接收,不过,如果你只是调用,不接收结果,也是没有问题的:

public static int add(int a, int b) {
    // 定义方法
    return a + b;
}

public static void main(String[] args) {
    add(1, 2); 				// 调用方法
}

6.4 方法的嵌套调用

方法的嵌套调用就是一个方法可以调用另外一个方法,另外一个方法还可以继续调用其他的方法,依此类推。

举个栗子:

下面定义了2个方法,funA() 和 funB(),并在main()方法中调用了funA() ,然后在funA()中调用了 funB()。

public class MethodTest {
  
    public static void funB() {
        System.out.println("----b");
    }

    public static void funA() {
        System.out.println("----a1");
        funB();
        System.out.println("----a2");
    }

    public static void main(String[] args) {
        funA();
    }
}

执行结果:

----a1
----b
----a2

我们会发现在 funA() 中调用 funB() 后,funB() 执行完成,重新回到了 funA() 继续执行。

6.6 方法的重载

什么是方法的重载?

方法的重载就是 Java 中允许存在多个方法,它们的方法名一样,但是参数不一样,注意不包括返回值。

举个栗子:

public class HelloJava {
    public static void main(String[] args) {
        String name = "doubibiji";
        int year = 13;
        sayHello(name, year);       // 调用方法
    }

  	// 定义方法
    public static void sayHello() {
    }
  	// 重载方法1
    public static void sayHello(String name) {
    }
  	// 重载方法2
    public static void sayHello(String name, int age) {
    }
  	// 重载方法3
    public static void sayHello(int age, String name) {
    }
}

上面定义了4个 sayHello 的方法,但是是被允许的,因为它们的参数不一样(包括参数类型和顺序、参数个数),在调用的时候根据,根据传递的参数来判断调用的那个方法。

注意返回值类型不同,不构成重载。


再看一下下面的代码:

public class HelloJava {
    public static void main(String[] args) {
        add(1, 2);		// 会调用哪一个
    }

    public static void add(int x, int y) {
        System.out.println("int相加:" + (x + y));
    }
    public static void add(float x, float y) {
        System.out.println("float相加:" + (x + y));
    }
    public static void add(long x, long y) {
        System.out.println("long相加:" + (x + y));
    }
    public static void add(double x, double y) {
        System.out.println("double相加:" + (x + y));
    }
}

在上面的代码中,add(1, 2) 会调用哪一个重载的方法呢?首先会调用 add(int x, int y)

如果将 add(int x, int y) 方法删掉,代码是不会报错的,运行后,会调用 add(long x, long y) ,自动进行类型的提升。

如果再将 add(long x, long y) 方法删掉,运行后,会调用 add(float x, float y) ,再删掉 add(float x, float y) 的话,最终会调用 (double x, double y)


Java API 中有很多重载的方法,例如用于数学计算的 Math 类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6.7 方法的递归

什么是方法的递归?

方法的递归,就是在一个方法内部,又调用了这个方法自己,这个就是方法的递归。

举个例子:

public class HelloJava {
    public static void funA() {
        System.out.println("----");
        funA();
    }

    public static void main(String[] args) {
        funA();
    }
}

上面的方法,执行 funA() ,然后在 funA() 内部又调用了自己,那么会重新又调用了 funA() 方法,然后又调用了自己,这样就会一直无限调用,变成了无限循环调用,执行的时候很快就报Stack Overflow的错误,栈溢出。

所以方法的递归有时候是很危险的,很容易无限调用,造成栈溢出,程序崩溃。所以方法的递归调用一定要注意 结束或跳出递归 的条件。

例如我们写一个用递归求阶乘的方法:

public class HelloJava {
    /**
     * 求阶乘
     */
    public static int factorial(int num) {
        if (num <= 1) {
            return 1;
        }

        return num * factorial(num - 1);
    }

    public static void main(String[] args) {
        int num = 5;
        int result = factorial(num);
        System.out.println(num + "的阶乘为:" + result);  // 120
    }
}

以 5 举例,求 5 的阶乘,调用了 factorial方法 ,则计算 5 乘以 4 的阶乘,然后求 4 的阶乘,重新调用了 factorial方法 ,然后计算 4 乘以 3 的阶乘,一次类推,一直得到1的阶乘,然后向上返回。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

递归方法一定得有结束的条件,否则就会无限递归导致栈溢出错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/609163.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法day03

第一题 179. 查找总价格为目标值的两个商品 本题采用前后指针和单调性规律可解&#xff1b; 解题思路如下&#xff1a; 1、设置前后指针 2、前后指针所指的两数之和大于目标数&#xff0c;右指针左移&#xff1b; 前后指针所指的两数之和小于目标数&#xff0c;左指针右移&…

软件工程复习之软件定义时期

1.什么是软件&#xff1f; 答&#xff1a;软件是程序&#xff0c;数据和文档的集合。 程序是完成指定功能的计算机可执行的指令序列。 数据是程序进行信息处理的数据结构。 文档是开发&#xff0c;使用&#xff0c;维护的图文资料。 2.软件有何特点&#xff1f; 答&#…

2024年小沙弥小视频,轻松吸引中老年观众,上手简单,轻松月入了万

利用人工智能工具制作小沙弥主题的抖音内容&#xff0c;已成为网络赚钱的新途径。这个项目主要吸引中老年人群体&#xff0c;尤其是对智慧和人生哲理感兴趣的观众。小沙弥以其温馨且启发性的内容&#xff0c;引起中老年用户的共鸣&#xff0c;为他们提供心灵慰藉。 项 目 地 …

上传自己的项目到PyPI

准备工作 已注册pypi账号pypi账号已经配置了双重验证pypi账号的token令牌&#xff08;最后上传到pypi需要这个&#xff09;pip install twine&#xff08;上传需要用到的工具&#xff09; 操作步骤 1、准备好工程2、编写setup.py3、开始上传 大功告成 在pypi查看自己包的…

Linux—— 任务规划、SELinux、ACL、磁盘介绍

任务规划&#xff1a; 未来任务的一次性调度 atatqatrm服务&#xff1a; atd周期性任务的调度 crontab 所有用户的任务列表都以文件的形式存在于系统 /var/spool/cron/用户名-l -e-u-r时间 需要执行的任务服务&#xff1a; crond系统维护任务&#xff1a; yum软件仓库缓存的…

MySQL数据库基础(数据库操作,常用数据类型,表的操作)

MySQL数据库基础&#xff08;数据库操作&#xff0c;常用数据类型&#xff0c;表的操作&#xff09; 前言 数据库的操作1.显示当前数据库2.创建数据库3.使用数据库4.删除数据库 常用数据类型1.数值类型2.字符串类型3.日期类型 表的操作1.查看表结构2.创建表3.删除表 总结 前言 …

5. 分布式链路追踪TracingFilter改造增强设计

前言 在4. 分布式链路追踪客户端工具包Starter设计一文中&#xff0c;我们实现了基础的Starter包&#xff0c;里面提供了我们自己定义的Servlet过滤器和RestTemplate拦截器&#xff0c;其中Servlet过滤器叫做HoneyTracingFilter&#xff0c;仅提供了提取SpanContext&#xff0…

等保测评技术方案

等保&#xff0c;即“网络安全等级保护”&#xff0c;是中国实施的一项信息安全保护制度&#xff0c;旨在对不同重要性的信息和信息系统实行分等级保护&#xff0c;保障国家安全、社会秩序以及公共利益。等保技术方案是指为了达到国家网络安全等级保护标准要求&#xff0c;针对…

Linux的并发与竞争

文章目录 一、并发二、竞争三、保护内容是什么四、解决并发与竞争的几种常用方法1.原子操作原子整型API函数原子位操作 API 函数 2.自旋锁自旋锁格式如下&#xff1a;自旋锁 API 函数自旋锁的使用注意事项 3.信号量信号量 API 函数信号量格式如下&#xff1a; 4.互斥体API函数如…

正交频分复用回顾(通俗易懂)

OFDM我们知道&#xff0c;叫做正交频分复用&#xff0c;它是4G的一个关键技术&#xff0c;4G的多址技术叫做OFDMA&#xff0c;也就是说4G是通过OFDM来作用户区分的&#xff0c;具体是什么意思呢&#xff1f;继续往下看。 图1 在2G和3G时代&#xff0c; 单用户都是用的一个载波…

进口原装二手 Keysight86142B 是德86142A 高性能光谱分析仪

进口原装二手 Keysight86142B 是德86142A 高性能光谱分析仪 内置测试应用程序 • 10 pm 波长精度 • 快速双扫法 • 覆盖 S、C 和 L 波段 Keysight 86142B是一款台式光谱分析仪&#xff08;OSA&#xff09;&#xff0c;最适于对功率和波长精度、动态范围和低偏振敏感性都要…

深入理解Linux中TCP/IP协议栈的实现原理与具体过程

一、Linux内核与网络体系结构 在我们了解整个linux系统的网络体系结构之前&#xff0c;我们需要对整个网络体系调用&#xff0c;初始化和交互的位置&#xff0c;同时也是Linux操作系统中最为关键的一部分代码-------内核&#xff0c;有一个初步的认知。 1、Linux内核的结构 …

ansible离线部署etcd二进制集群

目录 概述资源安装执行过程集群验证 概述 功能如下&#xff1a; ansible 2.9版本离线安装centos 7 内核离线升级cfssl 离线二进制安装etcd 3.5.13版本 二进制离线安装 资源 相关前置资源如下 资源地址Ansible离线安装地址ansible-playbook离线升级centos内核地址ansible离线…

基于springboot实现社区医院管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现社区医院管理系统演示 摘要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&…

MySQL——变量的定义与使用

新建链接&#xff0c;自带world数据库&#xff0c;里面自带city表格。 DQL # MySQL变量的定义与使用 #1、不允许数字作为开头 #2、只能用_或$符号&#xff0c;不允许使用其他符号 #3、不允许使用关键字或保留字 set userName小可爱; select userName; #标识符只影响当前查询#…

[C++]哈希应用-海量数据处理

文章目录 海量数据处理前言哈希切分问题1&#xff1a;给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址&#xff1f;问题2&#xff1a;给一个超过100G大小的log file, log中存着IP地址, 设计算法找到top K的IP&#xff1f; 位图应用问题3&…

UART、SPI 与 I2C:走线和布局指南

这是翻译自PCB Hero的一篇非常基础的文章。 还有一篇关于这三个总线的比较文章可以参照阅读一下:https://www.totalphase.com/blog/2021/12/i2c-vs-spi-vs-uart-introduction-and-comparison-similarities-differences/ I2C、SPI、UART 之间的差异及其布局指南 从8位到32位的…

ECP44304T-76是一款增强型通信处理器吗?

ABB ECP44304T-76是一款增强型通信处理器&#xff0c;专为ABB的PLC控制系统设计。 这款通信处理器的主要功能是提供PLC与其他设备或网络之间的通信接口。它支持多种通讯协议&#xff0c;包括但不限于Profibus、Ethernet、Modbus等&#xff0c;使得PLC可以轻松集成到复杂的工业…

【最大公约数 唯一分解定理 调和级数】2862. 完全子集的最大元素和

本文涉及知识点 质数、最大公约数、菲蜀定理 组合数学汇总 唯一分解定理 调和级数 LeetCode2862. 完全子集的最大元素和 给你一个下标从 1 开始、由 n 个整数组成的数组。你需要从 nums 选择一个 完全集&#xff0c;其中每对元素下标的乘积都是一个 完全平方数&#xff0c;例…

程序员学CFA——数量分析方法(六)

数量分析方法&#xff08;六&#xff09; 假设检验假设检验的步骤假设检验的基本思想与步骤估计与假设检验的区别假设检验的基本思想假设检验的步骤 假设检验的相关概念原假设与备择假设检验统计量及其分布显著性水平双尾检验与单尾检验p值第一类错误与第二类错误统计显著与经济…