JAVA学习笔记 07 - 方法

本文是Java基础课程的第七课。主要介绍Java中的方法,包括方法如何声明和使用、方法的返回值及参数、方法的可变参数、方法重载、构造方法、变量的作用域和生命周期等问题

一、Java中的方法

1、方法的概念

在Java中,从面向对象哲学来说,方法对象所具有的行为。就方法本身来说,方法完成特定功能的、相对独立程序段,与其它编程语言中的子程序函数等概念相当方法一旦声明可以在不同的程序段中多次调用

在之前的内容中已经使用过多次由JDK提供的方法,如:

System.out.println("Hello World"); 		// println() 是一个方法
new Random().nextInt();					// nextInt() 是一个方法
"Hello World".length();					// length() 是一个方法

2、为什么使用方法

通过使用方法,可以:

  1. 实现对象行为,使程序符合面向对象哲学
  2. 使程序变得更简短清晰
  3. 提高了代码的重用性
  4. 可以提高程序开发效率
  5. 利于程序维护

二、方法的声明

Java中,声明一个方法的语法如下:

[修饰符] 返回值类型 方法名称([参数列表]) {
	// 方法体
}

说明:

  • 声明方法的语句中包括方法头方法声明)和方法体两部分。其中方法头方法声明)确定方法名称形式参数名称类型顺序返回值类型和方法的访问权限方法体由括在花括号内语句组成,这些语句实现方法功能
  • 方法的修饰符可选的,最常用的修饰符是public,表示方式是公开的。关于修饰符的详细内容将在以后的章节中介绍。
  • 返回值类型反映方法完成功能后返回运算结果数据类型如果方法没有返回值,使用void关键字声明。
  • 方法名称符合标识符命名规范,并遵守约定,使用动词动宾短语见名知意,符合驼峰式命名法
  • 方法的参数列表指定在调用该方法时,应该传递的参数顺序个数数据类型。参数列表中可以包含若干个参数(没有、一个或多个),相邻的两个参数之间用逗号,隔开
  • 方法声明中的方法头方法声明),对于调用方法的开发者来说,便可以认为是API,即应用程序编程接口

下面是一个示例:

package com.codeke.java.test;

public class MathUtils {
    /**
     * 将两个整数相乘并打印结果
     * @param num1 第一个参与相乘的整数
     * @param num2 第二个参与相乘的整数
     */
    public void multiplyAndPrint(int num1, int num2) {
        int result = num1 * num2;
        System.out.printf("%d与%d相乘的结果是%d\n", num1, num2, result);
    }

    /**
     * 将两个整数相加并返回结果
     * @param num1 第一个参与相加的整数
     * @param num2 第二个参与相加的整数
     * @return 相加的结果
     */
    public int add(int num1, int num2) {
        return num1 + num2;
    }
}

说明:

  • 该示例中声明了一个类,名叫MathUtils,该类中声明了两个方法。
  • multiplyAndPrint(int num1, int num2)方法可以将两个整数相乘并打印结果。
  • add(int num1, int num2)方法可以将两个整数相加并返回结果,注意该方法中的return语句,对于有返回值的方法,方法体中通过return语句来返回值,详细内容将在后面的内容中介绍。

三、方法的调用

调用方法,即执行该方法发出调用的方法称为主调方法被调用的方法称为被调方法。方法调用一般情况下由对象使用.操作符完成,语法格式如下:

对象.方法名([参数1, 参数2, ..., 参数n]);

说明:

  • 参数个数数据类型与被调方法参数列表对应
  • 被调方法有返回值的时候,通常应在主调方法定义变量存储返回值
  • 有些方法可以使用类名直接调用,将在后面的章节中介绍。

下面是一个示例:

package com.codeke.java.test;

public class Test {
	public static void main(String[] args) {
		// 实例化一个MathUtils类的对象,并赋值给MathUtils类型的变量mu
		MathUtils mu = new MathUtils();
		// 通过mu调用multiplyAndPrint(int num1, int num2)方法
		mu.multiplyAndPrint(2, 3);
		// 通过mu调用add(int num1, int num2)方法,并赋值给变量result
		int result = mu.add(1, 2);
		// 打印result
		System.out.println("result = " + result);
	}
}

四、方法的返回值

方法的返回值被调方法调用后返回主调方法数据。大多数情况下,方法被调用后都需要告诉主调方法运算或处理的结果,此时便需要方法的返回值。

通常方法的设计应当遵循功能单一原则,即一个方法只做一件简单而明确的事,像前面例子中的multiplyAndPrint(int num1, int num2)方法,即包含了进行相乘运算的功能,也包含了打印结果的功能,违背了方法功能单一原则。更好的方式应该将打印结果的功能从该方法中移除,将结果返回,交由主调方法去处理。
下面是修改后的示例:
修改后的MathUtils类源码:

