programing

범용 메서드를 사용하는 경우 및 와일드 카드를 사용하는 경우

goodsources 2022. 12. 29. 20:34
반응형

범용 메서드를 사용하는 경우 및 와일드 카드를 사용하는 경우

OracleDocGenericMethod에서 범용 메서드에 대해 읽고 있습니다.와일드 카드를 사용할 때와 범용적인 방법을 사용할 때의 비교가 매우 혼란스럽습니다.문서에서 인용합니다.

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);
}

대신 여기서는 일반적인 방법을 사용할 수 있습니다.

interface Collection<E> {
    public <T> boolean containsAll(Collection<T> c);
    public <T extends E> boolean addAll(Collection<T> c);
    // Hey, type variables can have bounds too!
}

[…] 이는 type 인수가 다형성에 사용되고 있음을 나타냅니다.이 인수의 유일한 효과는 다양한 실제 인수 유형을 다른 호출 사이트에서 사용할 수 있도록 하는 것입니다.그렇다면 와일드카드를 사용해야 한다.와일드카드는 유연한 서브타이핑을 지원하도록 설계되어 있습니다.이것이 여기서 표현하려고 하는 것입니다.

같은 거 (Collection<? extends E> c);형형 형형 형형 형형 형? 형? ?? ??그렇다면 왜 일반적인 방법 사용이 좋지 않은 것으로 간주되는가?

계속 진행하면 다음과 같습니다.

일반 메서드를 사용하면 하나 이상의 인수 유형 간의 종속성을 메서드 및/또는 반환 유형에 표현하기 위해 유형 매개 변수를 사용할 수 있습니다.이러한 종속성이 없는 경우 일반 방법을 사용하지 않아야 합니다.

이것은 무엇을 의미합니까?

그들은 예를 들었다.

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}

[…]

와일드카드를 전혀 사용하지 않고 다른 방법으로 이 메서드의 시그니처를 작성할 수 있습니다.

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...
}

이 문서는 두 번째 선언을 금지하고 첫 번째 구문의 사용을 장려하고 있습니까?첫 번째 선언과 두 번째 선언의 차이점은 무엇입니까?둘 다 같은 일을 하는 것 같아요?

누가 이 주변을 밝혀줄 수 있나요?

와일드카드 파라미터와 타입 파라미터가 같은 처리를 하는 장소가 있습니다.그러나 유형 매개 변수를 사용해야 하는 특정 장소도 있습니다.

  1. 다른 유형의 메서드 인수에서 일부 관계를 적용하려는 경우 와일드카드를 사용할 수 없으며 유형 매개 변수를 사용해야 합니다.

예를 들면, 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」를 .src ★★★★★★★★★★★★★★★★★」dest가 「」에 .copy()메서드는 파라미터화된 유형이 같아야 하며 다음과 같이 유형 파라미터를 사용하여 수행할 수 있습니다.

public static <T extends Number> void copy(List<T> dest, List<T> src)

Here, you are ensured that both 여기에서는, 다음의 양쪽 모두를 확실히 할 수 있습니다.dest ★★★★★★★★★★★★★★★★★」src have same parameterized type for 파라미터화된 유형이 같다List. . So, it's safe to copy elements from 따라서 요소를 복사하는 것이 안전합니다.src로로 합니다.dest.

다만, 와일드 카드를 사용하는 방법을 변경하는 경우는, 다음의 순서에 따릅니다.

public static void copy(List<? extends Number> dest, List<? extends Number> src)

예상대로 괜찮아요.예상대로 되지 않을 거예요. In 2nd case, you can pass 두 번째 경우에는 합격할 수 있습니다.List<Integer> ★★★★★★★★★★★★★★★★★」List<Float> as ~하듯이dest ★★★★★★★★★★★★★★★★★」src그래서, 요소들을 이동시키는 것은src로로 합니다.dest 없는 전혀 하지 않아도 .이러한 관계가 필요하지 않은 경우 유형 매개 변수를 전혀 사용하지 않아도 됩니다.

와일드카드와 타입 파라미터의 다른 차이점은 다음과 같습니다.

  • 파라미터화된type인수가1개밖에 없는 경우 와일드카드를 사용할 수 있지만 type 파라미터도 사용할 수 있습니다.
  • 유형 매개 변수는 다중 경계를 지원하지만 와일드카드는 지원하지 않습니다.
  • 와일드카드는 상한과 하한을 모두 지원하며 유형 매개 변수는 상한만 지원합니다.''를 에는 ''를 사용합니다.List입입 of Integer슈퍼클래스의 경우 다음과 같은 작업을 수행할 수 있습니다.

    public void print(List<? super Integer> list)  // OK
    

    type 파라미터는 사용할 수 없습니다.

     public <T super Integer> void print(List<T> list)  // Won't compile
    

