> For the complete documentation index, see [llms.txt](https://docs.sysout.co.kr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sysout.co.kr/base-language/java/java-advanced/generic-type.md).

# 제네릭(Generic)

## 제네릭(Generic)

{% hint style="info" %}
제네릭(Generic) 프로그래밍은 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그래밍 방식이다.

출처 : [위키백과 - 제네릭 프로그래밍](https://ko.wikipedia.org/wiki/%EC%A0%9C%EB%84%A4%EB%A6%AD_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D)
{% endhint %}

위키백과의 설명처럼 **Generic**이란 데이터의 형식에 구애받지 않도록 일반화 하는 것을 말한다. 여기서 데이터의 형식을 일반화 한다는 것은 무슨 의미일까?

### 사례 : 택배 회사의 고민

> 택배 회사에서 의뢰받은 배송 물품을 어떻게 포장하는 것이 좋을까?
>
> *택배 회사는 사용자가 의뢰한 배송 물품을 파손되지 않도록 목적지까지 운송하는 역할을 수행한다. 이를 위해서 의뢰받은 물품을 포장해야 할 필요가 생기는데, 다양한 물품들을 그에 맞게 포장하려면 매우 많은 종류의 상자들이 필요할 것이다. 또한 종류별로 상자들을 만든다 하더라도 새로운 품목이 언제든지 등장할 수 있는 사정이기 때문에 고민을 하고 있다.*

우리는 이미 해결책을 알고 있다. 지금도 우리의 집으로 배송되는 물품들이 어떻게 오는지 알고 있기 때문이다. 결론부터 말하면 상품을 일일이 고려할 필요 없이 **일정한 크기의 상자**를 준비하여 배송품을 넣고 배송하면 된다. 상품이 들어가지 않으면 들어갈 만한 다른 규격의 상자에 넣으면 된다.

![이 상자에 종류와 관계 없이 물건을 넣으면 된다](/files/-MeyeZuD6DO7cUZociYp)

하지만 여기서 문제가 발생한다. 우리는 다양한 상품을 취급하고 있으며, 그중에는 파손 위험이 큰 유리나 가전제품들도 있을 것이다. 하지만 상자만 가지고는 이 제품이 어떤 내용물을 가지고 있는지 알기 어렵다. 상자에 어떠한 물건이 들어있던 우리는 상자로 인식하며, 특별한 표시가 없다면 내용물의 형태를 알기 어렵다는 것이다. 자바로 비유하면 형태를 알 수 없기 때문에 `Object`라고 생각할 수 밖에 없다는 것이다.

상자 안에 들어있는 물건들은 일반적으로 스티커를 이용하여 표시한다. 스티커에는 형태에 대한 매우 추상적인 정보가 있을 수도 있고, 구체적인 정보가 있을 수도 있다.

![유리제품임을 알리는 스티커](/files/-Meyg8Y2bapvGRfeY9_M)

![다양한 내용물 표시 스티커](/files/-MeygpokFOBF1zU0UNX2)

물건을 1개만 넣을 수 있는 택배상자는 다음과 같이 정의할 수 있다.

{% tabs %}
{% tab title="Box" %}
{% code title="Box.java" %}

```java
public class Box<E> {
	private E item;
	public void setItem(E item) {
		this.item = item;
	}
	public E getItem() {
		return this.item;
	}
}
```

{% endcode %}
{% endtab %}

{% tab title="GenericExample01" %}

```java
public class GenericExample01 {
    public static void main(String[] args){
        Box a = new Box();
        Box<String> b = new Box<String>();
        Box<String> c = new Box<>();
        Box<?> d = new Box<>();
    }
}
```

{% endtab %}
{% endtabs %}

`GenericExample01`에서 각각의 객체들의 내용물은 다음과 같이 설정된다.

* a는 Generic 형태를 지정하지 않았기 때문에 item 형태는은 Object로 설정된다.&#x20;
* b는 Generic 형태를 String으로 지정했기 때문에 item 형태는 String으로 설정된다.
* c는 b의 축약형 표현이며, 우측은 편의상 생략이 가능하다.
* d는 ?로 지정한 경우 명시적으로 Object라고 작성한것과 동일하게 설정된다.

![GenericExample01의 객체의 이해를 돕기 위한 그림](/files/-Mez9PRxEjeAeREl4z_C)

a, b, c, d는 다 같은 상자이지만 내용물의 형태가 다르기 때문에 동일한 형태로 인식되지 않는다. 또한  a는 명시적으로 **Generic** 형태가 작성되지 않았기 때문에 경고가 발생한다.

{% hint style="info" %}
만약 int와 같은 원시형(raw type)을 Generic으로 설정하고 싶다면 int가 아니라 Integer로 설정해야 한다. Generic은 참조형태만 설정할 수 있다.
{% endhint %}

다음 코드는 오류가 발생한다.

```java
Box<int> e = new Box<>();
```

원시형은 반복자로 사용할 수 없으며, 다음 코드 형태로 사용해야 한다. 이 부분에 대해서 상세한 설명은 [Java Language Specification(JLS) - 4.8. Raw Types](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8) 을 참고한다.

```java
Box<Integer> e = new Box<Integer>();
```

다음과 같이 객체의 우측을 생략하여 표현할 수 있다.

```java
Box<Integer> f = new Box<>();
```

이처럼 **Generic**을 클래스에 적용시켜 자료형을 생성 시 결정할 수 있도록 일반화할 수 있다.