package com.codeke.java.test;

public class MathUtils {
    /**
     * 将两个整数相乘并返回结果
     * @param num1 第一个参与相乘的整数
     * @param num2 第二个参与相乘的整数
     * @return 相乘的结果
     */
    public int multiply(int num1, int num2) {
        int result = num1 * num2;
        return result;
    }

    /**
     * 将两个整数相加并返回结果
     * @param num1 第一个参与相加的整数
     * @param num2 第二个参与相加的整数
     * @return 相加的结果
     */
    public int add(int num1, int num2) {
        return num1 + num2;
    }
}

说明:

  • 方法需要向主调方法返回值时,方法声明中要明确返回值类型方法体中通过return语句返回值,语法格式如下:
    return [表达式];
    
    当调用方法时,方法返回值return后面表达式的值返回值类型必须与方法声明返回值类型一致
  • 被调方法只能给主调方法返回一次数据
  • 在方法执行过程中,一旦执行return语句方法结束执行返回
  • 在返回值类型声明为void的方法中,可以使用return;结束方法执行。

五、方法的参数

1、方法传参

方法的参数即调用方法时主调方法依据被调方法声明的参数列表传递给被调方法数据。调用方法时,主调方法传入参数称之为实际参数实参),被调方法中用来接收数据的参数称之为形式参数形参)。通常在设计方法时,将方法被调用时会变化的数据设计成方法的参数,可以使方法更加灵活的根据调用者的需要进行处理。
下面是一个示例:
修改后的MathUtils类源码:

public class MathUtils {
	/**
	 * 将两个整数相乘并返回结果
	 * @param num1 第一个参与相乘的整数
	 * @param num2 第二个参与相乘的整数
	 * @return 相乘的结果
	 */
	public int multiply(int num1, int num2) {
		int result = num1 * num2;
		return result;
	}

	/**
	 * 将两个整数相加并返回结果
	 * @param num1 第一个参与相加的整数
	 * @param num2 第二个参与相加的整数
	 * @return 相加的结果
	 */
	public int add(int num1, int num2) {
		return num1 + num2;
	}

	/**
	 * 求两个整数的最大公约数
	 * @param num1 参与运算的第一个整数
	 * @param num2 参与运算的第二个整数
	 * @return 参与运算的两个整数的最大公约数
	 */
	public int getGCD(int num1, int num2) {
		while (true) {
			if (num1 < num2) {
				int temp = num1;
				num1 = num2;
				num2 = temp;
			}
			int remainder = num1 % num2;
			if (remainder == 0) {
				return num2;
			} else {
				num1 = num2;
				num2 = remainder;
			}
		}
	}
}

Test类源码:

package com.codeke.java.test;

public class Test {
	public static void main(String[] args) {
		// 实例化一个MathUtils类的对象,并赋值给MathUtils类型的变量mu
		MathUtils mu = new MathUtils();

		// 定义两个int类型的变量number1和number2,分别存储数字319和377
		int number1 = 319, number2 = 377;

		// 通过mu调用add(int num1, int num2)方法,并赋值给变量sum
		// 注意方法传参时,实参的顺序、类型、数量均要与方法的参数列表相同
		int sum = mu.add(number1, number2);
		// 打印sum
		System.out.println("sum = " + sum);

		// 通过mu调用getGCD(int num1, int num2)方法,并赋值给变量gcd
		// 注意方法传参时,实参的顺序、类型、数量均要与方法的参数列表相同
		int gcd = mu.getGCD(number1, number2);
		// 打印gcd
		System.out.println("gcd = " + gcd);
	}
}

说明:

  • MathUtils类中新声明了方法getGCD(int num1, int num2),用来计算两个整数的最大公约数(Greatest Common Divisor),使用了辗转相除法
  • Test类的main()方法中实例化一个MathUtils类的对象,并赋值给MathUtils类型的变量mu,通过mu调用了add(int num1, int num2)getGCD(int num1, int num2)方法传参时,实参顺序数据类型数量均要与方法参数列表相同
  • 另外,当被调用的方法不需要传参数时,方法声明时和调用方法名后()不能省略。参数列表的设计要根据实际情况来定,参数调用不便参数方法不灵活

2、方法传参时基本数据类型和引用数据类型的内存变化

下面是另外一个示例:
修改后的MathUtils类部分源码:

package com.codeke.java.test;

public class MathUtils {
	/**
	 * 计算一个int类型整数的平方,并赋值回原变量
	 * @param num 需要计算平方的整数
	 */
	public void square(int num) {
		num = num * num;
	}

