본문 바로가기
study/Java

Java의 Generic

by 고기만두(개발자) 2021. 8. 29. 16:01
728x90
반응형

이번 시간에는 generic에 대하여 알아보려 합니다.

제네릭(generic)이란 데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미합니다.

Java 5 이전에는 대부분의 클래스와 메서드에서 인수나 반환값으로 Object을 사용했습니다.

그러나 object을 사용하는 경우에는 저장할 때와 읽어올 때 총 두 번 다시 원하는 타입으로 타입 변환해야 하며, 이때 오류가 발생할 가능성이 여전히 남아 있습니다.

이를 해결하기 위해 Java 5 버전부터 generic이 추가되어, 클래스/메서드 단에서 잘못된 타입 사용으로 인한 문제를 해결할 수 있게 되었습니다.

제네릭의 장점을 크게 2가지로 요약할 수 있습니다.

1. 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있습니다.

2. 반환되는 값에 대한 타입 변환, 타입 검사에 들어가는 노력을 줄일 수 있습니다.

package jaryogujo;
import java.util.*;
class AnimalList<T> {

    ArrayList<T> al = new ArrayList<T>();

    void add(T animal) {
    	al.add(animal);
    }

    T get(int index) {
    	return al.get(index); 
    }

    boolean remove(T animal) {
    	return al.remove(animal); 
    }

    int size() {
    	return al.size(); 
    }
}

다음과 같이 제네릭 클래스 AnimalList<T> 를 생성했습니다.

'T'를 타입 변수(type variable)라고 하며, 임의의 참조형 타입을 의미합니다.

T가 아닌 어떤 문자를 사용해도 상관없으며, 여러 개의 타입 변수는 쉼표(,)로 구분하여 명시할 수 있습니다.

타입 변수는 클래스에서뿐만 아니라 메서드의 매개변수나 반환값으로도 사용할 수 있습니다.

class LandAnimal {
	public void crying() {
		System.out.println("육지동물"); 
	}
}

class Cat extends LandAnimal {
	public void crying() { 
		System.out.println("냐옹냐옹"); 
	}
}

class Dog extends LandAnimal { 
	public void crying() {
		System.out.println("멍멍");
	}
}

class Sparrow { 
	public void crying() {
		System.out.println("짹짹"); 
	} 
}


public class Generic01 {

    public static void main(String[] args) {
        AnimalList<LandAnimal> landAnimal = new AnimalList<>(); // Java SE 7부터 생략가능

        landAnimal.add(new LandAnimal());
        landAnimal.add(new Cat());
        landAnimal.add(new Dog());
        // landAnimal.add(new Sparrow()); // 오류

         for (int i = 0; i < landAnimal.size() ; i++) {
            landAnimal.get(i).crying();
        }
    }
}

AnimalList<LandAnimal> landAnimal = new AnimalList<>(); 에서처럼, 타입 변수 자리에 실제로 어떤 타입을 사용할 것인지 명시해주어야 합니다.

하지만 인스턴스 생성 시 타입을 추정할 수 있는 경우, Java SE 7 이상 버전에서는 이를 생략해도 무방합니다.

이 예제에서는 LandAnimal이라는 클래스를 지정했습니다.

그리고 HashMap<String, Integer> hm = new HashMap<String, Integer>();에서 본 것처럼 두 개 이상의 타입도 지정할 수 있습니다.

 

그러나 int, string 같은 기본 타입의 경우, 제네릭 클래스를 정의할 때 바로 사용할 수가 없습니다.

대신 Integer같은 wrapper클래스를 사용해야 합니다.

위 예제에서는, LandAnimal과 이를 상속받는 Cat, Dog의 경우 AnimalList에 추가되었고, 그 결과 육지동물에 이어, ‘냐옹냐옹멍멍이 출력되었습니다.

하지만 Sparrow LandAnimal 을 상속받지 않습니다. 그래서 에러를 뱉어냅니다.

자바 코드에서 선언되어 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환됩니다.

그리고 코드 내의 모든 제네릭 타입은 제거되어, 컴파일된 class 파일에는 어떠한 제네릭 타입도 포함되지 않게 됩니다.

제네릭을 사용하지 않는 코드와의 호환성을 유지하기 위해서입니다.

 

지금까지 generic에 대해 알아보았습니다.

728x90
반응형

'study > Java' 카테고리의 다른 글

클린코드(Clean code) 1장 - 좋은 코드와 나쁜 코드  (0) 2022.09.04
Java 힙 공간 에러 발생한 배치 성능개선후기  (0) 2022.08.22
Queue에 대해 알아보자  (0) 2021.08.28
Stack(push/pop)  (0) 2021.08.27
Hashmap / Treemap  (0) 2021.08.26

댓글