본문 바로가기
Java Tutorial

[Java] 제네릭스 (Generics)

by 미소5 2023. 2. 16.
    • 제네릭스란?
    • class 클래스명<T>, interface 인터페이스명<T>, T  변수명, T  메소드명()
    • 저장되는 요소를 제네릭타입<T> 으로 제한 (제네릭 타입과 일치하는 객체만 저장)
    • Object를 사용하면, 자바의 모든 객체를 받을 수 있음
    1. 객체의 타입 안정성을 높인다.
    2. 타입체크와 형변환을 생략할수있으므로 코드가 간결해진다. →프로그램 성능 향상
List list=new ArrayList();
list.add("hello");
String str=(String)list.get(0);		//타입변환 해야함
List<String> list=new ArrayList<String>();	//String객체만 저장할수있는 list 생성
list.add("hello");
String str=list.get(0);		//타입변환할 필요 없음

 

  • 타입변수<T>
    • 제네릭클래스를 작성할때, Object타입(일반클래스) 대신 타입변수<T>를 선언해서 사용 (모두 타입파라미터T로 대체   → 매개변수화된 타입)
    • 객체 생성 시, 타입변수 <T> 대신 실제 타입을 대입 (타입변수에 대입은 인스턴스별로 다르게 가능)
      • 다형성 
        • 참조변수와 생성자의 대입된 타입은 일치해야한다.     List<String> list=new ArrayList<String>(); 
        • 제네릭클래스 간의 다형성은 성립     List<Tv> list = new ArrayList<Tv>();     //ok. ArrayList는 List의 자손
        • 매개변수의 다형성도 성립     ArrayList<Product> list = new ArrayList<Product>();     list.add(new Tv());  //ok. Tv는 Product의 자손
    • static멤버에는 타입변수를 사용할수없다.
    • 타입변수로 배열 선언은 가능하지만(T타입의 배열 ok), 배열 생성할때는 타입변수 사용 불가 (new T[n]은 불가)
    • 멀티타입파라미터:     여러개의 타입변수가 필요한 경우, 콤마를 구분자로 선언.     class<K,V...> 

 

  • 제한된 제네릭클래스, 제한된 타입파라미터
    • <T extends 상위타입>
    • 타입파라미터T에 대입할수있는 타입을 제한
    • 상위타입은 클래스 뿐 아니라 인터페이스도 가능

 

 

 

  • 와일드카드 타입
    • 하나의 참조변수로 대입된 타입이 다른 객체를 참조 가능   
      •  ArrayList<? exends Product> list = new ArrayList<Tv>();
    • 와일드카드는 다음 세가지형태로 사용할수있다     
      • <?>
        • 제한없음: 모든 타입이 올수있다. <? extends Object>와 동일
      • <? extends 상위타입>
        • 상위클래스 제한: 상위타입과 그 자손들만 가능
      • <? super 하위타입>
        • 하위클래스 제한: 하위타입과 그 조상들만 가능  
    • 메소드의 매개변수에 와일드카드를 사용할수있다.   
class Course<T> { ... }
void register(Course<?> c){...} 

void registerStudent(Course<? extends Student> c){...} 

void registerWorker(Course<? super Worker> c){...}
Course<Person> personCourse = new Course<Person>("일반인과정", 5);

/**매개변수의 다형성은 성립*/
personCourse.add(new Person("일반인"));
personCourse.add(new Worker("직장인"));   //Worker는 Person의 자손

 

 

 

  • 제네릭 메소드:     제네릭 타입이 선언된 메소드 (타입변수는 메소드 내에서만 유효)
    • <T,...> 반환타입 메소드명(매개변수,...) { } 
    • 메소드를 호출할때마다, 다른 제네릭타입을 대입할수있게함
    • 클래스의 타입매개변수와 메소드의 타입매개변수는 별개 (다른 타입변수)
    • 메소드를 호출할때마다, 타입을 대입 (대부분 생략가능)
      • 메소드를 호출할때 타입을 생략하지않을때는, 클래스이름 생략 불가     
        • Util.<Integer, String>compare(a,b);     //ok
        • Juicer.<Fruit>makeJuice(f);     //ok
        • <Fruit>makeJuice(f);     //에러

 

 

 

  • 제네릭타입의 형변환
    • 와일드카드가 사용된 제네릭타입으로는 형변환 가능     
      • Box<Object> objBox = (Box<Object>)new Box<String>();     //에러. 형변환 불가능
      • Box<? extends Object> wBox = (Box<? extends Object>)new Box<String>();      //ok
    • 제네릭타입과 원시타입(일반클래스) 간의 형변환은 바람직하지않다. (경고 발생)     

 

 

 

  • 제네릭타입의 제거: 컴파일러는 제네릭타입을 제거하고, 필요한 곳에 형변환을 넣는다
    1.  제네릭 타입의 경계를 제거
    2.  제네릭타입 제거 후에 타입이 불일치하면, 형변환을 추가
    3.  와일드카드가 포함된 경우, 적절한 타입으로 형변환 추가
1.

class Box<T extends Fruit>{
	void add(T t){...}
    }
    
//제네릭타입의 제거
class Box{
	void add(Fruit t){...}
    }
2.

get(int i){
	return list.get(i);
    }
    
//제네릭타입의 제거
Fruit get(int i){
	return (Fruit)list.get(i);
    }
3.

static Juice mekeJuice(FruitBox<? extends Fruit> box){
    String tmp="";
    for (Fruit f:box.getList()){
    	tmp += f+"";
    return new Juice(tmp);
}
  
//제네릭타입의 제거
static Juice mekeJuice(FruitBox box){
    String tmp="";
    Iterator it=box.getList().iterator();
    while(it.hasNext()){
    	tmp+= (Fruit)it.next() +"";
        }
    return new Juice(tmp);
}
728x90
반응형

'Java Tutorial' 카테고리의 다른 글

[Java] 람다식  (0) 2023.03.14
[Java] Set컬렉션  (0) 2023.02.19
[Java] List컬렉션  (0) 2023.02.18
[Java] 컬렉션 프레임워크 (Collection Framework)  (0) 2023.02.16
[Java] 객체 지향 프로그래밍 (Object Oriented Programming)  (0) 2023.02.10