	/**
	 * 计算一个int类型数组中每个元素的平方,并赋值回原元素
	 * @param nums 需要计算元素平方的数组
	 */
	public void square(int[] nums) {
		for (int i = 0; i < nums.length; i++) {
			nums[i] = nums[i] * nums[i];
		}
	}
}

Test类源码:

public class Test {
	public static void main(String[] args) {
		// 实例化一个MathUtils类的对象,并赋值给MathUtils类型的变量mu
		MathUtils mu = new MathUtils();

		// 通过mu调用square(int num)方法,方法中对形参计算平方并赋值
		// 注意该方法并没有返回值,观察方法中形参的改变是否会影响实参
		int num = 3;
		mu.square(num);
		System.out.println("num = " + num);

		// 通过mu调用square(int[] nums)方法,方法中对形参中的每个元素计算平方并赋值
		// 注意该方法并没有返回值,观察方法中形参的改变是否会影响实参
		int[] nums = {3};
		mu.square(nums);
		System.out.println("nums[0] = " + nums[0]);
	}
}

说明:

  • 方法传参即是一个变量赋值的过程。根据前面章节中所介绍的基本数据类型的变量相互赋值和引用数据类型的变量相互赋值时的区别,即可理解上例中代码的执行原理。
  • 代码System.out.println("num = " + num)执行时,输出结果为3,被调方法中的形参发生变化时,主调方法中的实参并没有受影响。图示如下:
    在这里插入图片描述
  • 代码System.out.println("nums[0] = " + nums[0])执行时,输出结果为9,被调方法中的形参发生变化时,主调方法中的实参也发生了变化。图示如下:
    在这里插入图片描述

3、方法的可变参数

设计方法时,如果参数类型可以确定,但个数不确定,可以使用可变参数
下面是一个示例:
修改后的MathUtils类部分源码:

package com.codeke.java.test;

public class MathUtils {
	/**
	 * 将若干个整数相加并返回结果
	 * @param nums 参与相加的整数,可变参数
	 * @return 相加的结果
	 */
	public int add(int ... nums){
		int sum = 0;
		// 参数nums其实是一个int类型的数组
		if(nums instanceof int[]){
			System.out.println("nums是一个int类型的数组");
		}
		// 循环累加
		for (int num : nums) {
			sum += num;
		}
		return sum;
	}
}

Test类源码:

package com.codeke.java.test;

public class Test {
	public static void main(String[] args) {
		// 实例化一个MathUtils类的对象,并赋值给MathUtils类型的变量mu
		MathUtils mu = new MathUtils();

		// 通过mu调用add(int ... nums)方法,累加若干个整数并返回结果
		// 该方法声明时使用了可变参数,传参时参数的个数不受限制
		int sum1 = mu.add(1, 3, 5, 7, 9, 11);
		System.out.println("sum1 = " + sum1);

		// 可变参数其实就是数组
		int[] nums = {2, 4, 6, 8, 10};
		int sum2 = mu.add(nums);
		System.out.println("sum2 = " + sum2);
	}
}

说明:

  • 可变参数其实就是数组。上例中instanceof运算符用来判断对象是否是特定类的一个实例
  • 参数列表中只能有一项可变参数,且必须位于参数列表最后

六、方法的重载

一个类中,多个方法具有相同方法名称,但却具有不同参数列表,与返回值无关,称作方法重载(overload)。
下面是一个示例:
修改后的MathUtils类部分源码:

package com.codeke.java.test;

public class MathUtils {
	/**
	 * 将两个整数相乘并返回结果
	 * @param num1 第一个参与相乘的整数
	 * @param num2 第二个参与相乘的整数
	 * @return 相乘的结果
	 */
	public int multiply(int num1, int num2) {
		return num1 * num2;
	}

	/**
	 * 将两个浮点相乘并返回结果
	 * @param num1 第一个参与相乘的浮点数
	 * @param num2 第二个参与相乘的浮点数
	 * @return 相乘的结果
	 */
	public double multiply(double num1, double num2) {
		return num1 * num2;
	}

	/**
	 * 将两个整数相加并返回结果
	 * @param num1 第一个参与相加的整数
	 * @param num2 第二个参与相加的整数
	 * @return 相加的结果
	 */
	public int add(int num1, int num2) {
		return num1 + num2;
	}

	/**
	 * 将两个浮点数相加并返回结果
	 * @param num1 第一个参与相加的浮点数
	 * @param num2 第二个参与相加的浮点数
	 * @return 相加的结果
	 */
	public double add(double num1, double num2) {
		return num1 + num2;
	}
}

Test类源码:

package com.codeke.java.test;

