관리 메뉴

제뉴어리의 모든것

제네릭스(Generics)의 기본 개념 - 1 본문

JAVA

제네릭스(Generics)의 기본 개념 - 1

제뉴어리맨 2022. 7. 7. 00:00

제네릭스란?

컴파일시에 클래스나 메서드에 쓰인 타다양한 입들을 체크해 주는 기능이다.

제네릭(Generic)은 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미.

 

제네릭스란의 사용목적

타입의 안정성을 높이기위해. 라고 정의 되어있다.

근데 이 내용이 나한테는 크게 와닿지 않았다.

쉽게 생각해서 A라는 클래스는 B라는 데이터 타입의 변수들만 들어와야 클래스의 사용 목적에도 맞고 처리가 가능한것이 있을것이다. 그런데 이때, 뜬금없이 C라는 타입의 데이터 들어와서 클래스의 사용 목적에 맞지도 않고 처리가 불가능한 경우를 방지하기 위해서이다. 

 

제네릭스란의 장점

  • 타입의 안정성을 제공
  • 타입체크와 형변환이 필요 없으므로 코드가 간결해짐 

이런 장점들이 있는데, 차차 알아보자.

 

클래스에서의 제네릭스의 선언

 

  • 제네릭스 적용 전 소스
class Box <Object>{
    List<Object>elements = new LinkedList<Object>();


    public Box() {
    }

    public void put(Object element) {
        this.elements.add(element);
    }

    public Object get() {

        return elements.get(elements.size()-1);
    }
}

Box라는 클래스가 있다.

Box 클래스는 클래스 이름만으로 무언가를 담는 클래스라는걸 알 수 있다.

그런데 Box라는 클래스는 여러 용도로 쓰일 수 있다.

과일을 담는 박스, 장난감을 담는 박스.. 무엇이든 사용 가능할 것이다.

그래서 Box내에서 관리하는 요소(elemtents)의 타입을 Object로 정의해 주었다.

왜냐하면 Integer라던가 Fruit이라는 개발자가 만든 참조타입 등과 같이 특정 타입으로 지정을 해주면 

Integer를 담는 IntegerBox클래스 Fruit을 담는 Fruit클래스를 각각 만들어서 사용해주어야 한다.

그렇다면 이렇게 생각할 수 있다.

그럼 그냥 Object로 두면 되지.

그렇게 한다면 Box 클래스에서 get메서드로 요소를 꺼내서 쓸때마다 형변환을 하여야 할것이다.

그리고 

Box integerBox = new Box(); 와 같이 Integer만 관리하는 Box 객체를 만들려고 했는데,

여러 코드를 진행 하던 중, 아래와 같이 과일이란 객체가 실수로 들어가버렸다.

integerBox.put(new fruit());  //fruit이라는 개발자가 만든 과일클래스의 객체

이럴 경우 컴파일시 에러가 발생하지 않는다.

Object는 모든 클래스의 부모 클래스이기때문에 문법상 문제가 없기 때문이다.

그렇다면 put 메서드 안에 타입을 검사하는 조건문을 넣으면 되지 않나 싶을것이다.

그럴 경우 Box라는 클래스는 여러 타입을 다 담기 위해 Object라는 타입을 사용하였고,

그럴 경우, put메서드 안에 Integer가 들어왔는지 조건문을 넣어버리면

Box메서드는 Fruit을 담는 용도의 Box 클래스로는 만들 수가 없다. (사실 아예 없는것은 아니지만, 예를들어 무엇을 담을 클래스인지 최초 생성할때 구별할 수 있는 값을 넘겨주어서 할 수도 있지만, 비효율적이며 직관적이지도 않다)

클래스의 정의는 하나이기 때문이다.

그래서 제네릭스라는 기법을 사용한다.

 

  • 제네릭스 적용 후 소스
class Box <T>{
    List<T>elements = new LinkedList<T>();


    public Box() {
    }

    public void put(T element) {
        this.elements.add(element);
    }

    public T get() {

        return elements.get(elements.size()-1);
    }
}

 

클래스에 제네릭스를 적용한 모습이다.

클래스명 우측에 <> 안에 아직정해지지 않았다는 의미로 의미없는 "T"라는 기호를 넣었다.

저 T는 클래스의 객체 다음과 같이 생성을 할때 정해진다

 

클래스에서의 제네릭스의 사용

public class realTest {
    public static void main(String[] args) {
        Box<Fruit> box = new Box<Fruit>();
        box.put(new Fruit());
    }
}
class Fruit {
}

class Box <T>{
	:
    :
    :
    :
}

위에 코드를 보면 객체 생성시 <>를 사용하여 T가 무엇인지 정의하여 준다.

참고로 

Box<Fruit> box = new Box(); //가능

위와 같은 표현도 가능하다.

JDK1.7 부터 참조변수만으로도 추정이 가능하므로 생략 가능하다.

그러나 아래와 같은 경우는 불가능하다.

Box<Fruit> box = new Box<Integer>(); //에러
Box<Integer> box = new Box<Fruit>(); //에러

단순하게, 참조변수와 실제 객체 생성부분 에서의 제네릭 타입은 동일해야 한다.

 

제네릭스의 주의점

1. 제네릭 타입은 기본형은 불가하다

 

 

 

참조 : 

자바의 정석,

https://st-lab.tistory.com/153