본문 바로가기
Language/Java

[Java] 자바기초 - 제네릭(Generic)

by J4J 2020. 12. 28.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 제네릭에 대해 적어보는 시간을 가져보려고 합니다.

 

 

제네릭이란?

 

자바로 프로그래밍된 코드들을 보시면 인스턴스를 생성할 때 꺽쇠("<>")들로 표현된 코드들을 보신 경험이 있을 것인데 이런 코드들이 모두 제네릭이 적용된 코드들입니다.

 

제네릭이라고 하는 것은 클래스 내부에서 사용될 변수들의 타입을 지정해주는 역할을 수행합니다.

 

다른 표현으로는 담고 싶은 데이터 타입을 정해 다른 데이터 타입은 담을 수 없도록 해준다 라고 말할 수 있습니다.

 

제네릭을 일상생활에서 비유하자면 뷔페에 갈 때 이쪽은 한식코너, 저쪽은 양식코너와 같이 분류하는 것이라고 생각하면 됩니다.

 

제네릭을 사용하는 이유는 원치 않은 데이터 타입을 담을 때 컴파일 과정에서 발견하기 위해 사용됩니다. (코드 작성 단계에서 발견)

 

예를 들어 정수 값만 리스트에 담으려고 하는데 사람은 누구나 실수를 하기 때문에 실수 값도 리스트에 담을 수도 있습니다.

 

담는 과정에서는 문제가 되지 않겠지만 이후에 리스트가 사용되는 메서드 등에서 정수 값에 맞는 코드들을 작성을 해놨는데 갑자기 실수로 집어넣은 실수 값이 나오면 어떻게 될까요?

 

당연히 에러가 발생하거나 잘못된 결과가 나오게 되는데 에러가 발생되면 에러 나는 부분을 찾아 수정하면 되지만 결과만 잘못 나올 경우는 잘못된 부분을 찾기가 매우 어려운 상황이 발생합니다.

 

이런 상황을 만들지 않기 위해 제네릭을 사용하여 컴파일 단계에서 자동으로 에러로 잡아줌으로 써 개발할 때 실수를 줄이게 해줍니다.

 

 

사용 방법

 

제네릭을 사용하는 방법은 꺽쇠 사이에 담고 싶은 데이터 타입을 넣어주면 끝입니다.

 

하지만 여기서 주의하셔야 될 점은 모든 데이터 타입을 담을 수 있는 것이 아니라 참조형 데이터 타입만 담을 수가 있습니다.

 

다른 말로는 int, double, boolean 등의 자료형들은 사용할 수 없다는 의미이기도 합니다.

 

어? 위에선 정수와 실수로 예시를 들으셨는데 정수나 실수는 담지 못하는 것일까요?

 

이 대답은 No입니다.

 

자료형들을 객체화시켜 클래스로 표현되도록 해주는 것이 있는데 바로 Wrapper Class라는 것입니다.

 ※ Wrapper Class에 대해 모른다면? [Java] 자바기초 - Wrapper Class

 

Wrapper Class를 사용한다면 정수, 실수, 논리형 모두 사용이 가능합니다.

 

코드로 보여드리겠습니다.

 

package generic;

import java.util.ArrayList;
import java.util.List;

public class Save<T> { // T의 데이터 타입을 인스턴스를 생성할 때 지정
	
	List<T> numbers;
	
	public Save() {
		numbers = new ArrayList<T>();
	}
	
	public void add(T number) {
		numbers.add(number);
	}
	
	public int sum() { // 데이터가 모두 정수일 때 합 구하기
		int total = 0;
		
		for(int i=0; i<numbers.size(); i++) {
			total = total + (int)numbers.get(i);
		}
		
		return total;
	}
}

 

package generic;

public class Main {
	public static void main(String[] args) {
		Save<Integer> saveInteger = new Save<Integer>(); // T에 해당하는 변수 타입을 Integer로 선언
		Save<Double> saveDouble = new Save<Double>(); // T에 해당하는 변수 타입을 Double로 선언
		Save saveNumber = new Save(); // T에 타입을 담지 않을 경우
		
		saveInteger.add(3); // 가능
		saveInteger.add(3.5); // Error
		saveNumber.add(3); // 가능
		
		saveDouble.add(3); // Error
		saveDouble.add(3.5); // 가능
		saveNumber.add(3.5); // 가능
		
		System.out.println(saveNumber.sum()); // 실행 시 Error
	}
}

 

 

위의 코드르 보시면 Save 클래스에는 T라는 임의의 데이터 타입을 담을 수 있도록 설정하여 리스트에 T변수 데이터를 담는 메서드와 정수 값들의 합만 구할 수 있는 메서드를 작성했습니다. (T뿐만 아니라 자바에서 사용되는 키워드를 제외하고 모두 사용 가능)

 

그리고 Main 클래스에서는 T를 Integer로 변경시킨 것과 Double로 변경시킨 것 그리고 T에 변수를 담지 않은 인스턴스를 각각 생성하고 각각 정수와 실수 데이터를 담고 모두 합한 값을 출력해 봤습니다.

 

정수로 예를 들면 add라는 메서드는 public void add(Integer number) { ... }로 변경이 되었기 때문에 3이라는 값을 넣을 순 있지만 3.5라는 값을 넣을 경우 에러가 나는 것을 확인할 수 있습니다.

 

그리고 T에 타입을 담지 않을 경우는 정수와 실수 구분 없이 모두 담을 수 있지만 담은 데이터들의 합을 구하기 위해 실행시키면 에러가 발생되는 것을 확인할 수 있습니다.

 

왜냐하면 3.5라는 값을 넣으면 자료형의 double이 아닌 Wrapper Class의 Double이 되어 int로 캐스팅이 될 수 없기 때문입니다. (자료형의 double일 경우는 int로 캐스팅 가능)

 

이와 같은 상황이 발생할 때 간단한 코드면 금방 해결이 되지만 코드 양이 많아질수록 더 많은 시간이 필요하게 되는데 제네릭을 통해 발생되지 않아도 되는 상황을 제거함으로 써 효율적으로 코드 작성을 할 수 있습니다.

 

 

정리

 

제네릭은 데이터 타입을 구분하기 위해 사용
뷔페에서 한식코너에 한식 음식, 양식 코너에 양식 음식만 두는 것과 동일
타입의 명칭은 자바에서 사용되는 키워드를 제외하고 모두 사용 가능

 

 

 

이상으로 제네릭에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

728x90
반응형

댓글