Programing

Java SafeVarargs 주석, 표준 또는 모범 사례가 있습니까?

lottogame 2020. 5. 29. 07:51
반응형

Java SafeVarargs 주석, 표준 또는 모범 사례가 있습니까?


최근에 java @SafeVarargs 주석을 발견했습니다. Java의 variadic 함수를 안전하지 않은 것으로 만드는 것에 대한 인터넷 검색으로 인해 혼란스러워졌습니다 (힙 중독? 지워진 유형?). 몇 가지 사항을 알고 싶습니다.

  1. @SafeVarargs의 의미 에서 가변적 인 Java 함수가 안전하지 않은 이유는 무엇입니까 (바람직한 심도의 형태로 설명 됨)?

  2. 왜이 주석이 프로그래머의 재량에 달려 있습니까? 컴파일러가 확인할 수있는 것이 아닌가?

  3. 그의 기능이 실제로 Varag를 안전하게 지키기 위해 준수해야 할 표준이 있습니까? 그렇지 않은 경우이를 보장하기위한 모범 사례는 무엇입니까?


1) 인터넷과 StackOverflow에는 제네릭 및 varargs의 특정 문제에 대한 많은 예가 있습니다. 기본적으로 유형 매개 변수 유형의 가변 개수의 인수가있는 경우입니다.

<T> void foo(T... args);

Java에서 varargs는 컴파일 타임에 간단한 "다시 쓰기"를 수행하는 구문 설탕입니다. type의 varargs 매개 변수는 type X...의 매개 변수로 변환됩니다 X[]. 그리고이 varargs 메소드를 호출 할 때마다 컴파일러는 varargs 매개 변수에 들어가는 모든 "변수 인수"를 수집하고 다음과 같은 배열을 작성합니다 new X[] { ...(arguments go here)... }.

varargs 유형이 콘크리트와 같은 경우에 잘 작동합니다 String.... 와 같은 유형 변수 인 T...경우 T해당 호출에 대한 구체적인 유형으로 알려진 경우에도 작동 합니다. 방법은 위의 클래스의 일부 예를 들어 경우 Foo<T>, 당신은이 Foo<String>참조, 다음 호출 foo우리가 알고 있기 때문에 괜찮을 것에 TString코드에서 그 시점에서.

그러나의 "값" T이 다른 유형 매개 변수 인 경우에는 작동하지 않습니다 . Java에서는 유형 매개 변수 구성 요소 유형 ( new T[] { ... }) 의 배열을 작성할 수 없습니다 . 따라서 Java는 대신 new Object[] { ... }(여기 Object의 상한이 있습니다 T. 상한이 다른 경우 대신 대신 Object) 사용하고 컴파일러 경고를 제공합니다.

그렇다면 무엇을 만드는 new Object[]대신에 new T[]무엇이 잘못 되었나요 ? Java의 배열은 런타임에 구성 요소 유형을 알고 있습니다. 따라서 전달 된 배열 객체는 런타임에 잘못된 구성 요소 유형을 갖습니다.

varargs를 가장 일반적으로 사용하는 경우 요소를 반복하기 만하면 문제가되지 않으므로 (배열의 런타임 유형에 신경 쓰지 않아도 됨) 안전합니다.

@SafeVarargs
final <T> void foo(T... args) {
    for (T x : args) {
        // do stuff with x
    }
}

그러나 전달 된 배열의 런타임 구성 요소 유형에 의존하는 것은 안전하지 않습니다. 안전하지 않고 충돌하는 간단한 예는 다음과 같습니다.

class UnSafeVarargs
{
  static <T> T[] asArray(T... args) {
    return args;
  }

  static <T> T[] arrayOfTwo(T a, T b) {
    return asArray(a, b);
  }

  public static void main(String[] args) {
    String[] bar = arrayOfTwo("hi", "mom");
  }
}

문제는 여기에 우리의 유형에 따라 달라집니다 것입니다 args될 수 T[]로 복귀하기 위해 T[]. 그러나 실제로 런타임에 인수의 유형은의 인스턴스가 아닙니다 T[].

3) 메소드에 type 인수가있는 경우 T...(여기서 T는 모든 유형 매개 변수 임)

  • 안전 : 메소드가 배열의 요소가 인스턴스라는 사실에만 의존하는 경우 T
  • 안전하지 않은 경우 : 어레이가 인스턴스라는 사실에 의존하는 경우 T[]

배열의 런타임 유형에 의존하는 것들은 다음과 같습니다 : type으로 반환, type T[]의 매개 변수에 인수로 전달,을 T[]사용하여 배열 유형 가져 오기 .getClass(), List.toArray()Arrays.copyOf()

2) 위에서 언급 한 구별이 너무 복잡하여 자동으로 쉽게 구별 할 수 없습니다.


모범 사례를 위해 이것을 고려하십시오.

이것이 있다면 :

public <T> void doSomething(A a, B b, T... manyTs) {
    // Your code here
}

이것을 다음과 같이 변경하십시오.

public <T> void doSomething(A a, B b, T... manyTs) {
    doSomething(a, b, Arrays.asList(manyTs));
}

private <T> void doSomething(A a, B b, List<T> manyTs) {
    // Your code here
}

I've found I usually only add varargs to make it more convenient for my callers. It would almost always be more convenient for my internal implementation to use a List<>. So to piggy-back on Arrays.asList() and ensure there's no way I can introduce Heap Pollution, this is what I do.

I know this only answers your #3. newacct has given a great answer for #1 and #2 above, and I don't have enough reputation to just leave this as a comment. :P

참고URL : https://stackoverflow.com/questions/14231037/java-safevarargs-annotation-does-a-standard-or-best-practice-exist

반응형