programing

자바가 필요합니까? 자바가 필요합니까? 자바가 필요합니까?교환의 단점이 있습니까?교환의 단점이 있습니까?

copysource 2022. 7. 10. 11:09
반응형

자바가 필요합니까?교환의 단점이 있습니까?

다음 예에서는 (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)

그러면 컴파일이 작동하게 됩니다.

세 가지 질문이 있습니다.

  1. 현재 버전이 컴파일되지 않는 이유는 무엇입니까?나는 공분산 문제를 어렴풋이 이해하지만, 굳이 설명해야 한다면 분명히 설명할 수 없다.
  2. assertThat to 는 methodMatcher<? extends T>그렇게 하면 망가질 만한 다른 케이스가 있나요?
  3. 「이것들」의?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클래스 오브젝트

결과했을 때, 그과결격,,,,,를 설정하고 있습니다.TMapString로로 합니다.Date 오브젝트,, 클래스 오브젝트MapString어떤 것이든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

반응형