Java에서 변수 인수가있는 메소드에 배열을 인수로 전달할 수 있습니까?


276

다음과 같은 함수를 만들 수 있기를 원합니다.

class A {
  private String extraVar;
  public String myFormat(String format, Object ... args){
    return String.format(format, extraVar, args);
  }
}

여기서 문제는이 args같은 처리 Object[]방법에있어서 myFormat, 따라서 단일 인수입니다 String.format내가 매일 싶습니다 동안 Object의이 args새로운 인수로 전달되어야한다. String.format가변 인수를 가진 메소드이기도하기 때문에 이것이 가능해야합니다.

이것이 가능하지 않은 경우와 같은 방법이 String.format(String format, Object[] args)있습니까? 이 경우 새 배열 extraVarargs사용하여 해당 메소드에 전달할 수 있습니다.


8
나는 왜이 질문이 "이것이 유효한"질문인지 궁금 할 것입니다. 당신은 그것을 시도하지 못했습니다? 과도하게 묻지 마십시오. 선보다 해를 더 많이 입게됩니다.
kamasheto

21
사실, 이것은 쉽게 테스트 할 수있었습니다. 그러나 이와 같은 질문에 대한 좋은 점은 주제를 공개하고 흥미로운 답변을 요청한다는 것입니다.
akf

2
실제로 위의 코드를 사용하여 배열 인수를 메소드의 인수로 전달하려고했습니다. 그러나 extraVar를 args 앞에 추가해야한다는 것을 알지 못했습니다. 변수 인수가 메소드로도 배열로 취급된다는 것을 알면 물론 이것은 매우 논리적입니다.
user362382

답변:


181

variadic 메소드의 기본 유형은 function(Object... args) 입니다 function(Object[] args) . Sun은 이전 버전과의 호환성을 유지하기 위해 이러한 방식으로 varargs를 추가했습니다.

그래서 당신은 단지 앞에 추가 할 수 있어야 extraVarargs하고 전화 String.format(format, args).


1
X[]메소드 에 type 인수를 전달하면 x(X... xs)Eclipse에서 다음 경고가 표시됩니다.Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
Luke Hutchison

318

예, a T...는 a의 구문 설탕 일뿐 T[]입니다.

JLS 8.4.1 형식 매개 변수

목록의 마지막 형식 매개 변수는 특별합니다. 유형에 따라 줄임표로 표시되는 가변 arity 매개 변수 일 수 있습니다 .

마지막 형식 매개 변수가 유형의 변수 arity 매개 변수 인 경우 형식 T의 형식 매개 변수를 정의하는 것으로 간주됩니다 T[]. 이 방법은 가변 arity 방법입니다. 그렇지 않으면 고정 된 arity 방법입니다. 변수 arity 메소드의 호출에는 공식 매개 변수보다 더 많은 실제 인수 표현식이 포함될 수 있습니다. 변수 arity 매개 변수 앞의 형식 매개 변수에 해당하지 않는 모든 실제 인수 표현식이 평가되고 결과가 메소드 호출에 전달 될 배열에 저장됩니다.

다음은 설명하는 예입니다.

public static String ezFormat(Object... args) {
    String format = new String(new char[args.length])
        .replace("\0", "[ %s ]");
    return String.format(format, args);
}
public static void main(String... args) {
    System.out.println(ezFormat("A", "B", "C"));
    // prints "[ A ][ B ][ C ]"
}

그리고 네, 위의 main다시 때문에 방법은 유효 String...단지입니다 String[]. 또한 배열은 공변량이므로 a String[]는 a Object[]이므로 ezFormat(args)어느 쪽이든 호출 할 수 있습니다 .

또한보십시오


Varargs gotchas # 1 : 추월 null

varargs가 해결되는 방법은 매우 복잡하며 때로는 놀라게 할 수도 있습니다.

이 예제를 고려하십시오.

static void count(Object... objs) {
    System.out.println(objs.length);
}

count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!

varargs가 해결되는 방식으로 인해 마지막 명령문은로 호출되며 objs = null물론 발생 NullPointerException합니다 objs.length. nullvarargs 매개 변수에 하나의 인수 를 제공 하려면 다음 중 하나를 수행하십시오.

count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"

관련 질문

다음은 varargs를 처리 할 때 사람들이 질문 한 일부 샘플입니다.


Vararg gotchas # 2 : 추가 인수 추가

알다시피, 다음은 "작동하지 않습니다":

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(myArgs, "Z"));
    // prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"

varargs가 작동하는 방식 때문에 ezFormat실제로 두 개의 인수를 얻습니다. 첫 번째는 a String[]이고 두 번째는 a String입니다. 배열을 varargs에 전달하고 해당 요소를 개별 인수로 인식하고 추가 인수를 추가 해야하는 경우 추가 요소를 수용하는 다른 배열 을 만들 수밖에 없습니다 .

유용한 도우미 메소드는 다음과 같습니다.

static <T> T[] append(T[] arr, T lastElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    arr[N] = lastElement;
    return arr;
}
static <T> T[] prepend(T[] arr, T firstElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    System.arraycopy(arr, 0, arr, 1, N);
    arr[0] = firstElement;
    return arr;
}

이제 다음을 수행 할 수 있습니다.

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(append(myArgs, "Z")));
    // prints "[ A ][ B ][ C ][ Z ]"

    System.out.println(ezFormat(prepend(myArgs, "Z")));
    // prints "[ Z ][ A ][ B ][ C ]"

Varargs gotchas # 3 : 프리미티브 배열 전달

"작동하지 않습니다":

    int[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ [I@13c5982 ]"

Varargs는 참조 유형에서만 작동합니다. 오토 박싱은 기본 배열에는 적용되지 않습니다. 다음과 같이 작동합니다.

    Integer[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ 1 ][ 2 ][ 3 ]"

2
Object ... variadic 매개 변수를 사용하면 컴파일러에서 기본 인수조차도 Object에 자동 상자 화 될 수있는 서명 사이의 모호성을 식별하므로 추가 서명을 사용하기가 어렵습니다.
eel ghEEz

7
메서드에 Object ... 형식의 마지막 매개 변수가 있고 예를 들어 String []을 전달하는 메서드를 호출하는 경우 누락 된 문제가 있습니다. 컴파일러는 배열이 varargs의 첫 번째 항목인지 또는 모든 varargs와 동등한 지 알 수 없습니다. 경고합니다.
Snicolas

X[]메소드 에 type 인수를 전달하면 x(X... xs)Eclipse에서 다음 경고가 표시됩니다.Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
Luke Hutchison

23

배열을 전달해도 괜찮습니다. 사실 같은 정도입니다.

String.format("%s %s", "hello", "world!");

와 같다

String.format("%s %s", new Object[] { "hello", "world!"});

기본 구문은 vararg 매개 변수 의 배열을 기대하기 때문에 컴파일러는 구문 설탕입니다. 컴파일러는 첫 번째 것을 두 번째로 변환합니다 .

보다


4

jasonmp85는 다른 배열을에 전달하는 것에 적합합니다 String.format. 배열의 크기는 일단 구성되면 변경할 수 없으므로 기존 배열을 수정하는 대신 새 배열을 전달해야합니다.

Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar; 
String.format(format, extraVar, args);

1

나는 같은 문제가 있었다.

String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;

그런 다음 obj를 varargs 인수로 전달했습니다. 효과가있었습니다.


2
그것도 추가하십시오.
Mathews Sunny
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.