최근에 다음 기사를 읽었습니다.
http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html
내 질문은 다음과 같은 방법을 만드는 대신입니다.
public void drawAll(List<? extends Shape> shapes){
for (Shape s: shapes) {
s.draw(this);
}
}
다음과 같은 메서드를 만들 수 있으며 제대로 작동합니다.
public <T extends Shape> void drawAll(List<T> shapes){
for (Shape s: shapes) {
s.draw(this);
}
}
어떤 방법을 사용해야합니까? 이 경우 와일드 카드가 유용합니까?
답변
그것은 당신이 무엇에 따라 필요 할 수 있습니다. 다음과 같은 작업을 수행하려면 제한된 유형 매개 변수를 사용해야합니다.
public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
if (shape.isPretty()) {
shapes.add(shape);
}
}
여기에 a List<T> shapes
와 a T shape
가 있으므로 안전하게 할 수 shapes.add(shape)
있습니다. 선언 된 경우 안전하게 List<? extends Shape>
이동할 수 없습니다add
(a List<Square>
및 a 가있을 수 있기 때문에 Circle
).
따라서 제한된 유형 매개 변수에 이름을 지정하여 일반 메소드의 다른 곳에서 사용할 수 있습니다. 물론이 정보가 항상 필요한 것은 아니므로 유형 (예 :)에 대해 많이 알 필요가없는 경우 drawAll
와일드 카드만으로 충분합니다.
경계 유형 매개 변수를 다시 참조하지 않더라도 경계가 여러 개인 경우 경계 유형 매개 변수가 여전히 필요합니다. 다음은 Angelika Langer의 Java Generics FAQ 에서 인용 한 것입니다.
와일드 카드 바운드와 유형 매개 변수 바운드의 차이점은 무엇입니까?
와일드 카드는 하나의 경계 만 가질 수 있지만 유형 매개 변수는 여러 경계를 가질 수 있습니다. 와일드 카드는 하한 또는 상한을 가질 수 있지만 유형 매개 변수에 대한 하한은 없습니다.
와일드 카드 경계와 유형 매개 변수 경계는 둘 다 경계라고 불리며 부분적으로 유사한 구문을 갖기 때문에 종종 혼동됩니다. […]
구문 :
type parameter bound T extends Class & Interface1 & … & InterfaceN wildcard bound upper bound ? extends SuperType lower bound ? super SubType
와일드 카드는 하한 또는 상한 중 하나만 가질 수 있습니다. 와일드 카드 경계 목록은 허용되지 않습니다.
constrast에서 유형 매개 변수는 여러 경계를 가질 수 있지만 유형 매개 변수에 대한 하한은 없습니다.
Effective Java 2nd Edition, Item 28의 인용문 : 제한된 와일드 카드를 사용하여 API 유연성을 높입니다 .
유연성을 극대화하려면 생산자 또는 소비자를 나타내는 입력 매개 변수에 와일드 카드 유형을 사용하십시오. […] PECS는 생산자
extends
, 소비자를 의미합니다.super
[…]반환 유형으로 와일드 카드 유형을 사용하지 마십시오 . 사용자에게 추가적인 유연성을 제공하는 대신 클라이언트 코드에서 와일드 카드 유형을 사용하도록 강제합니다. 올바르게 사용 된 와일드 카드 유형은 클래스 사용자에게 거의 보이지 않습니다. 메서드가 허용해야하는 매개 변수를 받아들이고 거부해야하는 매개 변수를 거부하도록합니다. 클래스 사용자가 와일드 카드 유형에 대해 생각해야한다면 클래스의 API에 문제가있을 수 있습니다.
PECS 원칙을 적용하여 이제 addIfPretty
예제 로 돌아가서 다음을 작성하여 더 유연하게 만들 수 있습니다.
public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }
이제 우리는 addIfPretty
a Circle
, a List<Object>
. 이것은 명백히 typesafe하지만 우리의 원래 선언은 그것을 허용 할만큼 충분히 유연하지 않았습니다.
관련 질문
- Java Generics : PECS 란 무엇입니까?
- 사람이 무엇을 설명 할 수
<? super T>
평균과 때 사용해야하는 방법이 건설에 협조해야<T>
하고<? extends T>
?
요약
- 제한된 유형 매개 변수 / 와일드 카드를 사용하면 API의 유연성이 향상됩니다.
- 유형에 여러 매개 변수가 필요한 경우 경계 유형 매개 변수를 사용할 수밖에 없습니다.
- 유형에 하한이 필요한 경우 경계 와일드 카드를 사용할 수밖에 없습니다.
- “생산자”는 상한을, “소비자”는 하한을 가짐
- 반환 유형에 와일드 카드를 사용하지 마십시오.
답변
귀하의 예에서는 T를 사용할 필요가 없습니다. 다른 곳에서는 해당 유형을 사용하지 않기 때문입니다.
하지만 다음과 같이했다면 :
public <T extends Shape> T drawFirstAndReturnIt(List<T> shapes){
T s = shapes.get(0);
s.draw(this);
return s;
}
또는 polygenlubricants가 말한 것처럼 목록의 유형 매개 변수를 다른 유형 매개 변수와 일치시키고 싶다면 :
public <T extends Shape> void mergeThenDraw(List<T> shapes1, List<T> shapes2) {
List<T> mergedList = new ArrayList<T>();
mergedList.addAll(shapes1);
mergedList.addAll(shapes2);
for (Shape s: mergedList) {
s.draw(this);
}
}
첫 번째 예제에서는 Shape의 자식을받을 수있는 함수에 결과를 전달할 수 있기 때문에 Shape 만 반환 한 다음 좀 더 형식 안전성을 얻습니다. 예를 들어 a List<Square>
를 내 메서드에 전달한 다음 결과 Square를 Squares 만 사용하는 메서드에 전달할 수 있습니다. ‘?’를 사용한 경우 결과 Shape를 Type 안전하지 않은 Square로 캐스팅해야합니다.
두 번째 예에서는 두 목록이 동일한 유형 매개 변수 ( ‘?’로 할 수 없음)를 가지고 있는지 확인하여 두 목록 모두의 모든 요소를 포함하는 목록을 만들 수 있습니다. .
답변
2 개의 SinglyLinkQueue를 병합하려는 아래의 James Gosling 4 판의 Java 프로그래밍에서 다음 예제를 고려하십시오.
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입니다. 첫 번째 방법은 책에 없습니다.
답변
내가 이해하는 한, 와일드 카드는 유형 매개 변수가 필요하지 않은 상황에서 더 간결한 코드를 허용합니다 (예 : 여러 곳에서 참조되거나 다른 답변에서 자세히 설명한 것처럼 여러 경계가 필요하기 때문에).
링크에서 귀하는이 방향을 암시하는 다음 문장을 읽었 음을 나타냅니다 ( “Generic Methods”아래).
일반 메서드를 사용하면 형식 매개 변수를 사용하여 메서드 및 / 또는 반환 형식에 대한 하나 이상의 인수 형식 간의 종속성을 표현할 수 있습니다. 이러한 종속성이 없으면 제네릭 메서드를 사용하면 안됩니다.
[…]
와일드 카드를 사용하는 것이 명시 적 유형 매개 변수를 선언하는 것보다 더 명확하고 간결하므로 가능할 때마다 선호해야합니다.
[…]
또한 와일드 카드는 필드, 지역 변수 및 배열의 유형과 같이 메서드 서명 외부에서 사용할 수 있다는 이점도 있습니다.
답변
두 번째 방법은 좀 더 장황하지만 T
내부 를 참조 할 수 있습니다 .
for (T shape : shapes) {
...
}
내가 이해하는 한 그게 유일한 차이점입니다.