Programing

제네릭의 실제 예는 무엇입니까

crosscheck 2020. 10. 25. 11:38
반응형

제네릭의 실제 예는 무엇입니까 ?


나는 그것이 ( 모든 수준의 부모 클래스)의 <? super T>모든 수퍼 클래스 나타내는 것을 이해합니다 . 그러나 저는이 일반적인 바운드 와일드 카드에 대한 실제 예를 상상하기 위해 정말 고생합니다.TT

나는 <? super T>의미를 이해 하고이 방법을 보았다 :

public class Collections {
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++)
        dest.set(i, src.get(i));
  }
}

이 구조를 사용할 수있는 실제 사용 사례 의 예를 찾고 있으며 그것이 무엇인지에 대한 설명이 아닙니다.


내가 생각할 수있는 가장 쉬운 예는 다음과 같습니다.

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

같은 Collections. 이런 식으로 Dog할 수 Comparable<Animal>있으며 Animal이미 구현 한 경우 Dog아무것도 할 필요가 없습니다.

실제 예를 들어 편집 :

이메일 핑퐁을 한 후 직장에서 실제 사례를 제시 할 수 있습니다 (예!).

우리는 Sink(무엇을하는지 중요하지 않습니다) 라는 인터페이스를 가지고 있습니다 . 아이디어는 물건을 축적 한다는 것입니다. 선언은 매우 사소합니다 (간체).

interface Sink<T> {
    void accumulate(T t);
}

분명히 a를 취하고 List요소를 a로 배출 하는 도우미 메서드가 있습니다 Sink(좀 더 복잡하지만 간단하게 만들기 위해).

public static <T> void drainToSink(List<T> collection, Sink<T> sink) {
    collection.forEach(sink::accumulate);
}

간단 하죠? 잘...

나는를 가질 수 List<String>있지만 그것을 a로 배출하고 싶습니다. Sink<Object>이것은 우리에게 매우 일반적인 일입니다. 그러나 이것은 실패합니다.

Sink<Object> sink = null;
List<String> strings = List.of("abc");
drainToSink(strings, sink);

이 작업을 수행하려면 선언을 다음과 같이 변경해야합니다.

public static <T> void drainToSink(List<T> collection, Sink<? super T> sink) {
    ....
}

이 클래스 계층이 있다고 가정합니다. Cat은 Mammal에서 상속하고 다시 Animal에서 상속합니다.

List<Animal> animals = new ArrayList<>();
List<Mammal> mammals = new ArrayList<>();
List<Cat> cats = ...

다음 호출은 유효합니다.

Collections.copy(animals, mammals); // all mammals are animals
Collections.copy(mammals, cats);    // all cats are mammals
Collections.copy(animals, cats);    // all cats are animals
Collections.copy(cats, cats);       // all cats are cats 

그러나 다음 호출은 유효 하지 않습니다.

Collections.copy(mammals, animals); // not all animals are mammals
Collections.copy(cats, mammals);    // not all mammals are cats
Collections.copy(cats, animals);    // mot all animals are cats

따라서 메서드 시그니처는 단순히 더 구체적인 (상속 계층 구조의 하위) 클래스에서보다 일반적인 클래스 (상속 계층의 상위)로 복사하는 것을 보장합니다.


예를 들어, Collections.addAll메소드 단순화를 살펴보십시오 .

public static <T> boolean addAll(Collection<? super T> c, T... elements) {
    boolean result = false;
    for (T element : elements)
        result |= c.add(element);
    return result;
}

여기에서 요소 유형이 요소 유형의 상위 유형 인 모든 컬렉션에 요소를 삽입 할 수 있습니다 T.

하한 와일드 카드가없는 경우 :

public static <T> boolean addAll(Collection<T> c, T... elements) { ... }

다음은 유효하지 않습니다.

List<Number> nums = new ArrayList<>();
Collections.<Integer>addAll(nums , 1, 2, 3);

용어 Collection<T>가보다 제한적 이기 때문 Collection<? super T>입니다.


다른 예시:

Predicate<T><? super T>다음 메소드에서 와일드 카드 를 사용하는 Java의 인터페이스 :

default Predicate<T> and(Predicate<? super T> other);

default Predicate<T>  or(Predicate<? super T> other);

<? super T> 더 넓은 범위의 다른 술어를 연결할 수 있습니다. 예를 들면 다음과 같습니다.

Predicate<String> p1 = s -> s.equals("P");
Predicate<Object> p2 = o -> o.equals("P");

p1.and(p2).test("P"); // which wouldn't be possible with a Predicate<T> as a parameter

방법이 있다고 가정합니다.

passToConsumer(Consumer<? super SubType> consumer)

그런 다음 Consumer사용할 수있는 모든 메서드를 사용하여이 메서드를 호출 합니다 SubType.

