지네릭스(Generics) part 1

Shaun·2021년 8월 17일
0

JAVA

목록 보기
14/30

지네릭스란?

  • 지네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능이댜.

  • ArrayList의 경우 object[] 타입이라 다양한 종류의 객체를 담을 수 있지만 보통 한 종류의 객체를 담는 경우가 많다. 그런데 꺼낼때마다 형변환을 하고 타입체크하고... 너무 불편하다. 그리고 원하지 않는 종류의 객체가 포함되는걸 막을 방법도 없다.

-> 지네릭스가 해결해줄께!

지네릭스의 장점
1. 타입 안정성을 제공한다.
2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.

※ 기존에는 다양한 종류의 타입을 다루는 메서드의 매개변수나 리턴타입으로 Object타입의 참조변수를 많이 사용했고 그로 인해 형변환이 불가피 했지만 이젠 Object 대신 원하는 타입을 지정하기만 하면된다.

 Box<String> b= new Box<String>();
 b.setItem(new Object());	//에러 String타입 이외 지정불가
 b.setItem("ABC");
 String item=(String)b.getItem(); //**형변환 필요없음**
 
 

지네릭 특징

지네릭 타입에 Object타입을 지정하면 타입을 지정하지 않은게 아니고 일부로 알고 적은 것이므로 경고는 발생하지 않는다.

컴파일 후에 Box<String.> 과 Box<Integer.> 는 이들의 원시 타입 인 Box로 바뀐다. 즉 지네릭 타입이 제거 된다.

지네릭스의 제한

  • 지네릭 클래스 Box의 객체를 생성할떄 객체별로 다른 타입을 지정하는 것은 적절하다. 하지만 static맴버에 타입변수T를 사용할 수 없다. T는 인스턴스로 간주 되기 떄문이다.(static맴버는 인스턴스변수를 참조할수 없다.)

    	Box<Apple>appleBox= new Box<Apple>();
    	 BOX<Grape> grapeBox= new Box<Grape>();
  • 지네릭 타입의 배열을 선언하는 것은 가능하지만 배열을 생성하는 것은 불가하다.

    	T[] itemArr  // 가능
    
    	T[] tmpArr=new T[itemArr.length]  //불가

    ->왜냐하면 new연산자 떄문이다. 이연산자는 컴파일시 T타입이 뭔지 정확히 알아야한다.

    ->instance of 연산자도 같은 이유로 T를 피연산자로 사용할수 없다.

지네릭 클래스의 객체 생성과 사용

  1. 참조변수와 생성자에 대입된 타입(매개변수화된 타입) 이 일치해야 한다

    box<Apple> appleBox=new Box<Apple>(); //가능
  2. 두타입이 상속관계에 있어도 마찬가지이다. Apple이 Fruit의 자손이라고 가정하자.

    box<Fruit> appleBox=new Box<Apple>();  //에러 대입된 타입 다름
  3. 두 지네릭 클래스의 타입이 상속관계에 있고 대입된 타입이 같은건 괜찮다.

    Box<Apple> appleBox=new Fruit<Apple>();  //가능
  4. add(T item) 대입된 타입과 다른 타입의 객체는 추가 할수 없다. 하지만 T가 fruit인 경우 Fruit 자손들은 매개변수가 될수 있다.

    Box<Fruit> fruitBox=new Box<Fruit>(); 
    fruitBox.add(new Fruit());
    fruitBox.add(new Apple()); //자손 가능 

제한된 지네릭 클래스

  • 한 류의 타입만 저장할 수 있도록 제한할 수 있지만, 그래도 여전히 모든 종류의 타입을 지정할 수 있다는 것에는 변함이 없다. 이를 해결 하기위해 한종류의, 지정된 타입만 들어올수 있게 'extends' 를 사용한다.
  • 'extends' 를 사용하면 특정 타입의 자손들만 대입할수 있다.

    	class FruitBox<T extends Fruit>{   //Fruit의 자손만 타입으로 올수 있다.
    
    	 }
  • T타입에 Object 를 대입하면 모든 종류 의 객체를 저장할수 있다.

※ 만약 클래스가 아니라 인터페이스를 구현 해야 한다하면, 이떄도 'extends' 를 사용한다. implements 사용 x

※ 클래스 Fruit의 자손이면서 Eatable 인터페이스도 구현해야 한다면 '&' 기호를 써준다
->class FruitBox<T extends Fruit & Eatable>

와일드 카드

1.쥬스를 만드는 메서드가 있다고 가정해보자.

  • Juice makeJuice(FruitBox<Fruit> box){
    }
  1. 이렇게 FruitBox< Friut> box로 고정해 버리면 다른 타입의 객체FruitBox< Apple> box는 매개변수가 될수 없어서 매서드를 따로 만들어야한다.

    3.그러나 지네락 타입이 다른 것만으로는 오버로딩이 성립하지 않는다.

  2. 이럴때 사용하는게 와일드카드 기호로는 '?'로 표현하고 어떠한 타입도 될수 있다.

< ? extends T> = 와일드 카드의 상한 제한/ T와 그 자손들만 가능
< ? super T> = 와일드 카드의 하한 제한 /T와 그 조상들만 가능
< ?> = 제한없음/ 모든타입가능

  • Fruit 의 자손 FruitBox< Apple>/ Fruit< Fruit>/ Fruit< Grape> 다 가능하다.
    -> Juice makeJuice(FruitBox<? extends Fruit> box){
    }
profile
호주쉐프에서 개발자까지..

0개의 댓글