Lang/Java

제네릭

soooy0 2024. 12. 6. 19:35
  • 클래스 생성 전 우리는 이 클래스에 어떤 내용물을 넣을지 미리 알고 있다. 따라서, 저장할 내용물의 타입을 미리 알려주면 Box라는 클래스는 content 필드에 무엇이 대입되고, content를 읽을 때 어떤 타입으로 제공할지 알게 됨 → 이것이 제네릭
  • 제네릭: 결정되지 않은 타입을 파라미터로 처리하고, 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능
// Box클래스에서 결정되지 않은 content의 타입을 T라는 타입 파라미터로 정의함
public class Box<T> {

	// BOX의 내용물에는 다양한 것이 들어갈 수 있기 때문에 T라는 타입 파라미터로 정의
	public T content;
}

// Box클래스는 T가 무엇인지는 모르나, 객체가 생성될 시점에 다른 타입으로 대체된다는 것을 알고 있게 된다.
Box<String> box = new Box<String>();
box.content = "안녕하세요.";
String content = box.content; // (String)을 붙여 강제 형변환 할 필요 없이 바로 데이터를 얻을 수 있음

//만약 content에 정수형 숫자 100을 저장하고 싶다면, <Integer>로 대체하면 된다.

 

제네릭 타입
  • <T>에서 타입 파라미터로 쓰이는 T는 임의로 정한 것이고, 어떤 알파벳을 써도 된다. 단, 여기에 들어갈 수 있는 타입은 클래스 및 인터페이스이다. <int>와 같은 기본 타입은 타입 파라미터의 대체 타입이 될 수 없다.
Box<String> box = new Box<String>(); >> Box<String> box = new Box<>();
Box<Integer> box = new Box<String>(); >> Box<Integer> box = new Box<>();


// 변수를 선언할 때와 동일한 타입으로 호출하고 싶다면, 생성자 호출 시 생성자에는 타입을 명시하지 않고 <>만 붙일 수 있다.
  • <>부호 안에 타입 파라미터들은 여러 개 작성 가능하다. 외부에서 제네릭타입을 사용하려면 구체적인 타입을 지정해야 한다. 만약 지정하지 않으면 Object타입이 암묵적으로 사용된다.
제네릭 메소드
  • 마찬가지로 제네릭 메소드도 타입 파라미터를 가지고 있는 메소드를 말한다. 타입 파라미터가 메소드 선언부에 정의된다는 점에서 제네릭 타입과 차이가 있다.
public <A, B, ...>  리턴타입 메소드명(매개변수, ...){...}

ex) public <T> Box<T> boxing(T t){...}

 

제한된 타입 파라미터
  • 경우에 따라서 타입 파라미터를 대체하는 구체적인 타입을 제한할 필요가 있다. 예를 들면 숫자를 연산하는 메소드는 타입을 정수형, 혹은 실수타입으로 제한해야 한다.
  • 제한된 타입 파라미터 : 특정 타입과 상속(하위) 또는 구현관계에 있는 타입만 대체할 수 있는 타입 파라미터를 말한다.
public <T extends 상위타입>  리턴타입 메소드명(매개변수, ...){...}

ex) public <T extends Number> boolean compare(T t1, T t2){
		double v1 = t1.doubleValue();
        double v3 = t2.doubleValue();
       
       return (v1 == v2);
     }
     
     
// 타입 파라미터가 Number타입으로 제한되면서, Object의 메소드 뿐만 아니라 Number가 가지고 있는 메소드도 사용 가능.
// doubleValue()는 Number클래스에 정의되어 있는 메소드이다.

 

와일드카드 타입 파라미터
  • 제네릭 타입을 매개값이나 리턴 타입으로 사용 할 때 타입 파라미터로 ? (와일드카드)를 사용할 수 있다.
  • ?는 범위에 있는 모든 타입으로 대체할 수 있다는 의미이다.
  • 예를 들어 Person extends Worker, Student // Student extends HighStudent, MiddleStudent 라고 할 때, 타입 파라미터의 대체 타입으로 student와 그 하위 클래스들만 가능하도록 매개변수를 선언하려면 아래와 같이 쓴다.
리턴타입 메소드명(제네릭타입<? extends Student> 변수) {...}

 

  • 반대로 Worker와 상위 클래스인 Person만 가능하도록 선언하려면 아래와 같이 쓴다.
리턴타입 메소드명(제네릭타입<? super Worker> 변수) {...}

 

  • 어떤 타입이든 가능하도록 선언할 수도 있다.
리턴타입 메소드명(제네릭타입<?> 변수) {...}