자바가 필요합니까?교환의 단점이 있습니까 ?
다음 예에서는 (Hamcrest matchers에서 JUnit 사용)
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
JUnit에서는 .assertThat
다음 중 하나:
public static <T> void assertThat(T actual, Matcher<T> matcher)
컴파일러 오류 메시지는 다음과 같습니다.
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
''를 '''가 됩니다.assertThat
다음 중 하나:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
그러면 컴파일이 작동하게 됩니다.
세 가지 질문이 있습니다.
- 현재 버전이 컴파일되지 않는 이유는 무엇입니까?나는 공분산 문제를 어렴풋이 이해하지만, 굳이 설명해야 한다면 분명히 설명할 수 없다.
assertThat
to 는 methodMatcher<? extends T>
그렇게 하면 망가질 만한 다른 케이스가 있나요?- 「이것들」의?
assertThat
【JUnit】?Matcher
메서드를 JUnit이 matchs를 매칭하기 에 JUnit은 matchs 메서드를 필요로 JUnit이 matchs를 하고 있기 때문에 도 하지 때문입니다.이것은 범용으로 입력되지 않고, 아무것도 하지 않는 타입의 안전성을 강제하기 위한 시도로 보입니다.Matcher
실제로는 일치하지 않을 뿐이고, 어떤 경우에도 테스트는 실패합니다.안전하지 않은 조작은 포함되어 있지 않습니다(또는 그런 것 같습니다).
JUnit의 .assertThat
:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}
우선, http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html에 접속해 주세요.그녀는 훌륭한 일을 하고 있습니다.
기본적인 생각은 이 시스템을
<T extends SomeClass>
가 '비활성화'가 될 수 .SomeClass
그 어떤 아유형도요
이 예에서는
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
말은, 「... 」라고 하는군요.expected
에는, 「」를 는 임의의 할 수 .Serializable
결과 맵에 따르면 이 맵은 다음 명령어만 유지할 수 있습니다.Date
클래스 오브젝트
결과했을 때, 그과결격,,,,,를 설정하고 있습니다.T
Map
String
로로 합니다.Date
오브젝트,, 클래스 오브젝트Map
String
어떤 것이든Serializable
.
가지해야 할 것은, 한 것이 있습니까?Class<Date>
andDate
의 ? ★★★★★★★★★★★★★.String
로로 합니다.Class<Date>
으로는 별로 것 Date.class
「」의 , Date
)
「」의 는,assertThat
은 '어느 정도'가 '어느 정도'라는 것을 할 수 Matcher
이치
질문에 답해주신 모든 분들 덕분에 제가 좀 더 명확하게 할 수 있었습니다.결국 Scott Stanchfield의 답변이 제가 이해하게 된 방법과 가장 비슷해졌지만, 그가 처음 글을 썼을 때 저는 그를 이해하지 못했기 때문에, 저는 다른 누군가가 혜택을 받을 수 있도록 문제를 다시 설명하려고 합니다.
일반적인 파라미터가 1개밖에 없고 이해하기 쉽기 때문에 List로 질문을 다시 하겠습니다.
클래스의 등)<Date>
Map(맵)<K, V>
이 예에서와 같이 다운캐스트를 강제하여 컴파일러가 이것이 안전함을 보증하도록 하는 것입니다(런타임 예외 없음).
List의 경우를 생각해 보겠습니다.제 질문의 본질은 T타입과 List를 채택한 방법이 왜 T타입보다 상속의 사슬 아래쪽에 있는 어떤 것의 목록을 받아들이지 않는가 하는 것입니다.다음 예시를 생각해 보겠습니다.
List<java.util.Date> dateList = new ArrayList<java.util.Date>();
Serializable s = new String();
addGeneric(s, dateList);
....
private <T> void addGeneric(T element, List<T> list) {
list.add(element);
}
list 파라미터는 날짜 리스트이며 문자열 리스트가 아니기 때문에 컴파일되지 않습니다.만약 이것이 컴파일된다면 제네릭스는 그다지 유용하지 않을 것이다.
된다.<String, Class<? extends Serializable>>
.<String, Class<java.util.Date>>
에 날짜 클래스를 요소를 같은 이들은 공변량이 아니기 때문에 날짜 클래스를 포함하는 맵에서 값을 가져와 직렬화 가능한 요소를 포함하는 맵에 포함시키려면 다음과 같은 메서드 시그니처가 필요합니다.
private <T> void genericAdd(T value, List<T> list)
다음 두 가지를 모두 수행할 수 있기를 원합니다.
T x = list.get(0);
그리고.
list.add(value);
이 경우 junit 메서드는 실제로 이러한 것에 관심이 없지만 메서드 시그니처는 공분산을 필요로 합니다.공분산은 취득되지 않기 때문에 컴파일되지 않습니다.
두 번째 질문에서는
Matcher<? extends T>
T가 오브젝트일 경우 API의 의도가 아닌 어떤 것이든 실제로 받아들이는 단점이 있습니다.목적은 매처가 실제 객체와 일치하는지 확인하는 것이며 객체를 계산에서 제외하는 방법은 없습니다.
세 번째 질문에 대한 답변은 체크되지 않은 기능(이 메서드가 범용화되지 않은 경우 JUnit API 내에 안전하지 않은 타이프캐스팅이 존재하지 않음)에 관해 아무것도 손실되지 않는다는 것입니다.다만, 이 두 가지 파라미터가 일치할 가능성이 있는 것을 정적으로 확인하는 등, 다른 것을 실시하려고 하고 있습니다.
편집(고려 및 경험 후):
이 의 시그니처는 변수 와 범용 T를 하려고 합니다.공변량이 아니기 때문에 효과가 없습니다. 예를 가 있을 때 T가 수도 있고, T가 있을 수도 요. tList<String>
컴파일러가 알아내는 일치를 전달한다.Matcher<ArrayList<T>>
타입 파라미터가 아니더라도 List와 ArrayList는 공변량이기 때문에 문제 없습니다만, Generics는 ArrayList를 필요로 하기 때문에 위와 같은 이유로 List를 허용할 수 없습니다.
요약하면 다음과 같습니다.
Class<? extends Serializable> c1 = null;
Class<java.util.Date> d1 = null;
c1 = d1; // compiles
d1 = c1; // wont compile - would require cast to Date
클래스 참조 c1에 롱인스턴스가 포함되어 있는 것을 알 수 있습니다(특정 시점에서 기본 객체는 다음과 같이 되어 있을 수 있습니다).List<Long>
그러나 "알 수 없는" 클래스가 날짜라는 보장은 없기 때문에 날짜로 캐스팅할 수 없습니다.이것은 type safe가 아니기 때문에 컴파일러는 그것을 허용하지 않습니다.
그러나 다른 오브젝트(예에서는 이 오브젝트는 Matcher)를 도입하면 다음과 같이 됩니다.
List<Class<? extends Serializable>> l1 = null;
List<Class<java.util.Date>> l2 = null;
l1 = l2; // wont compile
l2 = l1; // wont compile
...단, 목록의 유형이 ?가 되면 T가 아닌 T가 확장됩니다.
List<? extends Class<? extends Serializable>> l1 = null;
List<? extends Class<java.util.Date>> l2 = null;
l1 = l2; // compiles
l2 = l1; // won't compile
내 생각에 변화함으로써Matcher<T> to Matcher<? extends T>
기본적으로 l1 = l2를 할당하는 것과 유사한 시나리오를 소개합니다.
네스트된 와일드카드를 사용하는 것은 아직 매우 혼란스럽지만, 일반 참조를 서로 할당하는 방법을 살펴봄으로써 범용성을 이해하는 데 도움이 되는 이유를 알 수 있기를 바랍니다.함수가 호출될 때 컴파일러가 T의 유형을 추론하기 때문에 더욱 혼란스럽습니다(T라고 명시적으로 말하지 않습니다).
원래 코드가 컴파일되지 않는 이유는<? extends Serializable>
는, 「시리얼러블을 확장하는 클래스」가 아니고, 「시리얼러블을 확장하는 불명확하지만 특정의 클래스」를 의미합니다.
예를 들어, 코드가 기재되어 있는 경우, 이 코드를 할당하는 것은 완전히 유효합니다.new TreeMap<String, Long.class>()
로.expected
컴파일러가 코드 컴파일을 허용한 경우assertThat()
아마 부서질 것이다 왜냐하면 그것은 예상할 수 있기 때문이다.Date
의 대신 오브젝트Long
맵에서 찾을 수 있는 객체입니다.
와일드카드를 이해하기 위한 한 가지 방법은 와일드카드가 특정 범용 참조가 가질 수 있는 오브젝트의 유형을 지정하는 것이 아니라 호환성이 있는 다른 범용 참조의 유형을 지정하는 것이라고 생각하는 것입니다(이것은 혼란스럽게 들릴 수 있습니다). 따라서 첫 번째 답변은 매우 잘못된 표현입니다.
바꿔 말하면List<? extends Serializable>
즉, 이 참조를 다른 목록에 할당할 수 있습니다.이 경우 유형은 알 수 없는 유형으로 Serialable의 서브클래스입니다.하나의 리스트가 Serializable의 서브클래스를 유지할 수 있다고 생각하지 마십시오(그것은 의미론이 잘못되어 Generics에 대한 오해의 원인이 되기 때문입니다).
이것이 오래된 질문이라는 것을 알지만, 나는 경계된 와일드카드를 꽤 잘 설명하는 예를 공유하고자 한다. java.util.Collections
에는 다음 방법이 있습니다.
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
리스트가 있는 경우T
물론 목록에는 확장되는 유형의 인스턴스를 포함할 수 있습니다.T
목록에 동물이 포함되어 있는 경우, 목록에는 개와 고양이(둘 다 동물)가 포함될 수 있습니다.개는 "woofVolume"라는 속성을 가지고 있고 고양이는 "mowVolume"라는 속성을 가지고 있습니다.이러한 속성에 근거해 정렬하고 싶은 경우도 있습니다만, 특히 다음의 서브클래스에 대해서T
어떻게 이 방법을 사용할 수 있을까요?Comparator의 한 가지 제한 사항은 한 가지 유형의 두 가지 항목만 비교할 수 있다는 것입니다.T
) 。그래서 단순히 필요한 것은Comparator<T>
이 방법을 사용할 수 있습니다.하지만, 이 방법의 창안자는 만약 어떤 것이 만약 어떤 것이, 어떤 것이,T
, 그것은 또한 슈퍼클래스의 인스턴스이다.T
따라서, 그는 우리에게 비교기를 사용할 수 있도록 허락했다.T
또는 슈퍼클래스의T
,예.? super T
.
를 사용하면 어떻게 됩니까?
Map<String, ? extends Class<? extends Serializable>> expected = null;
언급URL : https://stackoverflow.com/questions/897935/when-do-java-generics-require-extends-t-instead-of-t-and-is-there-any-down
'programing' 카테고리의 다른 글
Vue의 데이터 특성을 통해 함수 참조 전달 (0) | 2022.07.10 |
---|---|
제스트가 포함된 Vuex - 정의되지 않은 속성을 읽을 수 없습니다. (0) | 2022.07.10 |
Vue.js로 작성된 SPA 로딩 화면을 구현하려면 어떻게 해야 합니까? (0) | 2022.07.10 |
PWA가 Play Store에 웹 앱과 TWA로 배포될 때 PWA 분석을 처리하는 방법 (0) | 2022.07.10 |
DDD 모델의 도메인 대 Vuex 작업 (0) | 2022.07.10 |