본문 바로가기

Language/Java

[Java] 재네릭(Generic)이란?

재네릭(Generic)

재네릭은 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능이다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄일 수 있다.

타입 안정성을 높인다는 것은 의도하지 않은 타입의 객체가 저장되는 것을 막고, 저장된 객체를 꺼내올 때 원래의 타입과 다른 타입으로 잘못 형변환되어 발생할 수 있는 오류를 줄여준다는 뜻이다.

 

재네릭의 장점
1. 타입 안정성을 제공한다.
2. 타입체크와 형변환을 생략할 수 있어 코드가 간결해 진다.

재네릭 이전의 코드

재네릭 이전의 코드에 대해서 살펴보자.

먼저 무엇이든 저장하고 꺼낼 수 있는 상자를 준비해 준다.

 

class Apple{
	public String toString() {
		return "I am an apple.";
	}
}

class Orange{
	public String toString() {
		return "I am an orange.";
	}
}

class Box{ //무엇이든 저장하고 꺼낼 수 있는 상자
	private Object ob;
	
	public void set(Object o) {
		ob = o;
	}
	public Object get() {
		return ob;
	}
}

 

 

각각의 상자에 사과와 오렌지를 담았지만 실제 이 상자들은 object 형을 참조하기 때문에  명시적인 형변환을 필요로 한다. 그리고 이것은 컴파일러의 오류 발견 가능성을 낮추는 결과로 이어진다. (코드의 안정성이 떨어짐) 

 

public class Main {
	public static void main(String[] args){
		Box aBox = new Box();   // 상자 생성
		Box oBox = new Box();   // 상자 생성
		
		aBox.set(new Apple());  // 상자에 사과를 담는다.
		oBox.set(new Orange()); // 상자에 오렌지를 담는다.
		
		Apple ap = (Apple)aBox.get();    // 상자에서 사과를 꺼낸다.
		Orange og = (Orange)oBox.get();  // 상자에서 오렌지를 꺼낸다.
		
		System.out.println(ap);
		System.out.println(og);
	}
}

 

 

더욱더 큰 문제는 아래처럼 꺼내는 과정에서 바로 println 메서드를 호출했을 때 어떠한 오류도 발생하지 않기 때문에 프로그래머가 자신이 무엇을 실수했는지 조차 알수없다는 것이다.

 

public class Main {
	public static void main(String[] args){
		Box aBox = new Box();  
		Box oBox = new Box();  
		
                //프로그래머의 실수
                //사과와 오렌지가 아닌 문자열을 담았다
		aBox.set("Apple");  
		oBox.set("Orange"); 
		
		System.out.println(aBox.get()); // Apple
		System.out.println(oBox.get()); // Orange
	}
}

 


재네릭 이후의 코드

Box 클래스를 재네릭화 시켜보겠다. 

아래의 의미는 인스턴스 생성시에 T의 값을 필요에 맞게 결정하겠다는 의미이다.

 

class Box<T>{
	private T ob;
	
	public void set(T o) {
		ob = o;
	}
	public T get() {
		return ob;
	}
}

 

 

이와 같이 타입을 미리 지정해 주었기 때문에 상자에 다른 타입의 물건을 담으려 할 때 에러가 발생한다.

이렇게 재네릭을 사용하면 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있고 따로 타입을 체크하고 변화해 줄 필요가 없다.

 

	public static void main(String[] args){
		Box<Apple> aBox = new Box<Apple>();    
		// T를 Apple로 결정하여 인스턴스 생성
		// 따라서 Apple 또는 Apple을 상속하는 하위 클래스의 인스턴스 저장가능
		
		Box<Orange> oBox = new Box<Orange>();   
		// T를 Orange로 결정하여 인스턴스 생성
		// 따라서 Orange 또는 Orange을 상속하는 하위 클래스의 인스턴스 저장가능
		
		aBox.set(new Apple());  // 상자에 사과를 담는다.
		oBox.set(new Orange()); // 상자에 오렌지를 담는다.
        
                //aBox.set("Apple");   // 에러방생
		//oBox.set("Orange");  // 에러발생
		
		Apple ap = aBox.get();    // 사과를 꺼내는데 형 변환 하지 않는다.
		Orange og = oBox.get();   // 오렌지를 꺼내는데 형 변환 하지 않는다.
		
		System.out.println(ap);
		System.out.println(og);
	}

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

[Java] 객체지향프로그래밍(OOP)란?  (0) 2022.09.15
[Java] 형변환(캐스팅, casting)  (0) 2022.09.14
[Java] 자바의 명명규칙  (0) 2022.09.13
[Java] JVM 메모리 구조  (0) 2022.09.12
[Java] Queue(큐) 클래스 정리  (0) 2022.09.08