일반적인 방법을 사용하는시기와 와일드 카드를 사용하는시기는?
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) { ... }
이 문서는 두 번째 선언을 권장하지 않으며 첫 번째 구문의 사용을 장려합니까? 첫 번째 선언과 두 번째 선언의 차이점은 무엇입니까? 둘 다 같은 일을하는 것 같습니다?
누군가이 지역에 빛을 비출 수 있습니까?
와일드 카드 및 유형 매개 변수가 동일한 작업을 수행하는 특정 위치가 있습니다. 그러나 유형 매개 변수를 사용해야하는 특정 장소도 있습니다.
- 다른 유형의 메소드 인수에 관계를 적용하려면 와일드 카드로이를 수행 할 수 없으므로 유형 매개 변수를 사용해야합니다.
메소드를 예로 들어 메소드에 전달 된 src및 dest목록 copy()이 동일한 매개 변수화 된 유형이어야 한다고 가정하고 다음 과 같이 유형 매개 변수를 사용하여 수행 할 수 있습니다.
public static <T extends Number> void copy(List<T> dest, List<T> src)
여기에서, 당신은 둘 것을 보장하는 dest과 src에 대한 동일한 파라미터 화 된 형태를 가지고 List. 따라서 요소를에서 (으) src로 복사하는 것이 안전 합니다 dest.
그러나 와일드 카드를 사용하도록 방법을 변경하는 경우 :
public static void copy(List<? extends Number> dest, List<? extends Number> src)
예상대로 작동하지 않습니다. 두번째 경우에, 당신은 통과 할 수 List<Integer>와 List<Float>같은 dest과 src. 그래서에서 요소를 이동 src하는 것은 dest더 이상 안전 입력되지 않습니다. 그런 종류의 관계가 필요하지 않으면 유형 매개 변수를 전혀 사용하지 않아도됩니다.
와일드 카드 사용과 유형 매개 변수 사용의 다른 차이점은 다음과 같습니다.
- 매개 변수화 된 유형 인수가 하나만 있으면 와일드 카드를 사용할 수 있지만 유형 매개 변수도 작동합니다.
- 유형 매개 변수는 다중 경계를 지원하지만 와일드 카드는 지원하지 않습니다.
와일드 카드는 상한과 하한을 모두 지원하며 유형 매개 변수는 상한 만 지원합니다. 따라서
List유형Integer또는 수퍼 클래스 인 메소드를 정의 하려면 다음을 수행하십시오.public void print(List<? super Integer> list) // OK그러나 유형 매개 변수를 사용할 수 없습니다 :
public <T super Integer> void print(List<T> list) // Won't compile
참고 문헌 :
2 개의 SinglyLinkQueue를 병합하려는 아래의 James Gosling 4 판의 Java Programming에서 다음 예제를 고려하십시오.
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입니다. 첫 번째 방법은 책에 없습니다.
In your first question: It means that if there is a relation between the parameter's type and the method's return type then use a generic.
For example:
public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);
Here you are extracting some of the T following a certain criteria. If T is Long your methods will return Long and Collection<Long>; the actual return type is dependent on the parameter type, thus it is useful, and advised, to use generic types.
When this is not the case you can use wild card types:
public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);
In this two example whatever the type of the items in the collections the return types will be int and boolean.
In your examples:
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
those two functions will return a boolean whatever is the types of the items in the collections. In the second case it is limited to instances of a subclass of E.
Second question:
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
This first code allow you to pass an heterogeneous List<? extends T> src as a parameter. This list can contain multiple elements of different classes as long as they all extends the base class T.
if you had:
interface Fruit{}
and
class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}
you could do
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
On the other hand
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
constrain List<S> src to be of one particular class S that is a subclass of T. The list can only contain elements of one class (in this instance S) and no other class, even if they implement T too. You wouldn't be able to use my previous example but you could do:
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. */
Wildcard method is also generic - you could call it with some range of types.
The <T> syntax defines a type variable name. If a type variable has any use (e.g. in method implementation or as a constraint for other type), then it makes sense to name it, otherwise you could use ?, as anonymous variable. So, looks like just a short-cut.
Moreover, the ? syntax is not avoidable when you declare a field:
class NumberContainer
{
Set<? extends Number> numbers;
}
I will try and answer your question, one by one.
Don't we think wild card like
(Collection<? extends E> c);is also supporting kind of polymorphism?
No. The reason is that the bounded wildcard has no defined parameter type. It is an unknown. All it "knows" is that the "containment" is of a type E (whatever defined). So, it cannot verify and justify whether the value provided matches the bounded type.
So, it's no sensible to have polymorphic behaviours on wildcards.
The document discourages the second declaration and promotes usage of first syntax? What's the difference between the first and second declaration? Both seems to be doing the same thing?
The first option is better in this case as T is always bounded, and source will definitely have values (of unknowns) that subclasses T.
So, suppose that you want to copy all list of numbers, the first option will be
Collections.copy(List<Number> dest, List<? extends Number> src);
src, essentially, can accept List<Double>, List<Float>, etc. as there is an upper bound to the parameterized type found in dest.
The 2nd option will force you to bind S for every type you want to copy, like 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.
As S is a parameterized type that needs binding.
I hope this helps.
One other difference which is not listed here.
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // correct
}
}
But the following will result in compile time error.
static <T> void fromArrayToCollection(T[] a, Collection<?> c) {
for (T o : a) {
c.add(o); // compile time error
}
}
As far as I understand, there is only one use case when wildcard is strictly needed (i.e. can express something that you can not express using explicit type parameters). This is when you need to specify a lower bound.
Apart from that however wildcards serve to write more concise code, as described by the following statements in the document you mention:
Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used.
[...]
Using wildcards is clearer and more concise than declaring explicit type parameters, and should therefore be preferred whenever possible.
[...]
Wildcards also have the advantage that they can be used outside of method signatures, as the types of fields, local variables and arrays.
참고URL : https://stackoverflow.com/questions/18176594/when-to-use-generic-methods-and-when-to-use-wild-card
'Programing' 카테고리의 다른 글
| Subversion을 사용하여 현재 체크 아웃 된 분기와 다른 분기로 변경 사항 커밋 (0) | 2020.07.29 |
|---|---|
| 확실히 설치된 모듈을 가져올 수 없습니다 (0) | 2020.07.29 |
| C ++로 짧은 리터럴을 작성하는 방법 (0) | 2020.07.29 |
| 주어진 수의 요소로 목록 자르기 (0) | 2020.07.29 |
| 서버에서받은 중복 헤더 (0) | 2020.07.28 |