Skip to content

Lesson3 Java的自定义函数与参数

目录

  1. Java方法的定义和使用
  2. Java传参的三种方式
  3. 形式参数与实际参数
  4. 课后练习

1. Java方法的定义和使用

在Java中,方法(Methods)是用来执行特定任务的代码块,可以被重复调用。

1.1 方法的定义语法

Java
1
2
3
4
5
修饰符 返回类型 方法名(参数列表) {
  // 方法体
  // 可以包含一系列的语句来实现特定功能
  // 可以使用参数,并且可能会返回一个值
 }
  • 修饰符(Modifiers):可以是 publicprivateprotected
  • 返回类型(Return Type):方法可以返回一个值的类型,如果方法不返回任何值,则使用 void
  • 方法名(Method Name):方法的名称,用来在程序中调用该方法。
  • 参数列表(Parameter List):可选的参数,用于接收方法执行所需的输入数据。
  • 方法体(Method Body):包含了实现方法功能的一系列语句。

1.2 修饰符(Modifiers)

修饰符定义了方法的访问级别和行为特性:

  • public:可以被任何类访问。
  • private:只能在同一个类中访问。
  • protected:可以被同一个包内的类和子类访问。

对于现阶段,只需掌握public类型方法即可。

public

  • 描述public 修饰符表示方法可以被任何类访问。
  • 示例
Java
1
2
3
4
5
6
7
8
9
public class Main {
    public static void greet(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public static void main(String[] args) {
        greet("Alice"); // 输出:Hello, Alice!
    }
}

1.3 返回类型

返回类型指定了方法返回的数据类型。如果方法不返回任何值,则使用 void

示例1:返回类型为 int

Java
1
2
3
4
5
public class MathUtils {
    public int add(int a, int b) {
        return a + b;
    }
}

示例2:返回类型为 void

Java
1
2
3
4
5
public class Printer {
    public void printMessage(String message) {
        System.out.println(message);
    }
}

1.4 方法名命名规则

方法名必须是一个合法的标识符(identifier),遵循以下规则:

  • 方法名可以包含字母、数字、下划线和美元符号。
  • 方法名不能以数字开头。
  • 方法名不应该是Java关键字。
  • 方法名应该具有描述性,清晰地表达方法的功能。

2. Java传参的两种方式

在Java中,我们可以使用不同的方式来传递参数给方法或函数。下面将介绍Java传参的两种常见方式:按值传递和按引用传递。

2.1 按值传递

按值传递意味着将参数的值复制一份,然后将这份复制的值传递给方法。在方法内部对参数的修改不会影响到原始参数。这种方式适用于基本数据类型(如intdouble等)。

示例

Java
public void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

public static void main(String[] args) {
    int x = 10;
    int y = 20;
    swap(x, y);
    System.out.println("x = " + x); // 输出:x = 10
    System.out.println("y = " + y); // 输出:y = 20
}
在这个例子中,虽然swap方法内部交换了ab的值,但这并不会影响main方法中的xy,因为传递的是值的副本。

2.2 按引用传递

按引用传递意味着将参数的引用(内存地址)传递给方法。在方法内部对参数的修改会影响到原始参数。在Java中,除了基本数据类型,其他所有的数据类型(如数组和对象)都是按引用传递的。

示例

Java
public void swap(int[] array) {
    int temp = array[0];
    array[0] = array[1];
    array[1] = temp;
}

public static void main(String[] args) {
    int[] nums = {10, 20};
    swap(nums);
    System.out.println("nums[0] = " + nums[0]); // 输出:nums[0] = 20
    System.out.println("nums[1] = " + nums[1]); // 输出:nums[1] = 10
}
在这个例子中,传递了一个数组numsswap方法,方法内部对数组元素的交换操作会直接影响到原始数组。

总结

  • 按值传递:传递参数值的副本,不会影响原始参数。
  • 按引用传递:传递参数的引用,方法内部的修改会影响原始参数。

根据具体的需求,选择合适的参数传递方式可以更好地实现程序功能。

3. 形式参数与实际参数

在Java中,函数的参数分为形式参数(形参)和实际参数(实参)。这两者在函数调用和定义中扮演不同的角色:

3.1 形式参数(Formal Parameters)

形式参数是在函数定义时声明的参数,它们作为函数的一部分,用来接收调用函数时传递的实际参数的值。形式参数在函数定义的括号内部声明,并指定它们的类型和名称。例如,以下是一个简单的函数定义,它有两个形式参数:

Java
1
2
3
4
5
public void calculateSum(int a, int b) {
    // 函数体
    int sum = a + b;
    System.out.println("Sum: " + sum);
}

在这个例子中,calculateSum 是一个函数,它接受两个形式参数 ab,它们的类型都是 int。这些形式参数在函数被调用时用于接收传递给函数的实际参数的值。

3.2 实际参数(Actual Arguments)

实际参数是在调用函数时传递给函数的值或者表达式。它们是真正用来执行函数操作的数据。在函数调用时,实际参数被传递给函数的形式参数。例如,下面是如何调用上面定义的 calculateSum 函数,并传递实际参数:

Java
public class Main {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;

        // 调用函数并传递实际参数
        calculateSum(num1, num2);
    }

    // 定义函数
    public static void calculateSum(int a, int b) {
        // 函数体
        int sum = a + b;
        System.out.println("Sum: " + sum);
    }
}

在这个示例中,num1num2main 函数中的两个变量,它们作为实际参数传递给 calculateSum 函数。在函数调用 calculateSum(num1, num2); 中,num1num2 分别传递给 ab 形式参数,进而在函数内部计算它们的和。

3.3 总结

  • 形式参数是在函数定义中声明的变量,它们用于接收实际参数的值。
  • 实际参数是在函数调用时传递给函数的值或表达式,它们被传递给形式参数,用于函数执行。

