1. 概述

在这个教程中,我们将探讨Java中method(String… args)method(String[])的区别。我们将一起研究如何将数组或可变长度参数列表传递给方法。

2. 将数组传递给方法

在本节中,我们将展示如何在方法的参数中声明一个String类型的数组,并在方法调用时传递相同类型的数组。

Java是一种静态类型语言,这意味着编译时就知道变量类型。程序员必须声明变量类型,无论是基本类型还是引用类型。当定义一个接受数组参数的方法时,我们期望在方法调用时明确指定要传递的数组类型

让我们看看在方法头中定义String数组参数的语法:

void capitalizeNames(String[] args)

上面方法头中的参数分解如下:

  • String[] - 类型名
  • args - 参数名
void capitalizeNames(String[] args) {
    for(int i = 0; i < args.length; i++){
       args[i] = args[i].toUpperCase();
    }
}

因此,capitalizeNames()方法有一个String数组参数args。方法头说明,当调用该方法时,它只接收一个java.lang.String[]类型的数组引用。

简而言之,当我们看到method(String[])在方法头中时,我们应该理解这个方法在被调用时接受一个String类型的单个数组作为参数。

看一个例子:

@Test
void whenCheckingArgumentClassName_thenNameShouldBeStringArray() {
    String[] names = {"john", "ade", "kofi", "imo"};
    assertNotNull(names);
    assertEquals("java.lang.String[]", names.getClass().getTypeName());
    capitalizeNames(names);
}

当我们检查capitalizeNames()方法参数names的类名时,我们得到java.lang.String[],这与方法定义中的参数匹配。如果我们尝试将不同类型的参数传递给方法,编译时会出错

@Test
void whenCheckingArgumentClassName_thenNameShouldBeStringArray() {
    ...
    int[] evenNumbers = {2, 4, 6, 8};
    capitalizeNames(evenNumbers);
}

上述代码片段会在控制台上输出编译错误消息:

incompatible types: int[] cannot be converted to java.lang.String[]

3. 可变长度参数列表

Java中的可变长度参数列表(也称为varargs)允许我们在方法调用时传递任意数量同类型的参数。

方法中可变长度参数列表的语法如下:

String[] firstLetterOfWords(String... args)

让我们分解上面方法头中的参数:

  • String… - 类型名带有省略号
  • args - 参数名
String[] firstLetterOfWords(String... args) {
    String[] firstLetter = new String[args.length];
    for(int i = 0; i < args.length; i++){
        firstLetter[i] = String.valueOf(args[i].charAt(0));
    }
    return firstLetter;
}

我们在方法签名中声明参数类型,后面跟着省略号和参数名。

使用可变长度参数列表,我们可以向方法添加任意数量相同类型的参数,因为Java将给定的参数视为数组元素处理。当在方法参数中添加varargs时,请确保类型、省略号和参数名称放在最后。

例如,以下写法是错误的:

static String[] someMethod(String... args, int number)

我们可以通过交换参数顺序,将varargs参数放在最后来修复这个问题:

static String[] someMethod(int number, String... args)

让我们测试上面编写的firstLetterOfWords方法:

@Test
void whenCheckingReturnedObjectClass_thenClassShouldBeStringArray() {
    assertEquals(String[].class, firstLetterOfWords("football", "basketball", "volleyball").getClass());
    assertEquals(3, firstLetterOfWords("football", "basketball", "volleyball").length);
}

我们知道firstLetterOfWords()方法接受String类型的可变长度参数列表,因为有省略号,且我们使用了相同的参数。测试显示,当我们访问其getClass()属性时,方法返回一个数组。当我们访问数组的长度属性时,结果为3,这与传入的参数数量匹配。

4. method(String[]) vs. method(String… args)

method(String[])表示Java方法中的String类型数组参数。它通常出现在Java类的主方法的参数中。主方法中的String[] args参数将命令行参数形成一个String数组。调用带有method(String[])的方法时,需要提供一个String数组作为参数

在定义方法时,我们只能有一个可变长度参数列表。varargs不仅限于java.lang.String类型,还可以有其他类型,如(int… args)(double… args)等。在底层,Java将使用varargs调用方法时传递的所有参数组合成一个数组。然而,我们可以在没有参数的情况下调用带有varargs参数的方法,这时它将被视为一个空数组。

args作为变量名只是一个约定——可以使用任何其他合适的名称代替。

5. 总结

在这个教程中,我们探讨了method(String[])method(String… args)之间的区别。前者是一个带有String数组参数的方法,后者是一个具有可变长度参数列表(varargs)的方法。

varargs始终作为方法参数列表中的最后一个参数出现,因此一个方法最多只能有一个varargs参数。

本教程的代码可以在GitHub上找到