강의 날짜:4/30(수)
드디어 마지막이다 마지막인만큼 내가 이해하지 못했던 개념에 대해서 설명하려고 지네릭스를 주제로 선정했다
이해가 안돼서 공부를 미뤘는데 발표를 핑계로 공부했다
처음에는 이해가 안됐는데 계속 보다보니까 알 것 같기도 하다
이번에도 개념 설명은 다른 분이 하고 나는 그거에 맞춰서 코드 설명을 했다
벌써 네번이나 해서 그런지 처음했을 때보다 긴장도가 덜 해진거 같다 확실히 도움이 많이 된듯하다... 이제는 개념공부와 더불어서 실습을 더 많이 하려고 한다 스터디는 이제 끗
: 컴파일 시 타입 체크
타입 안정성 확보
형변환없이 사용 가능 -> 코드 간결
Object 타입의 문제점
- 모든 타입을 받을 수 있지만 꺼낼 때 형변환 필요 -> 런타임 에러 위험 있음
Box b = new Box();
b.set("Hello");
Integer i = (Integer) b.get(); // ❗ 런타임 오류!
참조변수와 생성자에 대입된 타입(매개변수화된 타입)이 일치해야 함
Box<Apple> appleBox = new Box<Apple>();
Box<Fruit> appleBox = new Box<Apple>(); //상속 관계여도 호환X, 타입이 정확히 같아야 함
Box<Apple> appleBox = new fruitBox<Apple>(); //다형성, 가능함
지네릭 타입에 extends를 사용하면 특정타입의 자손들만 대입 할 수 있게 제한
class FruitBox<T extends Fruit>
//Fruit와 그의 자손 가능
<? extends T>
: 와일드 카드의 상한 제한, T와 그 자손들만 가능
<? super T>
: 와일드 카드의 하한 제한, T와 그 조상들만 가능
<?>
:제한 없음, 모든 타입 가능, <? extends object> 와 동일
import java.util.ArrayList;
class Fruit2 {public String toString(){return "Fruit";}}
class Apple2 extends Fruit2 {public String toString(){return "Apple";}} //Fruit2클래스를 상속받음
class Grape2 extends Fruit2 {public String toString(){return "Grape";}}//Fruit2클래스를 상속받음
class Juice{//주스 문자열을 더해주는 클래스
String name;
Juice(String name){this.name=name+ "Juice";}//매개변수가 있는 생성자,매개변수로 받은 name에 "juice" 문자열을 더해 iv 변수 name에 저장
public String toString(){return name;}//toString으로 name 반환
}
class Juicer{//주스를 만드는 클래스
static Juice makeJuice(FruitBox1<? extends Fruit2> box){//juice객체를 반환하는 makeJuice메서드
//매개변수 box의 타입이 Fruit2와 그 자손들 가능
//FruitBox1<Fruit2> 이렇게 쓰면 Fruit2인 타입만 가능함 / 그래서 와일드카드로 자손도 가능하게 만듦
//static Juice makeJuice(FruitBox1<T extends Fruit2> box) ->문법오류 메서드 매개변수에는 타입 매개변수 T를 쓸 수 없음
String tmp="";
for(Fruit2 f : box.getList())//box안에 있는 Fruit2의 객체(Apple2,Grape2)을 하나씩 꺼냄
tmp+=f+" ";//tmp에 객체의 toString을 호출해서 문자열로 만듦
return new Juice(tmp);//juice 객체 생성과 매개변수가 있는 생성자로 초기화
}
}
public class Ex12_3 {
public static void main(String[] args) {
FruitBox1<Fruit2> fruitBox=new FruitBox1<Fruit2>();
FruitBox1<Apple2> appleBox=new FruitBox1<Apple2>();
fruitBox.add(new Apple2());
fruitBox.add(new Grape2());
appleBox.add(new Apple2());
appleBox.add(new Apple2());
//appleBox.add(new Grape2()); 에러 타입이 다름, appleBox는 타입이 Apple이라 Apple만 가능
System.out.println(Juicer.makeJuice(fruitBox));//참조변수 fruitBox를 makeJuice메서드의 매개변수로 넘겨줌
System.out.println(Juicer.makeJuice(appleBox));
}
}
class FruitBox1<T extends Fruit2> extends Box2<T>{}
//FruitBox1의 클래스의 타입은 Fruit2와 그 자손들(타입제한)
//Box2 지네릭 클래스를 상속받아 그 멤버 사용가능
class Box2<T>{//제네릭 클래스임
ArrayList<T> list= new ArrayList<T>();//데이터 저장 arraylist가 담당
void add(T item){list.add(item);}
T get(int i){return list.get(i);}
ArrayList<T> getList(){return list;}//list의 값을 반환
int size(){return list.size();}
public String toString(){return list.toString();}
}
T vs ? 차이
<T extends X>
: 메서드 내부에서 T를 직접 쓸 때 사용? extends X
: 타입을 받기만 하고 내부에서 타입 이름 쓸 필요 없을 때 사용 → 간단함