4. 课后练习

4.1 方法的定义

题目 1: 在MathUtils中定义 multiply 方法,它会接受两个 float 参数,并返回它们的乘积。

Java
public class MathUtils {

    // To be implemented

    public static void main(String[] args) {
        MathUtils utils = new MathUtils();
        float product = utils.multiply(5.5f, 3.2f);
        System.out.println("The product is: " + product);  // 输出应该是 17.6
    }
}
解答
Java
public class MathUtils {
    public float multiply(float a, float b) {
        return a * b;
    }

    public static void main(String[] args) {
        MathUtils utils = new MathUtils();
        float product = utils.multiply(5.5f, 3.2f);
        System.out.println("The product is: " + product);  // 输出应该是 17.6
    }
}

题目 2: 请将下列代码(Lesson2课后练习)的点单、打印客户点单内容、计算订单总价三个功能封装成独立的方法。

Java
import java.util.Scanner;

public class RestaurantOrder {
    public static void main(String[] args) {
        // 定义价格常量
        final double BURGER_PRICE = 12.5;
        final double FRIES_PRICE = 6.0;
        final double COKE_PRICE = 4.5;

        // 创建 Scanner 对象以获取用户输入
        Scanner scanner = new Scanner(System.in);

        // 初始化总销售额
        double totalSales = 0.0;

        // 开始循环,直到顾客选择退出
        while (true) {
            // 初始化点单数量
            int option = 0;
            int burgers = 0;
            int fries = 0;
            int cokes = 0;

            // 获取用户点单
            System.out.print("\n请点单(输入-1退出,其他整数进入点单):");
            option = scanner.nextInt();

            // 如果输入为-1,则退出循环
            if (option == -1) {
                break;
            }

            // 获取各项食物的数量
            System.out.print("请输入汉堡的数量:");
            burgers = scanner.nextInt();

            System.out.print("请输入薯条的数量:");
            fries = scanner.nextInt();

            System.out.print("请输入可乐的数量:");
            cokes = scanner.nextInt();

            // 打印客户点单内容
            System.out.println("\n客户点单内容:");
            if (burgers > 0) {
                System.out.println("汉堡 x " + burgers);
            }
            if (fries > 0) {
                System.out.println("薯条 x " + fries);
            }
            if (cokes > 0) {
                System.out.println("可乐 x " + cokes);
            }

            // 计算本次点单的总价
            double orderTotal = burgers * BURGER_PRICE + fries * FRIES_PRICE + cokes * COKE_PRICE;

            // 累加到总销售额
            totalSales += orderTotal;

            // 打印本次点单的总价
            System.out.println("\n本次点单总价:" + orderTotal + " 元");
        }

        // 打印所有顾客的总销售额
        System.out.println("\n所有顾客的总销售额:" + totalSales + " 元");

        // 关闭 Scanner
        scanner.close();
    }
}

参考答案

Java
import java.util.Scanner;

public class RestaurantOrder {
    // 定义价格常量
    private static final double BURGER_PRICE = 12.5;
    private static final double FRIES_PRICE = 6.0;
    private static final double COKE_PRICE = 4.5;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double totalSales = 0.0;

        while (true) {
            int option = getUserOption(scanner);

            if (option == -1) {
                break;
            }

            int burgers = getQuantity(scanner, "汉堡");
            int fries = getQuantity(scanner, "薯条");
            int cokes = getQuantity(scanner, "可乐");

            printOrderDetails(burgers, fries, cokes);
            double orderTotal = calculateOrderTotal(burgers, fries, cokes);
            totalSales += orderTotal;

            System.out.println("\n本次点单总价:" + orderTotal + " 元");
        }

        System.out.println("\n所有顾客的总销售额:" + totalSales + " 元");

        scanner.close();
    }

    // 获取用户的点单选项
    private static int getUserOption(Scanner scanner) {
        System.out.print("\n请点单(输入-1退出,其他整数进入点单):");
        return scanner.nextInt();
    }

    // 获取特定商品的数量
    private static int getQuantity(Scanner scanner, String itemName) {
        System.out.print("请输入" + itemName + "的数量:");
        return scanner.nextInt();
    }

    // 打印客户点单内容
    private static void printOrderDetails(int burgers, int fries, int cokes) {
        System.out.println("\n客户点单内容:");
        if (burgers > 0) {
            System.out.println("汉堡 x " + burgers);
        }
        if (fries > 0) {
            System.out.println("薯条 x " + fries);
        }
        if (cokes > 0) {
            System.out.println("可乐 x " + cokes);
        }
    }

    // 计算订单总价
    private static double calculateOrderTotal(int burgers, int fries, int cokes) {
        return burgers * BURGER_PRICE + fries * FRIES_PRICE + cokes * COKE_PRICE;
    }
}

4.2 形式参数与实际参数

判断题

题目: 观察以下代码,判断参数 xy 是实际参数还是形式参数,它们是否会被修改,modifyValues 方法是否会对它们产生影响。选择正确的答案并解释原因。

Java
public class Test {
    public static void main(String[] args) {
        int x = 5;
        int y = 10;
        modifyValues(x, y);
        System.out.println("x = " + x + ", y = " + y);
    }

    public static void modifyValues(int a, int b) {
        a = a * 2;
        b = b + 3;
    }
}

A. 正确,xy 的值会被修改

B. 错误,xy 的值不会被修改

答案: B. 错误

理由: 在 Java 中,方法参数是按值传递的。当 modifyValues 方法被调用时,abxy 的副本,对它们的修改不会影响到原始的 xy。因此,xy 的值不会被修改,输出仍然是 x = 5, y = 10