passToConsumer(Consumer<SuperType> superTypeConsumer)
passToConsumer(Consumer<SubType> subTypeConsumer)
passToConsumer(Consumer<Object> rootConsumer)

예를 들어 :

class Animal{}

class Dog extends Animal{

    void putInto(List<? super Dog> list) {
        list.add(this);
    }
}

그래서 넣을 수 DogList<Animal>또는 List<Dog>:

List<Animal> animals = new ArrayList<>();
List<Dog> dogs = new ArrayList<>();

Dog dog = new Dog();
dog.putInto(dogs);  // OK
dog.putInto(animals);   // OK

putInto(List<? super Dog> list)방법을 putInto(List<Animal> list)다음과 같이 변경 하는 경우 :

Dog dog = new Dog();

List<Dog> dogs = new ArrayList<>();
dog.putInto(dogs);  // compile error, List<Dog> is not sub type of List<Animal>

또는 putInto(List<Dog> list):

Dog dog = new Dog();

List<Animal> animals = new ArrayList<>();
dog.putInto(animals); // compile error, List<Animal> is not sub type of List<Dog>

웹 라디오를 작성 했으므로 MetaInformationObjectPLS 및 M3U 재생 목록의 수퍼 클래스 클래스가있었습니다 . 선택 대화가 있었기 때문에 다음과 같이했습니다.

public class SelectMultipleStreamDialog <T extends MetaInformationObject>
public class M3UInfo extends MetaInformationObject
public class PLSInfo extends MetaInformationObject

이 클래스에는 메서드가 public T getSelectedStream()있습니다.
따라서 호출자는 구체적인 유형 (PLS 또는 M3U)의 T를 받았지만 수퍼 클래스에서 작업해야했기 때문에 목록이있었습니다 List<T super MetaInformationObject>.. 결과가 추가되었습니다.
이것이 일반적인 대화가 구체적인 구현을 처리 할 수있는 방법이고 나머지 코드는 수퍼 클래스에서 작동 할 수 있습니다.
그것이 좀 더 명확 해지기를 바랍니다.


이 간단한 예를 고려하십시오.

List<Number> nums = Arrays.asList(3, 1.2, 4L);
Comparator<Object> numbersByDouble = Comparator.comparing(Object::toString);
nums.sort(numbersByDouble);

Hopefully this is a somewhat compelling case: You could imagine wanting to sort the numbers for display purposes (for which the toString is a reasonable ordering), but Number is not itself Comparable.

This compiles because integers::sort takes a Comparator<? super E>. If it took just a Comparator<E> (where E in this case is Number), then the code would fail to compile because Comparator<Object> is not a subtype of Comparator<Number> (due to reasons that your question indicates you already understand, so I won't go into).


Collections serve as a good example here.

As stated in 1, List<? super T> lets you create List that will hold elements of type, that are less derived than T, so it can hold elements that inherit from T, that are type of T and that T inherits from.

On the other hand, List<? extends T> lets you define a List that can hold only elements that inherit from T (in some cases not even of type T).

This is a good example:

public class Collections {
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++)
        dest.set(i, src.get(i));
  }
}

Here you want to project List of less derived type to List of less derived type. Here List<? super T> assures us that all elements from src will be valid in the new collection.

1 : Difference between <? super T> and <? extends T> in Java


Say you have:

class T {}
class Decoder<T>
class Encoder<T>

byte[] encode(T object, Encoder<? super T> encoder);    // encode objects of type T
T decode(byte[] stream, Decoder<? extends T> decoder);  // decode a byte stream into a type T

And then:

class U extends T {}
Decoder<U> decoderOfU;
decode(stream, decoderOfU);     // you need something that can decode into T, I give you a decoder of U, you'll get U instances back

Encoder<Object> encoderOfObject;
encode(stream, encoderOfObject);// you need something that can encode T, I give you something that can encode all the way to java.lang.Object

A few real life examples come to mind for this. The first one I like to bring up, is the idea of a real-world object being used for 'improvised' functionality. Imagine that you have a socket wrench:

public class SocketWrench <T extends Wrench>

The obvious purpose of a socket wrench it so be used as a Wrench. However, if you consider that a wrench could be used in a pinch to pound in a nail, you could have an inheritance hierarchy that looks like this:

public class SocketWrench <T extends Wrench>
public class Wrench extends Hammer

In this scenario, you would be able to call socketWrench.pound(Nail nail = new FinishingNail()), even though that would be considered an atypical use for a SocketWrench.

While all along, the SocketWrench would have access to be able to call methods like applyTorque(100).withRotation("clockwise").withSocketSize(14) if it's being used as a SocketWrench instead of just a Wrench, instead of a Hammer.

참고URL : https://stackoverflow.com/questions/52185915/what-is-a-real-life-example-of-generic-super-t

반응형