1-2. 제네릭 적용

shin·2024년 6월 16일

제네릭을 사용하면 코드 재사용과 타입 안전성이라는 장점을 한 번에 잡을 수 있음

제네릭 적용 예제

package generic.ex1;
 	public class GenericBox<T> {
    
 		private T value;
        
 		public void set(T value) {
 			this.value = value;
    	}
        
 		public T get() {
 			return value;
    	}
        
}
  • <>를 사용한 클래스를 제네릭 클래스라고 함

    • 이 기호를 보통 다이아몬드라고 부름
  • 제네릭 클래스를 사용할 때는 Integer, String 같은 타입을 미리 결정하지 않음

  • 그 대신 클래스명 오른쪽에 <T>와 같이 선언하면 제네릭 클래스가 됨

    • 여기서 T를 타입 매개변수라고 함
    • 이 타입 매개변수는 이후에 Integer, String으로 변할 수 있음
  • 클래스 내부에 T 타입이 필요한 곳에 T value와 같이 타입 매개변수를 적어두면 됨


package generic.ex1;

public class BoxMain3 {
   public static void main(String[] args) {
  		GenericBox<Integer> integerBox = new GenericBox<Integer>(); //생성 시점에 T의 타입 결정
		integerBox.set(10);
   		//integerBox.set("문자100"); // Integer 타입만 허용, 컴파일 오류
  		Integer integer = integerBox.get(); // Integer 타입 반환 (캐스팅 X)
   		System.out.println("integer = " + integer);
        
		GenericBox<String> stringBox = new GenericBox<String>();
		stringBox.set("hello"); // String 타입만 허용
		String str = stringBox.get(); // String 타입만 반환
		System.out.println("str = " + str);
  		
        //원하는 모든 타입 사용 가능
		GenericBox<Double> doubleBox = new GenericBox<Double>();
		doubleBox.set(10.5);
		Double doubleValue = doubleBox.get();
		System.out.println("doubleValue = " + doubleValue);
   	     
   		//타입 추론: 생성하는 제네릭 타입 생략 가능
		GenericBox<Integer> integerBox2 = new GenericBox<>();
      }
 }

실행 결과

integer = 10
str = hello
doubleValue = 10.5

생성 시점에 원하는 타입 지정

class GenericBox<T>
  • 제네릭 클래스는 위와 같이 정의함
    • <>(다이아몬드 기호)안에 타입 매개변수를 정의하면 됨
new GenericBox<Integer>()
  • 제네릭 클래스는 생성하는 시점에 원하는 타입을 지정함
  • 이렇게 지정하면 앞서 정의한 GenericeBoxT가 다음과 같이 지정한 타입으로 변한 다음 생성됨

T에 Integer를 적용한 GenericBox 클래스

public class GenericBox<Integer> {

	private Integer value;
    
 	public void set(Integer value) {
 		this.value = value;
    }
    
	public Integer get() {
 		return value;
    }
    
 }
  • T가 모두 Integer로 변함
  • 따라서 Integer 타입을 입력하고 조회할 수 있음
integerBox.set(10); //성공
integerBox.set("문자100") // Integer 타입만 허용, 컴파일 오류
  • set(Integer value)이므로 이 메서드에는 Integer 숫자만 담을 수 있음
  • 따라서 String 타입을 담으려고 시도하면 컴파일 오류가 발생함
Integer integer = integerBox.get(); // Integer 타입 변환(캐스팅X)
  • get()의 경우에도 Integer를 반환하기 때문에, 타입 캐스팅 없이 숫자 타입으로 조회가 가능함
new GenericBox<String>()
  • String도 동일한 방식으로 사용하면 됨

T에 String를 적용한 GenericBox 클래스

public class GenericBox<String> {

	private String value;
    
 	public void set(String value) {
 		this.value = value;
    }
    
 	public String get() {
 		return value;
    }
    
 }
  • T가 모두 String으로 변함
  • 따라서 문자열을 입력하고, 문자열을 그대로 조회할 수 있음

원하는 모든 타입 사용 가능

  • 제네릭 클래스를 사용하면 아래와 같이 GenericBox 객체를 생성하는 시점에 원하는 타입을 마음껏 지정할 수 있음
new GenericBox<Double>()
new GenericBox<Boolean>()
new GenericBox<MyClass>()
  • 제네릭을 도입한다고 해서 앞서 설명한 GenericBox<String>, GenericBox<Integer>와 같은 코드가 실제로 만들어지는 것은 아님

  • 대신에 자바 컴파일러가 우리가 입력한 타입 정보를 기반으로 이런 코드가 있다고 가정하고 컴파일 과정에 타입 정보를 반영함

  • 이 과정에서 타입이 맞지 않으면 컴파일 오류가 발생함


타입 추론

GenericBox<Integer> integerBox = new GenericBox<Integer>() // 타입 직접 입력
GenericBox<Integer> integerBox2 = new GenericBox<>() // 타입 추론
  • 첫 번째 줄의 코드를 보면 변수를 선언할 때와 객체를 생성할 때 <Integer>가 두 번 나옴

    • 왼쪽에 있는 변수를 선언할 때의 <Integer>를 보고, 오른쪽에 있는 객체를 생성할 때 필요한 타입 정보를 얻을 수 있음
  • 따라서 두 번째 줄의 오른쪽 코드 new GenericBox<>()와 같이 타입 정보를 생략할 수 있음

  • 이렇게 자바가 스스로 타입 정보를 추론해서 개발자가 타입 정보를 생략할 수 있는 것을 타입 추론이라고 함

    • 참고로 타입 추론은 그냥 되는 것은 아님
  • 자바 컴파일러가 타입을 추론할 수 있는 상황에만 가능함

    • 쉽게 이야기해서 읽을 수 있는 타입 정보가 주변에 있어야 추론할 수 있음


강의 출처 : 김영한의 실전 자바 - 중급 2편

profile
Backend development

0개의 댓글