JAVA2_04_와일드카드

charl hi·2021년 9월 26일
0

JAVA2

목록 보기
4/8

링크텍스트

와일드카드 <?>

  • 하나의 참조변수로 대입된 타입이 다른 객체를 참조 가능
  • <? extends T> : T 포함 그 자손들만 가능, 와일드카드의 상한 제한
  • <? super T> : T 포함 그 조상들만 가능, 와일드카드의 하한 제한
  • <?> : 모든 타입 가능, 제한 없음. == <? extends Object>
ArrayList<? extends Product> list = new ArrayList<Product>();
ArrayList<? extends Product> list = new ArrayList<Tv>();
ArrayList<? extends Product> list = new ArrayList<Audio>();
  • 원래 new + 다음에 확정된 타입만 올 수 있고 앞뒤 같은타입만 되는데, 와일드카드로 가능하게 한다!!

  • 와일드카드로 다형성을 인정?하게 됨!!

  • ✨✨메소드의 매개변수에 와일드카드 사용

static Juice makeJuice(FruitBox<? extends Fruit> box){
...
}
...
System.out.println(Juicer.makeJuice(new FruitBox<Fruit>()));
System.out.println(Juicer.makeJuice(new FruitBox<Apple>()));

ex12_04

import java.util.ArrayList;

class Fruit2{	public String toString() {	return "Fruit2";}}
class Apple2 extends Fruit2{	public String toString() {	return "Apple2";}}
class Grape2 extends Fruit2{	public String toString() {	return "Grape2";}}

class Juice{
	String name;
	Juice(String name){
		this.name = name + "Juice";
	}
	public String toString() {	return name;}
}

class Juicer{
	static Juice makeJuice(FruitBox2<? extends Fruit2> box) {
		String tmp="";
		for(Fruit2 f : box.getList())
			tmp += f + " ";
		return new Juice(tmp);
	}
}

public class Ex12_04 {

	public static void main(String[] args) {
		FruitBox2<Fruit2> fBox = new FruitBox2<>();
		FruitBox2<Apple2> aBox = new FruitBox2<>();
		
		fBox.add(new Fruit2());
		fBox.add(new Apple2());
		fBox.add(new Grape2());
		
		aBox.add(new Apple2());
		aBox.add(new Apple2());
		
		System.out.println("fBox: "+fBox);
		System.out.println("getList(): "+fBox.getList());
		System.out.println("size(): "+fBox.size());
		System.out.println("makeJuice(fBox): "+Juicer.makeJuice(fBox));
		System.out.println(fBox.get(0));
		System.out.println(fBox.get(1));
		System.out.println(fBox.get(2));
		
		System.out.println("aBox: "+aBox);
		System.out.println("getList(): "+aBox.getList());
		System.out.println("size(): "+aBox.size());
		System.out.println("makeJuice(fBox): "+Juicer.makeJuice(aBox));
		System.out.println(aBox.get(0));
		System.out.println(aBox.get(1));
		

	}

}

class FruitBox2<T extends Fruit2> extends Box2<T>{}

class Box2<T>{
	ArrayList<T> list = new ArrayList<>();
	void add(T item) { list.add(item);}
	T get(int i) { return list.get(i);}
	//****??? 맨아래에 있는데 왜 또만들지?? 이런식으로 할수있다 이건가???
	ArrayList<T> getList() { return list;}
	int size() { return list.size();}
	public String toString() { return list.toString();}
}

fBox: [Fruit2, Apple2, Grape2]
getList(): [Fruit2, Apple2, Grape2]
size(): 3
makeJuice(fBox): Fruit2 Apple2 Grape2 Juice
Fruit2
Apple2
Grape2
aBox: [Apple2, Apple2]
getList(): [Apple2, Apple2]
size(): 2
makeJuice(fBox): Apple2 Apple2 Juice
Apple2
Apple2




지네릭메소드

  1. 지네릭 타입이 선언된 메소드
  • ✨✨타입변수는 메소드 내에서만 유효
