Programing

Java SafeVargs 주석, 표준 또는 모범 사례가 있는가?

c10106 2022. 4. 26. 12:50
반응형

Java SafeVargs 주석, 표준 또는 모범 사례가 있는가?

나는 최근에 자바를 우연히 만났다.@SafeVarargs주석을 달다무엇이 자바에서 다양한 기능을 안전하지 않게 만드는지 구글링하는 것은 나를 다소 혼란스럽게 만들었다.지워진 활자?) 그래서 나는 몇 가지를 알고 싶다.

  1. 다양한 Java 기능을 안전하지 않게 만드는 것은?@SafeVarargs감지(심층적인 예제의 형태로 설명됨)?

  2. 왜 이 주석을 프로그래머의 재량에 맡기는가?이것은 컴파일러가 확인할 수 있어야 하는 것이 아닌가?

  3. 그의 기능이 정말로 안전하다는 것을 확실히 하기 위해 반드시 지켜야 할 표준이 있는가?그렇지 않다면 이를 보장하기 위한 모범적 실무 지침은 무엇인가?

1) 인터넷과 StackOverflow에는 제네릭과 바라그(varg)의 특정 이슈에 대한 많은 예들이 있다.기본적으로 형식 매개 변수 유형의 변수 개수가 다음과 같은 경우:

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

자바에서 vargs는 compile time에 간단한 "re-writing"을 겪는 통사설탕이다: vargs parameter of type.X...유형 매개변수로 변환됨X[]; 그리고 이 vargs 방법에 대한 호출을 할 때마다, 컴파일러는 vargs 매개 변수에 들어가는 모든 "vargs 인수"를 수집하고, 같은 배열을 만든다.new X[] { ...(arguments go here)... }.

이것은 바르그 타입이 다음과 같이 콘크리트일 때 잘 작동한다.String.... 다음과 같은 유형 변수일 때T..., 그것은 또한 다음에 작동한다.T상기 방법이 클래스의 일부인 경우, 해당 호출에 대한 구체적인 유형으로 알려져 있다.Foo<T>, 그리고 너는Foo<String>참조, 그런 다음 호출foo우리가 알고 있기 때문에 괜찮을 것이다.T이다String암호의 바로 그 시점에

그러나 의 "가치"일 때는 효과가 없다.T다른 유형의 매개 변수.Java에서는, 타입 파라미터 컴포넌트 타입의 배열을 만드는 것이 불가능하다 (new T[] { ... }그래서 자바는 대신new Object[] { ... }(여기)Object의 상한이다T; 상한이 다른 것이 있다면, 그것 대신에 그것일 것이다.Object)) 그런 다음 컴파일러 경고를 한다.

그래서 창조하는 것이 무엇이 잘못되었는가?new Object[]대신에new T[]아니면 뭐?자바 어레이는 런타임에 해당 구성 요소 유형을 알고 있다.따라서, 전달된 어레이 개체는 런타임에 잘못된 구성 요소 유형을 갖게 될 것이다.

아마도 가장 일반적으로 사용되는 바라그(varg)의 경우, 단순히 요소 위에 반복하기 위해 이것은 문제가 되지 않으므로(배열의 런타임 유형에 상관하지 않음) 안전하다.

@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) 자신의 방법에 유형이 있는 인수가 있는 경우T...(여기서 T는 임의의 유형 매개변수임), 그리고 다음을 수행한다.

  • 안전: 어레이의 요소가 인스턴스(instance)라는 사실에만 의존하는 경우T
  • 안전하지 않음: 어레이가 의 인스턴스인지에 따라 달라지는 경우T[]

어레이의 런타임 유형에 따라 달라지는 항목: 유형으로 반환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
}

나는 내 방문자들이 더 편리하게 하기 위해 보통 바르그만 추가한다는 것을 알게 되었다.내 내부 구현이 거의 항상 보다 편리할 것이다.List<>그래서 다시 뒤로 젖혀라.Arrays.asList()내가 힙 오염을 소개할 방법이 없다는 걸 확실히 해야겠어. 이게 내가 하는 일이야.

이게 너의 3번밖에 답이 안 된다는 걸 알아. newact는 위의 1번과 2번에게 훌륭한 답을 주었고, 나는 이것을 그냥 코멘트로 남길 만큼 평판이 좋지 않아. :P

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

반응형