참고 자료:

아래의 Java Programming by James Gosling 4th Edition에서 2개의 SinglyLinkQueue를 Marge하는 예를 참조하십시오.

public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
    // merge s element into d
}

public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
        // merge s element into d
}

위의 두 방식 모두 동일한 기능을 가지고 있습니다.그럼 어떤 게 더 좋습니까?정답은 두 번째입니다.저자의 말을 빌리자면:

"일반적으로 와일드카드가 있는 코드는 여러 타입 파라미터를 가진 코드보다 읽기 쉽기 때문에 가능하면 와일드카드를 사용하는 것이 규칙입니다.유형 변수가 필요한지 여부를 결정할 때 해당 유형 변수가 두 개 이상의 매개 변수를 관련짓는 데 사용되는지 또는 매개 변수 유형과 반환 유형을 관련짓는 데 사용되는지 자문해 보십시오.'아니오'라고 대답할 경우 와일드카드를 사용하면 충분합니다.

참고: 책에는 두 번째 메서드만 지정되며 입력 매개 변수 이름은 'T'가 아닌 S입니다.첫 번째 방법은 책에 없습니다.

첫 번째 질문:이는 매개 변수의 유형과 메서드의 반환 유형 사이에 관계가 있는 경우 일반을 사용함을 의미합니다.

예를 들어 다음과 같습니다.

public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);

여기에서는 특정 기준에 따라 T의 일부를 추출합니다.가 'T'인 Long.Long ★★★★★★★★★★★★★★★★★」Collection<Long>; 실제 반환 유형은 파라미터 유형에 따라 다르므로 범용 유형을 사용하는 것이 좋습니다.

그렇지 않은 경우 와일드카드 유형을 사용할 수 있습니다.

public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);

예에서는 은 " " " " " 입니다.int ★★★★★★★★★★★★★★★★★」boolean.

이 예에서는 다음과 같습니다.

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);
}

이 두 함수는 컬렉션에 포함된 항목의 유형에 관계없이 부울을 반환합니다.두 번째 경우에는 E의 서브클래스의 인스턴스로 제한됩니다.

두 번째 질문:

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}

첫 하면 이종 를 전달할 수 .List<? extends T> src파라미터로 지정합니다.T가 되어 있는 한될 수 있습니다.

다음과 같은 경우:

interface Fruit{}

그리고.

class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}

할 수 있다

List<? extends Fruit> basket = new ArrayList<? extends Fruit>();
basket.add(new Apple());
basket.add(new Pear());
basket.add(new Tomato());
List<Fruit> fridge = new ArrayList<Fruit>(); 

Collections.copy(fridge, basket);// works 

반면에

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...
}

List<S> srcT자형 S자형 S자형이다.리스트에는 1개의 클래스(이 경우 S)의 요소만 포함할 수 있으며 T를 실장해도 다른 클래스는 포함할 수 없습니다.이전 예제는 사용할 수 없지만 다음을 수행할 수 있습니다.

List<Apple> basket = new ArrayList<Apple>();
basket.add(new Apple());
basket.add(new Apple());
basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();

Collections.copy(fridge, basket); /* works since the basket is defined as a List of apples and not a list of some fruits. */

와일드카드 메서드도 범용입니다.일부 타입의 범위로 호출할 수 있습니다.

