자바 제네릭 슈퍼 키워드
나는이 주제를 다뤘다
그러나 나는 여전히 super
키워드 로 잃어버린 것 같습니다 .
다음과 같은 컬렉션을 선언 할 때 :
List<? super Number> list = null; list.add(new Integer(0));//this compiles list.add(new Object());//this doesn't compile
그 반대가 아니어야합니다
Number
. .NET의 부모 인 일부 객체 (알 수없는 유형)를 포함하는 목록이 있습니다 . 따라서Object
(의 부모이므로Number
) 적합Integer
해야하며 그렇지 않아야합니다. 어떤 이유로 든 그 반대입니다.다음 코드가있는 경우
static void test(List<? super Number> param) { param.add(new Integer(2)); } public static void main(String[] args) { ArrayList<String> sList = new ArrayList<String>(); test(sList); //will never compile, however... }
위의 코드를 컴파일하는 것은 불가능하지만 (그리고 제 정신은 이것이 올바른 동작임을 암시합니다) 기본 논리는 그 반대를 증명할 수 있습니다.
String is Object, Object is superclass of Number. So String should work.
나는 이것이 미친 짓이라는 것을 알고 있지만 이것이
<S super T>
구조를 허용하지 않은 이유가 아닙니까? 그렇다면 왜<? super T>
허용됩니까?
누군가 가이 논리 체인의 누락 된 부분을 복원하도록 도와 줄 수 있습니까?
의 경계 와일드 카드는 모든 상위 유형을 List<? super Number>
캡처 할 수 있습니다 Number
. 이므로 Number extends Object implements Serializable
현재 캡처 변환 가능한 유형 List<? super Number>
은 다음과 같습니다.
List<Number>
List<Object>
List<Serializable>
add(Integer.valueOf(0))
위의 유형 중 하나 를 사용할 수 있습니다. 그러나 일반 유형 안전 규칙을 위반하므로 a 또는 a 를 사용할 수 없습니다 .add(new Object())
List<Number>
List<Serializable>
따라서 그것은이다 NOT 사실 당신이 할 수있는 add
모든 슈퍼 타입 Number
A와 List<? super Number>
; 이것은 제한된 와일드 카드와 캡처 변환이 작동하는 방식이 아닙니다. List<? super Number>
를 추가 할 수 있기 때문에 선언하지 않습니다 Object
(할 수 없습니다!). Number
객체 를 추가하고 싶기 때문에 (즉,의 "소비자" Number
) a List<Number>
는 너무 제한적입니다.
참고 문헌
- Angelika Langer의 제네릭 FAQ
- 제한된 와일드 카드 란 무엇입니까?
- 하한이있는 와일드 카드 매개 변수화 된 유형은 언제 사용합니까? ( "구체적인 매개 변수화 된 유형이 너무 제한적일 때.")
- 유형 매개 변수에 대한 하한이없는 이유는 무엇입니까? ( "말이 안 되니까.")
- JLS 5.1.10 캡처 변환
또한보십시오
- 효과적인 Java 2nd Edition , 항목 28 : 제한된 와일드 카드를 사용하여 API 유연성 향상
- "PECS는 생산자
extends
, 소비자,super
- "PECS는 생산자
관련 질문
- 나열 할 항목이 너무 많음, PECS,
new Integer(0)
대valueOf
등
첫 번째 부분의 경우 List<Number>
에 적합 List<? super Number>
하지만 당신은 추가 할 수 없습니다 Object
A를 List<Number>
. 당신은 추가 할 수 없습니다 이유 Object
에 List<? super Number>
.
반면에 Number
( Number
포함됨) 의 모든 하위 클래스를 목록에 추가 할 수 있습니다 .
두 번째 부분의 경우 String
는 Object
이지만 String
의 수퍼 클래스는 아닙니다 Number
.
모든 클래스의 서브 클래스로는,이처럼 일 경우 Object
, super
의미가 없을 것입니다.
가능한 모든 경우를 살펴 보겠습니다 List<? super Number>
.
- 전달 된 목록은
List<Object>
List<Object>
작동 할 것이다Object
맞다<? super Number>
- 의 모든 하위 유형을 추가 할 수 있습니다
Number
.List<Object>
- 또한 추가 할 수 있다고하더라도
String
.NET Framework의 모든 하위 클래스를 추가 할 수 있다는 것을 확신 할 수 있습니다Number
.
- 전달 된 목록은 다음과
List<Number>
같습니다.List<Number>
작동 할 것이다Number
맞다<? super Number>
- 의 모든 하위 유형을 추가 할 수 있습니다
Number
.List<Number>
- 전달 된 목록은 다음과 같습니다
List<Integer>
(또는의 모든 하위 클래스Number
).List<Integer>
작동하지 않습니다- Integer는의 서브 클래스
Number
이므로 정확히 피하고 싶은 것입니다. - 더 경우
Integer
A의 맞는Number
당신이 abble되지 않을 것은의 서브 클래스를 추가하는Number
A의List<Integer>
(예를 들어 A에 대한Float
) super
하위 클래스를 의미하지 않습니다.
- 전달 된 목록은
List<String>
(또는 확장Number
되지 않거나Number
(즉Number
, 및Object
) 의 "수퍼 계층"에 있지 않은 모든 클래스 입니다. )List<String>
작동하지 않습니다String
doesn't fit inNumber
"super hierarchy"- Even if
String
fits inObject
(which is a super class ofNumber
) you woudln't be sure to be able to add aNumber
to aList
that contain any subclass from one of the super classes ofNumber
) super
doesn't mean any subclass of one of the super classes, it only means one of the super classes.
How does it work ?
You could say that as long as you can add any subclass of Number
with your typed List
, it respects the super
keyword.
I didn't get it for a while. Many of the answers here, and the other questions show specifically when and where certain usages are errors, but not so much why.
This is how I finally got it. If I have a function that adds Number
s to a List
, I might want to add them of type MySuperEfficientNumber
which is my own custom class that implements Number
(but is not a subclass of Integer
). Now the caller might not know anything about MySuperEfficientNumber
, but as long as they know to treat the elements added to the list as nothing more specific than Number
, they'll be fine.
If I declared my method as:
public static void addNumbersToList(List<? extends Number> numbers)
Then the caller could pass in a List<Integer>
. If my method added a MySuperEfficientNumber
to the end of numbers
, then the caller would no longer have a List
of Integer
s and the following code wouldn't work:
List<Integer> numbers = new ArrayList<Integer>();
addNumbersToList(numbers);
// The following would return a MySuperEfficientNumber not an Integer
Integer i = numbers.get(numbers.size()-1)
Obviously this can't work. And the error would be inside the addNumbersToList
method. You'd get something like:
The method add... is not applicable for the arguments (MySuperEfficientNumber)
Because numbers
could be any specific kind of Number
, not necessarily something that MySuperEfficientNumber
is compatible with. If I flipped the declaration around to use super
, the method would compile without error, but the caller's code would fail with:
The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)
Because my method is saying, "Don't think that your List
can be of anything more specific than Number
. I might add all sorts of weird Number
s to the list, you'll just have to deal with it. If you want to think of them as something even more general than Number
-- like Object
-- that's fine, I guarantee they'll be at least Number
s, but you can treat them more generally if you want."
Whereas extends
is saying, "I don't really care what kind of List
you give me, as long as each element is at least a Number
. It can be any kind of Number
, even your own weird, custom, made-up Number
s. As long as they implement that interface, we're good. I'm not going to be adding anything to your list since I don't know what actual concrete type you're using there."
List<? super Number>
means that the reference type of the variable suggests we have a list of Numbers, Objects or Serializables.
The reason you can't add an Object, is because the Compiler does not know WHICH of these classes are in the generic definition of the actual instantiated object, so it only allows you to pass Number or subtypes of Number, like Double, Integer and so on.
Lets say we have a method that returns a List<? super Number>
. The creation of the object inside the method is encapsulated from our view, we just can't say if it is something like this:
List<? super Number> returnValue = new LinkedList<Object>();
or
List<? super Number> returnValue = new ArrayList<Number>();
So, the generic type could be Object or Number. In both cases, we would be allowed to add Number, but only in one case we would be allowed to add Object.
You have to distinguish between the reference type and the actual object type in this situation.
List<? super Number>
is such a List<AncestorOfNumber>
where we can implicitely cast each Number
to its super type AncestorOfNumber
.
Consider this: What generic type needs to be ????
in the following example?
InputStream mystream = ...;
void addTo(List<????> lsb) {
lsb.add(new BufferedInputStream(mystream));
}
List<BufferedInputStream> lb = new ArrayList<>();
List<InputStream> li = new ArrayList<>();
List<Object> lo = new ArrayList<>();
...
{ addTo(lb); addTo(li); addTo(lo); }
The answer: ????
is anything to which we can cast BufferedInputStream
, which is that very same or one of its ancestors: ? super BufferedInputStream
May I give a very simple Example.
public void add(List<? super Number> list) {
}
this will allow these calls
add(new LinkedList<Number>());
and everything above Number like
add(new LinkedList<Object>());
but nothing below the hierarchy so not
add(new LinkedList<Double>());
or
add(new LinkedList<Integer>());
So since its not clear for the program to know whether you give a List with Number or Object the compiler cannot allow you to add anything above Number to it.
For example a List would not accept an Object in spite of Object who would accept a Number. But since this is not clear the only valid input would be Number and its sub types.
참고URL : https://stackoverflow.com/questions/3847162/java-generics-super-keyword
'Development Tip' 카테고리의 다른 글
WCF에서 메서드 오버로딩이 허용되지 않는 이유는 무엇입니까? (0) | 2020.10.29 |
---|---|
문자열 매개 변수를 허용하는 생성자로 클래스 객체를 인스턴스화 하시겠습니까? (0) | 2020.10.29 |
Rspec 출력 형식 : 문서 (0) | 2020.10.29 |
Double 변수를 십진수로 캐스트 (0) | 2020.10.29 |
메모장 ++에서 regexp 캡처 그룹을 바꾸시겠습니까? (0) | 2020.10.29 |