[Java] 제니크스 경계 어댑터 유형 소개
15019 단어 Java
경계 와일드카드 유형의 역할
자바의 일반형은 List<Integer>
형을 List<Number>
형으로 변환할 수 없다.
유형이 다르다// OK 型パラメーターが同一の場合
List<Integer> foo = new ArrayList<Integer>();
// NG List<Integer> は、List<Number> に変換できない
List<Number> bar = foo;
// NG 初期化でも同様に変換不可
List<Number> foo = new ArrayList<Integer>();
따라서 경계 와일드카드를 사용하여 유형 매개변수를 어느 정도 넓게 만들 수 있습니다.
그러나 경계 와일드카드 유형은 두 가지입니다.
형의 경계를 결정할 때 각자의 장면에서 처리계에'확정불능형'문제가 발생하기 때문이다.
나는 그 문제를 하나하나 보고 싶다.
설명은 다음 Frite 클래스를 사용합니다.
최대 와일드카드 유형 Generic<? extends T>
유형 매개변수를 위에서 설명한 대로 지정하면 유형 매개변수는 상한 와일드카드 유형입니다.
? extends T-유형은 T 또는 모든 하위 클래스를 나타내는 유형입니다.
List<? extends Fruit>
유형을 고려하면 지정한 List형에서 Frit 클래스나 하위 클래스를 변환할 수 있습니다.
변환 가능 목록List<? extends Fruit> basket = new ArrayList<Fruit>(); // 1
List<? extends Fruit> basket = new ArrayList<Melon>(); // 2
List<? extends Fruit> basket = new ArrayList<Lemon>(); // 3
다음으로List<? extends Fruit> basket
우리는 변수에서 원소를 추출하는 것을 고려한다
basket 변수는 1이든 2든 3이든 Frit 클래스에서 얻을 수 있는 요소입니다.
넣다
상한 경계 와일드카드에서 T클래스로 변환
List<? extends Fruit> basket
변수에서 원소를 추출하는 것을 고려한다.
상한 어댑터형은 최소한 T클래스와 그 하위 클래스를 나타내는 유형이며List에서 요소를 얻었을 때 상한 T를 지정할 수 있다.
최대 와일드카드 유형을 T-유형으로 변환List<? extends Fruit> fruits = ...
// 問題なし
Fruit fruit = fruits.get(i);
이것은 ? extends T
형에서 T
형으로의 전환이다.
상한 경계 와일드카드에서 T의 하위 클래스로 변환
다음에 basket 변수에서 원소를 가져올 때 이 하위 클래스를 지정할 수 있는지 고려합니다.List<? extends Fruit>
형은 적어도 아래 3가지 List형에서 전환할 수 있다.
// OK 型パラメーターが同一の場合
List<Integer> foo = new ArrayList<Integer>();
// NG List<Integer> は、List<Number> に変換できない
List<Number> bar = foo;
// NG 初期化でも同様に変換不可
List<Number> foo = new ArrayList<Integer>();
Generic<? extends T>
유형 매개변수를 위에서 설명한 대로 지정하면 유형 매개변수는 상한 와일드카드 유형입니다.? extends T-유형은 T 또는 모든 하위 클래스를 나타내는 유형입니다.
List<? extends Fruit>
유형을 고려하면 지정한 List형에서 Frit 클래스나 하위 클래스를 변환할 수 있습니다.변환 가능 목록
List<? extends Fruit> basket = new ArrayList<Fruit>(); // 1
List<? extends Fruit> basket = new ArrayList<Melon>(); // 2
List<? extends Fruit> basket = new ArrayList<Lemon>(); // 3
다음으로List<? extends Fruit> basket
우리는 변수에서 원소를 추출하는 것을 고려한다basket 변수는 1이든 2든 3이든 Frit 클래스에서 얻을 수 있는 요소입니다.
넣다
상한 경계 와일드카드에서 T클래스로 변환
List<? extends Fruit> basket
변수에서 원소를 추출하는 것을 고려한다.상한 어댑터형은 최소한 T클래스와 그 하위 클래스를 나타내는 유형이며List에서 요소를 얻었을 때 상한 T를 지정할 수 있다.
최대 와일드카드 유형을 T-유형으로 변환
List<? extends Fruit> fruits = ...
// 問題なし
Fruit fruit = fruits.get(i);
이것은 ? extends T
형에서 T
형으로의 전환이다.상한 경계 와일드카드에서 T의 하위 클래스로 변환
다음에 basket 변수에서 원소를 가져올 때 이 하위 클래스를 지정할 수 있는지 고려합니다.
List<? extends Fruit>
형은 적어도 아래 3가지 List형에서 전환할 수 있다.ArrayList<Fruit>
ArrayList<Melon>
ArrayList<Lemon>
상한 어댑터 형식은 하위 종류로 변환할 수 없습니다
List<? extends Fruit> basket = ...
// NG コンパイルエラー Melon型には変換できません
Melon fruit = basket.get(i);
? extends Fruit
유형을 하위 클래스로 변환할 수 있는 경우 다음과 같은 모순이 발생합니다.최대 와일드카드 유형을 T 하위 클래스 1로 변환
// メロンリストを作る
List<Melon> melonList = new ArrayList<Melon>()
melonList.add(new Melon());
// List<Melon> melonList型をList<? extends Fruit>型に変換
List<? extends Fruit> basket = melonList;
// サブクラスへの変換が可能であればLemonとして受け取ることが可能となってしまう
Lemon fruit = basket.get(i);
따라서 하위 클래스로 변환할 수 없습니다.따라서
? extends T
형에서 Tのサブクラス
형으로 전환할 수 없다.쓰기
다음
List<? extends Fruit> fruits
은 변수에 원소를 추가하는 것을 고려한다.? extends Fruit
유형에서 Fruit型
로 전환할 수 있기 때문에 아래의 frits 변수에 Frits 대상을 추가할 수 있습니다.최대 와일드카드 유형에 쓰기
List<? extends Fruit> fruits = new ArrayList<Fruit>();
// 一見可能に思える
fruits.add(new Fruit());
그러나 이 같은 내용을 허용하면 다음과 같은 모순이 생길 수 있다.상한 어댑터 형식에 쓰기 모순
// fruitsの実態はメロンリスト
List<? extends Fruit> fruits = new ArrayList<Melon>();
// LemonクラスはFruitクラスのサブクラス
Fruit fruit = new Lemon();
// メロンリストにレモンが追加出来ることになる
fruits.add(fruit);
따라서 구체형T
형이나 Tのサブクラス
형에서 ? extends T
형으로 전환할 수 없다.상한선이 있는 와일드카드로 리스트형을 선언하면 요소를 추가할 수 없다는 의미다.
그곳에는 경계 어댑터 모양의 출전이 하나 더 있다.
※ 앱펜딕스에 구체형에서 전환에 대한 설명이 추가되었습니다.
최소 와일드카드 유형 Generic<? super T>
유형 매개변수를 위에서 설명한 대로 지정하면 유형 매개변수는 하한선이 있는 와일드카드 유형입니다.
? 슈퍼T형은 T나 그 슈퍼클래스의 모든 유형을 나타낸다.
List형은 List형에서 Frit 클래스나 슈퍼 클래스를 형 매개 변수로 변환할 수 있다.
변환 가능 목록List<? super Melon> baskets = new ArrayList<Melon>(); // 1
List<? super Melon> baskets = new ArrayList<Fruit>(); // 2
List<? super Melon> baskets = new ArrayList<Food>(); // 3
List<? super Melon> baskets = new ArrayList<Object>(); // 4
이번에는 제가 앞뒤로 basket 변수에 원소를 추가하는 걸 생각해 볼게요.
1∼4에서는 1·2·3·4와 관계없이 basket 변수에 멜론류를 추가할 수 있다.
쓰기
최소 와일드카드 유형으로 변환
List<? super Melon> basket
요소를 변수에 추가하려면 하한선이 있는 와일드카드 유형의 경우 최소한 T 클래스 또는 그 이상의 슈퍼 클래스를 나타내는 유형이어야 하기 때문에 List형에 요소를 추가할 때 하한선 T를 지정할 수 있어야 한다.
확인은 예시를 참고하여 하나하나 추가할 수 있다.List<? super Melon> fruits = new ArrayList<Object>()
시
Object 목록에 추가// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());
List<? super Melon> fruits = new ArrayList<Food>()
시
Food 목록에 추가// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());
List<? super Melon> fruits = new ArrayList<Melon>()
시
멜론에 추가// OK
fruits.add(new Melon());
// OK
fruits.add(new WaterMelon());
즉 T
또는 Tのサブクラス
형에서 ? super T
형으로 전환할 수 있다는 것이다.
넣다
? 슈퍼 멜론형은'멜론 클래스와 그 슈퍼 클래스를 나타내는 타입'이다.
그리고 자바의 모든 학급은 Object형을 계승했다.
따라서 ? super T
형에서 Object
형으로 전환할 수 있다.
하위 와일드카드 유형에서 Object 유형으로 변환Object object = basket.get(i)
총결산
Generic<? super T>
List<? super Melon> baskets = new ArrayList<Melon>(); // 1
List<? super Melon> baskets = new ArrayList<Fruit>(); // 2
List<? super Melon> baskets = new ArrayList<Food>(); // 3
List<? super Melon> baskets = new ArrayList<Object>(); // 4
// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());
// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());
// OK
fruits.add(new Melon());
// OK
fruits.add(new WaterMelon());
Object object = basket.get(i)
상한 경계 어댑터 형식과 구체적인 형식의 변환 테이블
가부
변환 소스
목표
그런 뜻
OK
? extends T
T
T
유형치 획득 가능NG
T
? extends T
쓰기 불가하위 와일드카드 유형 및 특정 유형의 변환 테이블
가부
변환 소스
목표
그런 뜻
OK
? super T
Object
Object형으로 값을 얻을 수 있음OK
T
? super T
쓰기 가능 T-값OK
Tサブクラス
? super T
T에 쓸 수 있는 하위 클래스 값일반적으로 PECS라는 주문이 존재하는데, 상한 경계 어댑터는 Producter라고 하고, 하한 경계 어댑터는 Consumer라고 한다
Appendix
경계 와일드카드 유형을 사용하여 값 쓰기
상한 경계 와일드카드를 지정했을 때, 그 List는 쓸 수 없다는 말을 들은 적이 있을 것이다.
이것은 단순히 이하로 할 수 없다는 뜻이다.具体型
에서 上限付きワイルドカード型
로 변경할 수 없음
Genesis형 객체를 선언하는 데 상한 와일드카드를 사용하는 경우 이러한 유형의 매개 변수가 있는 함수를 호출할 때 이러한 변환이 발생합니다.
다음은 Stack 클래스입니다.
ack 등급class Stack<T> {
void push(T e) {}
}
최대 와일드카드 유형을 사용하여 Stack 클래스를 선언합니다.Stack<? extends Fruit> basket = new Stack<Fruit>();
이때 basket 변수의 유형 매개 변수 T는 ? extends Fruit
형입니다.
즉,push 방법은 다음과 같다.
Stack의 유형 매개 변수가 최대 와일드카드일 경우void push(`? extends Fruit` e) {}
따라서 이push 방법을 사용하면 具体型(Fruit)
에서 ? extends Fruit
형으로 전환됩니다.
그리고 이 전환은 NG다.// NG Fruit型を `? extends Fruit` 型へは変換できない
basket.push(new Fruit());
Reference
이 문제에 관하여([Java] 제니크스 경계 어댑터 유형 소개), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/ysn/items/66e225004bf656f012c7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
ack 등급
class Stack<T> {
void push(T e) {}
}
최대 와일드카드 유형을 사용하여 StackStack<? extends Fruit> basket = new Stack<Fruit>();
이때 basket 변수의 유형 매개 변수 T는 ? extends Fruit
형입니다.즉,push 방법은 다음과 같다.
Stack의 유형 매개 변수가 최대 와일드카드일 경우
void push(`? extends Fruit` e) {}
따라서 이push 방법을 사용하면 具体型(Fruit)
에서 ? extends Fruit
형으로 전환됩니다.그리고 이 전환은 NG다.
// NG Fruit型を `? extends Fruit` 型へは変換できない
basket.push(new Fruit());
Reference
이 문제에 관하여([Java] 제니크스 경계 어댑터 유형 소개), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/ysn/items/66e225004bf656f012c7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)