static <T> void sort(List<T> list, Comparator<? super T> c)`
  • 여기서 static 바로 옆에 <T>가 제네릭 메소드라는 것을 알리는 시그니처이다. - by. 제네릭vs와일드카드


  1. 💖클래스의 타입 매개변수 <T> -- ✨메소드의 타입 매개변수 <T>는 별개!!!
class FruitBox<T> {
...
	static <T> void sort(List<T> list, Comparator<? super T> c) {
		...
	}
}
  • class FruitBox<T><T>static <T> void...<T> 는 ✨✨✨다른 타입변수다!!!!
    -> 같아도 되고 달라도 되고!


static <T extends Fruit> Juice makeJuice(FruitBox<T> box) {
	String tmp = "";
	for(Fruit f : box.getList())
		tmp += f + "";
	return new Juice(tmp);
}
  • ✨✨FruitBox<T><T><T extends Fruit> 를 의미한다!!!
  • 메소드를 호출할 때마다 타입을 대입해야(대부분 생략 가능)
System.out.println(Juicer.<Fruit>makeJuice(fBox));
System.out.println(Juicer.<Apple>makeJuice(aBox));
  • 도 되는데 아래처럼 대부분 생략할 수 있다.
  • 왜?? 생성할 때 <>와 같아서 !!
System.out.println(Juicer.makeJuice(fBox));
System.out.println(Juicer.makeJuice(aBox));


  • 메소드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가!!
System.out.println(<Fruit>makeJuice(fruitBox));	//(X) 클래스 생략 불가
System.out.println(this.<Fruit>makeJuice(fruitBox));	//(O)
System.out.println(Juicer.<Fruit>makeJuice(fruitBox));	//(O)


👀👀지네릭 메소드 & 와일드카드 메소드

지네릭 메소드

  • 지네릭 메소드는 메소드를 호출할 때마다 다른 지네릭 타입을 대입할 수 있게 한 것

와일드카드 메소드

  • 와일드카드는 하나의 참조변수로 서로 다른 타입이 대입된 여러 지네릭 객체를 다루기 위한 것

  • 여기 예시에선 둘다 가능하다. 그러나 둘의 용도가 다르다는 걸 알아야 한다!

  • 와일드카드가 안되는 경우가 있기에 그때는 지네릭을 써야한다.

흠..................



1.

List:

raw type이라고 부르죠 보통. 이렇게 쓰시면 안됩니다.

리스트에 새로운 element 넣을 때 타입체크가 안 되서 문제생길 여지가 아주 많습니다.

참고로 primitive타입 못넣습니다. 마찬가지로 Integer같은 wrapper 클래스 써야됩니다. 만약 그냥 들어가더라도 실질적으로는 auto-boxing 되어서 들어가는 겁니다.

List<?>:

wildcard 라고 부릅니다.

위 raw type처럼 모든 element를 Object로 간주하는건 똑같습니다. 그런데 차이점이 있다면 ✨✨✨add()가 막혀있습니다. null만 넣을 수 있죠. 그래서 이상한 타입의 element가 리스트에 추가되는걸 막아줍니다. 덕분에 안전합니다.

그리고 List<? extends Number> 이런 식으로 범위를 한정지을 수도 있어서 더욱 유용합니다.

List<T>, List<E>:

위 두가지는 type parameter 이름이 다를 뿐 본질적으로 같은겁니다.

기능은 wildcard랑 거의 비슷합니다.

차이점이 있다면 메소드나 클래스 내부에서 저 T, E같은 type parameter을 참조할 수 있단 것 뿐입니다.

List<Object>:

raw type과 동일합니다. 가급적 쓰지 않는 것을 추천드립니다.


제네릭은 보통 클래스 레벨에서 사용하고

와일드카드는 일회성같은 메소드나 메소드 내부변수등에서 사용합니다.

출처 okky


2.

<Object><? extends Object> 차이
링크텍스트


3.

List<?> list;

  1. 원소를 꺼내 와서는 Object에 정의되어 있는 기능만 사용하겠다. equals(), toString(), hashCode()…

  2. List에 타입이 뭐가 오든 상관 없다. 나는 List 인터페이스에 정의되어 있는 기능만 사용하겠다. size(), clear().. ✨✨✨단, 타입 파라미터와 결부된 기능은 사용하지 않겠다! add(), addAll() 사용못함!!!

  3. 와일드 카드는 list에 담긴 원소에는 전혀 관심이 없기 때문에 원소와 관련된 add 메소드를 사용할 수 없다. 단, ✨null은 들어갈 수 있다.

List<T> list;

  1. 원소를 꺼내 와서는 Object에 정의되어 있는 기능만 사용하겠다. equals(), toString(), hashCode()…

  2. List에 타입이 뭐가 오든 상관 없다. 나는 List 인터페이스에 정의되어 있는 기능만 사용을 하고, 타입 파라미터와 결부된 기능도 사용하겠다.

  3. 제네릭은 list에 담긴 원소에 관심을 갖기 때문에 원소와 관련된 add 메소드를 사용할 수 있다. 당연히 null도 들어갈 수 있다.

출처


4.

링크텍스트



링크텍스트

이걸 예시로 만들어보자




Ref

0개의 댓글