ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 제네릭
    개발/Java 2023. 7. 18. 17:16

    제네릭은 Java 5부터 추가된 타입이다.  

    제네릭 타입을 이용하면 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 발견할 수 있다.

    제네릭은 다음과 같은 이점을 가지고 있다.

    1. 컴파일 시 강한 타입 체크가 가능해진다.

    2. 타입 변환이 제거된다.

     

    제네릭 타입 (class<T>, interface<T>)

    타입을 파라미터로 가지는 클래스나 인터페이스를 말한다. 제네릭 타입은 이름 뒤에 <> 부호가 붙고 <> 사이에 타입 파라미터가 위치한다.

    제네릭을 사용한 코드와 사용하지 않은 코드를 비교해 보면서 차이를 알아보자. 

    public class Box {
    	private Object object;
        
        public void set(Object object) {
        	this.object = object;
        }
        
        public Object get() {
        	return object;
        }
    }
    
    ...
    
    Box box = new Box();
    // String 타입을 Object 타입으로 자동 변환해서 설정
    box.set("hello");
    // Object 타입을 String 타입으로 강제 타입 변환해서 가져옴
    String str = (String) box.get();

    제네릭을 사용하지 않은 코드에서는 타입변환이 일어나는 모습을 확인할 수 있다.

    public class Box<T> {
    	private T t;
        
        public void set(T t) {
        	this.t = t
        }
        public T get() {
        	return this.t;
        }
        
    }
    
    ...
    
    Box<String> box = new Box<String>();
    box.set("Hello");
    String str = box.get();

    타입 변환이 제거된 모습을 확인할 수 있다.

     

    멀티 타입 파라미터 (class<K,V,...>, interface<K,V,....>)

    제네릭 타입은 두 개 이상의 멀티 타입 파라미터를 사용할 수 있다.

    public class Box<A, B> {
    	private A name;
        private B age;
        
        public void setName(A name) {
        	this.name = name;
        }
        public void setAge(B age) {
        	this.code = age;
        }
        
        public A getName() {
        	return this.name;
        }
        
        public B getAge() {
        	return this.age;
        }
    }
    
    
    ...
    
    Box<String, Integer> box = new Box<String, Integer>();
    box.setName("홍길동");
    box.setAge(25);
    
    String name = box.getName();
    int age = box.getAge();

     

    제네릭 메소드 (<T, R> R method(T t))

    매개 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 뜻한다.

    public <타입 파라미터> 리턴 타입 메소드명(매개변수) {}

    제네릭 메소드 호출은 다음과 같이 할 수 있다.

    // 명시적으로 구체적인 타입을 지정
    리턴타입 변수 = <구체적 타입> 메소드명(매개값)
    
    // 매개 값으로 묵시적인 타입 추정
    리턴타입 변수 = 메소드명(매개값)

    제네릭 메소드가 사용되는 예

    public class Box<T> {
    	private T value;
        
        public void set(T value){
        	this.value = value;
        }
        
        public T get() {
        	return this.value;
        }
    }
    
    public class Util {
    	public static <T> Box<T> boxing(T t) {
        	Box<T> box = new Box(T);
            box.set(t);
            return box;
        }
    }
    
    public class BoxingMethodExample {
    	public static void main(String[] args) {
        	// 명시적 호출
        	Box<Integer> box1 = Util.<Integer>boxing(100);
            int intVlaue = box1.get();
            
            // 묵시적 호출
            Box<String> box2 = Util.boxing("홍길동");
            String strValue = box2.get();
        }
    }

     

    제한된 타입 파라미터 (<T extends 최상위 타입>)

    타입 파라미터에서 지정되는 구체적인 타입을 제한하기 위해 사용된다.

    제한된 타입 파라미터 메소드는 다음과 같이 선언할 수 있다.

    public <T extends 상위타입> 리턴타입 메소드(매개변수) {}

    제한된 타입 파라미터가 사용되는 예

    public class Util {
    	public static <T extends Number> int compare(T t1, T t2) {
        	// 매개변수로 넘어온 값을 double 값으로 저장
        	double v1 = t1.doubleValue();
            double v2 = t2.doubleValue();
            // Double.compare는 첫 번째 매개 값이 작으면 -1을, 같으면 0을, 크면 1을 리턴하는 메소드이다.
            return Double.compare(v1, v2);
        }
    }
    
    public class BoundedTypeParameterExample {
    	public static void main(String[] args) {
        	
            // 에러: String은 Number의 하위타입이 아님
            // String str = <String>Util.compare("안녕", "하세요");
            
        	int result1 = <Integer>Util.compare(10, 20);
            int result2 = <Double>Util.compare(4.5, 3);
            
        }
    }

     

    와일드 카드 타입 (<?>, <? extends ...>, <? super ...]>)

    제네릭 타입을 구체적인 타입 대신 와일드카드로 사용하고 싶을 때 다음과 같은 세 가지 방법으로 사용할 수 있다.

    1. 제네릭 타입 <?>: 제한 없음 - 모든 클래스나 인터페이스 타입이 올 수 있다.

    2. 제네릭 타입 <? extends 상위타입>: 상위클래스 제한 - 상위타입이나 하위타입만 올 수 있다.

    3. 제네릭 타입 <? super 하위타입>: 하위클래스 제한 - 하위타입이나 상위타입이 올 수 있다.

     

    다음 예로 쉽게 이해해 보자.

    Person의 하위 클래스로 Worker와 Student가 있고, Student의 하위 클래스로 HighStudent가 있다.

    1. Course<?>

    수강생은 모든 타입(Person, Worker, HighStudent)이 될 수 있다.

    2. Course<? extends Student>

    수강생은 Student와 HighStudent만 될 수 있다.

    3. Course<? super Worker>

    수강생은 Worker와 Person만 될 수 있다.

     

    제네릭 타입의 상속과 구현

    제네릭 타입도 부모 클래스가 될 수 있다.

    다음 예는 제네릭 클래스를 상속받은 클래스의 예다.

    // 자식 제네릭 타입은 추가적인 타입 파라미터를 가질 수 있다.
    public class ChildProduct<A, B, C> extends Product<T, M> {}

     

    ⚠️ 참고: [이것이 자바다] - 제네릭

    '개발 > Java' 카테고리의 다른 글

    초기화  (0) 2023.07.16
    생성자  (0) 2023.07.15
    클래스, 객체와 인스턴스  (0) 2023.07.15

    댓글

Designed by Tistory.