<T>이치가 어떤를 들어 메서드 또는 이름을 않은 경우, 「」( 「」를 사용할 수 .?어나니머스 변수로 지정합니다.지름길로 보이는군요

''는?필드를 선언할 때 구문을 피할 수 없습니다.

class NumberContainer
{
 Set<? extends Number> numbers;
}

저는 당신의 질문에 한 명씩 대답할 것입니다.

같은 거 (Collection<? extends E> c);형형 형형 형형 형형 형? 형? ?? ??

아니요. 그 이유는 경계된 와일드카드에 정의된 매개 변수 유형이 없기 때문입니다.그것은 알 수 없다.그게 "알고 있는" 모든 것은 "억제"라는 것이E(일부러)따라서 제공된 값이 경계 유형과 일치하는지 확인하고 정당화할 수 없습니다.

그래서 와일드카드에서 다형성 행동을 하는 것은 현명하지 못하다.

이 문서는 두 번째 선언을 금지하고 첫 번째 구문의 사용을 장려하고 있습니까?첫 번째 선언과 두 번째 선언의 차이점은 무엇입니까?둘 다 같은 일을 하는 것 같아요?

첫 은 ""로 하는 것이 .T경계가 있고, 에는 경계가 있습니다.source(알 수 )가 (알 수 없는 값).T.

따라서 모든 번호 목록을 복사하는 경우 첫 번째 옵션은 다음과 같습니다.

Collections.copy(List<Number> dest, List<? extends Number> src);

src 을 사용할 수 있습니다. 즉 「인정」을 받아들일 수 .List<Double>,List<Float> 기재되어 있는 이 있기 등입니다.dest.

수 .S, 예를 들면 「So」라고 하는 입니다.

//For double 
Collections.copy(List<Number> dest, List<Double> src); //Double extends Number.

//For int
Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.

~로S는 바인딩이 필요한 파라미터 유형입니다.

이게 도움이 됐으면 좋겠어요.

여기에 나열되지 않은 다른 차이점이 하나 있습니다.

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
        c.add(o); // correct
    }
}

그러나 다음과 같은 경우 컴파일 시간 오류가 발생합니다.

static <T> void fromArrayToCollection(T[] a, Collection<?> c) {
    for (T o : a) {
        c.add(o); // compile time error
    }
}

?는 알 수 없음을 의미합니다.

일반적인 규칙은 다음과 같습니다.읽을 수는 있지만는 없다

심플한 Pojo 차량 제공

class Car {
    void display(){

    }
}

컴파일 됩니다.

private static <T extends Car> void addExtractedAgain1(List<T> cars) {
    T t = cars.get(1);
    t.display();
    cars.add(t);
}

이 메서드는 컴파일되지 않습니다.

private static void addExtractedAgain2(List<? extends Car> cars) {
    Car car = cars.get(1);
    car.display();
    cars.add(car); // will not compile
}

또 다른 예

List<?> hi = Arrays.asList("Hi", new Exception(), 0);

hi.forEach(o -> {
   o.toString() // it's ok to call Object methods and methods that don't need the contained type
});

hi.add(...) // nothing can be add here won't compile, we need to tell compiler what the data type is but we do not know

와일드카드가 절대적으로 필요한 경우(즉, 명시적 유형 매개 변수를 사용하여 표현할 수 없는 것을 표현할 수 있는 경우)에는 한 가지 사용 사례만 있는 것으로 알고 있습니다.이때 하한을 지정해야 합니다.

단, 와일드카드는 다음 설명에서 설명한 바와 같이 보다 간결한 코드를 기술하는 역할을 합니다.

일반 메서드를 사용하면 하나 이상의 인수 유형 간의 종속성을 메서드 및/또는 반환 유형에 표현하기 위해 유형 매개 변수를 사용할 수 있습니다.이러한 종속성이 없는 경우 일반 방법을 사용하지 않아야 합니다.

[...]

와일드카드를 사용하는 것은 명시적 유형 파라미터를 선언하는 것보다 명확하고 간결하기 때문에 가능한 한 권장해야 합니다.

[...]

와일드카드는 필드 유형, 로컬 변수 및 배열로서 메서드 시그니처 외부에서 사용할 수 있다는 이점도 있습니다.

주로 -> 와일드카드는 일반적이지 않은 메서드의 파라미터/인수 수준에서 제네릭을 적용합니다.주의: 디폴트로는 genericMethod에서도 실행할 수 있지만, 여기서는 T 자체를 사용할 수 있습니다.

패키지 제네릭

public class DemoWildCard {


    public static void main(String[] args) {
        DemoWildCard obj = new DemoWildCard();

        obj.display(new Person<Integer>());
        obj.display(new Person<String>());

    }

    void display(Person<?> person) {
        //allows person of Integer,String or anything
        //This cannnot be done if we use T, because in that case we have to make this method itself generic
        System.out.println(person);
    }

}

class Person<T>{

}

SO 와일드카드에는 다음과 같은 구체적인 사용 사례가 있습니다.

언급URL : https://stackoverflow.com/questions/18176594/when-to-use-generic-methods-and-when-to-use-wild-card

반응형