public class Test {
	public static void main(String[] args) {
		// 实例化一个MathUtils类的对象,并赋值给MathUtils类型的变量mu
		MathUtils mu = new MathUtils();

		// 调用multiply(int num1, int num2)方法
		int result1 = mu.multiply(3, 4);
		System.out.println("result1 = " + result1);

		// 调用multiply(double num1, double num2)方法
		double result2 = mu.multiply(3.14, 6.18);
		System.out.println("result2 = " + result2);

		// 调用add(int num1, int num2)方法
		int result3 = mu.add(3,4);
		System.out.println("result3 = " + result3);

		// 调用add(double num1, double num2)方法
		double result4 = mu.add(3.12, 6.18);
		System.out.println("result4 = " + result4);
	}
}

说明:

  • 参数列表不同,是指参数个数参数数据类型参数顺序不同。比如以下是正确的方法重载的例子:
    public double area(double a);
    public double area(int a, double b);
    public double area(double a, int b);
    
    而以下是错误的方法重载的例子:
    public int calc(int a, int b);
    public void calc(int x, int y);
    
    两个calc()方法虽然返回值类型和参数名称不同,但参数个数、类型和顺序完全相同,也就是说它们的参数列表是相同的。
  • 调用方法时,方法名和传入的参数共同决定具体调用哪个方法
  • JDK API中有众多方法重载的例子,比如String类的substring([参数])indexOf([参数])lastIndexOf([参数])方法,PrintStream类的println()方法等。

七、构造方法

类中有一种特殊方法,其方法名与类名相同没有返回值类型,这种方法叫构造方法,也叫构造函数构造器
下面是一个示例:

public class Student {
	// 声明成员变量
	String name;		// 姓名
	int age;			// 年龄
	String studentNo;	// 学号

	// 声明方法
	// 没有参数的构造方法
	public Student (){
		System.out.println("Student类无参数的构造方法被调用");
	}
	
	// 有一个参数的构造方法
	public Student (String name) {
		this.name = name;
		System.out.println("Student类含有参数name的构造方法被调用");
	}
	
	// 有三个参数的构造方法
	public Student (String name, int age, String studentNo) {
		this.name = name;
		this.age = age;
		this.studentNo = studentNo;
		System.out.println("Student类含有参数name、age、studentNo的构造方法被调用");
	}

	// 自我介绍
	void introduce(){
		System.out.printf("大家好,我是%s,我今年%d岁,我的学号是:%s", name, age, studentNo);
	}
}

说明:

  • 构造方法主要用来在创建对象时为对象的成员变量赋初始值
  • 构造方法不允许使用对象调用,只有在new运算符实例化对象时才会被自动调用
  • 如果类中不显示声明构造方法,系统会为类默认提供无参数构造方法。如果自定义构造方法,系统默认构造方法不存在了。
  • 一个类可以声明多个构造方法,即构造方法重载,满足方法重载的要求即可。
  • 上例中使用了this关键字,在Java中,this可以引用当前类对象,关于该关键字,将在后面的章节中展开介绍。

八、变量的作用域和生命周期

1、变量的作用域

变量作用域就是指一个变量定义后,在程序的什么地方能够使用

在Java中,一对大括号 { } 包含的区域,也被称之为一个代码块(语句块)。使用大括号{ }的地方有:类声明、方法声明、方法中的循环体、分支条件后的语句等,一个变量作用域只被限制在该变量声明所在的代码块中(也就是离该变量的声明语句最近的大括号内)。

方法中声明的变量,称为局部变量,方法的形式参数方法的局部变量局部变量只能在当前方法使用;在判断代码块声明变量只能当前判断代码块使用,当前判断代码块之外不能正常使用;对循环代码块也是一样

声明在类中,但在方法之外的变量称为成员变量。被static关键字修饰的成员变量整个类声明里成员方法中都可以使用;没有被static关键字修饰的成员变量整个类声明里没有被static关键字修饰的成员方法中都可以使用。有时在一个方法中,会遇到局部变量成员变量同名的情况,此时,直接使用变量名其实是在使用局部变量,如果要使用成员变量需要this.成员变量名

2、变量的生命周期

变量生命周期是指变量什么时候分配内存什么时候从内存中回收

对于局部变量,会在方法语句块执行创建(在栈中分配内存),当它们执行完成后,变量随之销毁。另外,局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

对于没有被static关键字修饰的成员变量,会在对象创建的时候创建,在对象被销毁的时候销毁在堆中分配内存)。另外,成员变量在创建时具有默认值数值型变量的默认值是0整型0浮点型0.0),字符型变量的默认值是'\u0000'布尔型变量的默认值是false引用类型变量的默认值是null

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值