Java SafeVarargs 주석, 표준 또는 모범 사례가 있습니까?
최근에 java @SafeVarargs 주석을 발견했습니다. Java의 variadic 함수를 안전하지 않은 것으로 만드는 것에 대한 인터넷 검색으로 인해 혼란스러워졌습니다 (힙 중독? 지워진 유형?). 몇 가지 사항을 알고 싶습니다.
@SafeVarargs의 의미 에서 가변적 인 Java 함수가 안전하지 않은 이유는 무엇입니까 (바람직한 심도의 형태로 설명 됨)?
왜이 주석이 프로그래머의 재량에 달려 있습니까? 컴파일러가 확인할 수있는 것이 아닌가?
그의 기능이 실제로 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
우리가 알고 있기 때문에 괜찮을 것에 T
인 String
코드에서 그 시점에서.
그러나의 "값" 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
'Programing' 카테고리의 다른 글
Angular CLi가 생성 한 "spec.ts"파일은 무엇입니까? (0) | 2020.05.29 |
---|---|
여러 Xcode 버전을 설치할 수 있습니까? (0) | 2020.05.29 |
Android에서보기가 보이는지 어떻게 확인할 수 있습니까? (0) | 2020.05.28 |
Mac OS X 10.6에서 하드웨어 경고음을 울리는 방법 (0) | 2020.05.28 |
여러 인라인 스타일 객체를 결합하는 방법은 무엇입니까? (0) | 2020.05.28 |