Java SafeVargs 주석, 표준 또는 모범 사례가 있는가?
나는 최근에 자바를 우연히 만났다.@SafeVarargs
주석을 달다무엇이 자바에서 다양한 기능을 안전하지 않게 만드는지 구글링하는 것은 나를 다소 혼란스럽게 만들었다.지워진 활자?) 그래서 나는 몇 가지를 알고 싶다.
다양한 Java 기능을 안전하지 않게 만드는 것은?
@SafeVarargs
감지(심층적인 예제의 형태로 설명됨)?왜 이 주석을 프로그래머의 재량에 맡기는가?이것은 컴파일러가 확인할 수 있어야 하는 것이 아닌가?
그의 기능이 정말로 안전하다는 것을 확실히 하기 위해 반드시 지켜야 할 표준이 있는가?그렇지 않다면 이를 보장하기 위한 모범적 실무 지침은 무엇인가?
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
'Programing' 카테고리의 다른 글
Java의 변수 유형을 어떻게 아십니까? (0) | 2022.04.26 |
---|---|
다른 구성 요소가 있는 Vue JS 루프 (0) | 2022.04.26 |
Vue v-model.lazy 또는 @change가 내 Vue 데이터를 업데이트하지 않음 (0) | 2022.04.26 |
GCC의 ##_VA_에 대한 표준 대안ARGS__ 트릭? (0) | 2022.04.26 |
최대 절전 모드에서의 서로 다른 저장 방법의 차이점은? (0) | 2022.04.26 |