제네릭 프로그래밍은 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터
타입들을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그래밍 방식이다.
다형성의 특징을 가지고 있고, 결국 편하려고 만들어졌다.
제네릭의 필요성
제네릭은 클래스나 메서드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정한다. (강한 타입체크)
1. 잘못된 타입이 들어오는 것을 컴파일 단계에서 방지가 가능하다.
2. 실행 시 타입 검사나 타입 변환과 같은 번거로운 작업을 생략할 수 있게 된다.
//제네릭 X
ArrayList list = new ArrayList();
list.add("연필");
String temp = (String) list.get(0); //타입변환이 필요함
//제네릭 O
ArrayList<String> list2 = new ArrayList();
list2.add("연필");
temp = list2.get(0); //타입변환이 필요없음
과거에는 다양한 데이터 타입을 담기 위해서 최상위 클래스인 Object 타입으로 선언하여 사용했다.
데이터를 저장할 때는 상관이 없지만, 가져올 때는 각 객체의 타입에 맞도록 캐스팅을 해줘야 한다.
이때 실수로 잘못된 캐스팅을 해서 ClassCastException 에러가 발생하고 프로그램이
종료될 수 있는 문제점이 있다. (약한 타입체크)
이러한 문제점을 해결할 수 있도록 JDK1.5부터는 제네릭이 도입되었다.
자주 표기하는 제네릭 타입 변수
제네릭 타입 변수명은 일반적으로 영문 대문자 한 글자를 사용한다.
물론 이것은 관례적으로 자주 사용되는 변수 이름이고, 다른 이름을 넣어도 무방하다.
하지만 굳이 특별한 이유가 없다면 통상적인 이름을 사용하는 것이 좋다.
제네릭 클래스 & 인터페이스
1. 정의하기
public class ClassName <T> { ... }
public Interface InterfaceName <T> { ... }
public class ClassName <K, V> { ... } //여러 개의 타입 변수도 줄 수 있다.
2. 제네릭 클래스의 객체 생성
//public static void main(String[] args) {
ClassName<String> a = new ClassName<String>();
ClassName<Integer, String> b = new ClassName<Integer, String>();
//사용자가 정의한 클래스도 제네릭 타입으로 지정해 줄 수 있다.
ClassName<Student> a = new ClassName<Student>();
객체를 생성할 때는 제네릭 타입 변수에 실제 데이터 타입을 넣어줘야 한다.
여기서 주의해야할 점이 있다. 타입 변수에 기본 타입을 넣을 수 없다. 참조 타입만 가능하다.
제네릭 메서드
클래스 전체를 제네릭으로 선언하는 대신, 특정 메서드만 제네릭으로 선언할 수도 있다.
리턴 타입 또는 입력매개변수의 타입을 제네릭 타입 변수로 선언한다.
제네릭 클래스는 컴파일시에 실제 타입을 지정하는 것과 달리
제네릭 메서드는 호출되는 시점에 실제 제네릭 타입을 지정한다.
// 제네릭 메서드는 4종류가 존재한다.
// 1. 제네릭 타입 변수명이 1개
public <T> T method1(T t) {...}
// 2. 제네릭 타입 변수명이 2개
public <T, V> T method2(T t, V v) {...}
// 3. 매개변수에만 제네릭
public <T> T method3(T t) {...}
// 4. 리턴 타입에만 제네릭
public <T> T method4(int a) {...}
//public static void main(Stirng[] args){
A a = new A(); // 제네릭 메서드를 포함한 클래스
// 제네릭 타입 지정
a.<String>method1("안녕");
// 제네릭 타입 유추 (타입을 유추할 수 있을 때 제네릭 타입 지정 생략 가능)
a.method1("안녕");
오토 박싱 & 오토 언박싱
위에서 제네릭 타입 변수에 기본 타입을 넣을 수 없다고 했다.
자바는 자동으로 기본 타입을 참조 타입으로 바꿔주는 기능이 존재한다.
자바의 오토 박싱에 대해서 간단히 알아보자.
// JDK 1.5 버전 이전
ArrayList<Integer> arr = new ArrayList<>();
arr.add(new Integer(10));
arr.add(new Integer(20));
arr.add(new Integer(30));
// JDK 1.5 버전 이후
ArrayList<Integer> arr2 = new ArrayList<>();
arr.add(10);
arr.add(20);
arr.add(30);
JDK 1.5버전 부터는 오토 박싱 & 오토 언박싱을 지원한다.
예를들면 기본타입인 int를 Wrapper 클래스인 Integer클래스로
자동으로 만들어 주는 기능이 오토 박싱이다. 그 반대는 오토 언박싱이다.
편의성을 위해 제공해주고 있지만 내부적으로 추가적인 연산이 들어가게 되어 성능이 떨어진다.
따라서, 오토 박싱&언박싱이 일어나지 않도록 동일한 타입 연산이 이루어지도록 구현하자.
제네릭에 대해서 최대한 간단하게 적어보았다.
글이 길어지기 때문에 제네릭 메서드의 타입 범위 제한, 제네릭의 상속 등의 내용은 생략했다.
사실 제네릭은 컬렉션을 사용한 자료구조를 구현할 때 꼭 알아야 하는 부분이다.
컬렉션은 기본적으로 전부 제네릭 타입으로 지정되어 있기 때문이다.
다음 포스팅은 컬렉션을 활용한 제네릭 타입 자료구조에 대해 알아보겠다 !
참고 문헌 : Do it! 자바 완전정복
http://www.tcpschool.com/java/java_generic_concept
이미지출처
'Java > 자바 이론' 카테고리의 다른 글
[Java] 자바 두 개의 스택(Stack)으로 큐(Queue) 구현하기 (0) | 2022.07.17 |
---|---|
[Java] 자바 객체 정렬 Comparable과 Comparator의 이해 (0) | 2022.07.09 |
[Java] 자바 컬렉션(Collection) 프레임워크란? (0) | 2022.07.06 |
[Java] 자바 쓰레드(Thread) & 동기화 (0) | 2022.07.06 |
[Java] 자바 내부 클래스 4종류 (Inner Class) (0) | 2022.07.05 |