이 글에서는 Java Generic에 대해서 살펴보도록 하겠습니다.
1. Java Generic(자바 제네릭) 이란?
Java에서 Generic은 다양한 자료형을 지원하기 위한 기능입니다. Generic을 사용하면 클래스 또는 메소드에서 사용되는 자료형을 선언할 수 있으며, 이렇게 선언된 자료형은 클래스 또는 메소드가 실행될 때 구체적인 자료형으로 대체됩니다.
2. Java Generic(자바 제네릭)의 장점
Java Generic은 다음과 같은 이점을 제공합니다.
- 코드의 재사용성을 높입니다.
- Generic을 사용하면 여러 자료형에 대해 동일한 코드를 작성할 수 있습니다. 예를 들어, LinkedList 클래스는 Generic을 사용하여 다양한 자료형을 저장할 수 있습니다.
- 코드의 가독성을 높입니다.
- Generic을 사용하면 코드의 의도를 명확하게 표현할 수 있습니다. 예를 들어, ArrayList<String>은 문자열만을 저장하는 ArrayList임을 명시적으로 나타냅니다.
- 타입 안전성을 보장합니다.
- Generic을 사용하면 컴파일 시간에 타입 체크를 수행하여 타입 안전성을 보장합니다. 이로 인해 런타임에 타입 에러가 발생할 가능성을 줄일 수 있습니다.
Generic은 클래스와 메소드에서 모두 사용할 수 있습니다. 클래스에서 Generic을 사용할 때는 클래스 이름 뒤에 <T>와 같은 형식으로 Generic 파라미터를 선언합니다. 메소드에서 Generic을 사용할 때는 메소드 이름 뒤에 <T>와 같은 형식으로 Generic 파라미터를 선언합니다.
3. Java Generic(자바 제네릭) 사용 예제
이번 단락에서는 Java Generic을 사용한 예를 가지고 설명을 해 보도록 하겠습니다.
3.1 LinkedList<T> 예제
예를 들어, 다음과 같은 간단한 LinkedList 클래스를 생각해보겠습니다.
public class LinkedList<T> {
private Node<T> head;
public void add(T data) {
// ...
}
// ...
위의 LinkedList 클래스에서 T는 Generic 파라미터입니다. 이 클래스는 다양한 자료형을 저장할 수 있는 LinkedList를 제공합니다. add() 메소드는 T 타입의 데이터를 추가하는 메소드입니다. 메소드에서 Generic을 사용할 때는 파라미터와 리턴 타입 앞에도 Generic 파라미터를 선언할 수 있습니다.3.2 Generic 타입을 이용한 추상화와 구현 예제
다음과 같은 인터페이스를 만들어보겠습니다.
public interface Stack<T> {
void push(T element);
T pop();
T peek();
boolean isEmpty();
}
위의 인터페이스에서 T는 Generic 파라미터입니다. Stack 인터페이스는 push(), pop(), peek(), isEmpty() 메소드를 제공합니다. T 타입의 element를 추가하는 push() 메소드와 T 타입의 element를 제거하고 반환하는 pop() 메소드, T 타입의 element를 반환하는 엿보기 peek() 메소드, 스택이 비어 있는지 확인하는 isEmpty() 메소드가 포함되어 있습니다.이제 Stack 인터페이스를 구현하는 클래스를 만들어보겠습니다.
public class ArrayStack<T> implements Stack<T> { private T[] elements; private int top; public ArrayStack(int capacity) { elements = (T[]) new Object[capacity]; top = -1; } public void push(T element) { elements[++top] = element; } public T pop() { if (isEmpty()) { throw new EmptyStackException(); } T element = elements[top]; elements[top--] = null; return element; } public T peek() { if (isEmpty()) { throw new EmptyStackException(); } return elements[top]; } public boolean isEmpty() { return top == -1; } }
위의 ArrayStack 클래스에서 T는 Generic 파라미터입니다. 이 클래스는 Stack 인터페이스를 구현하며, T 타입의 element를 저장하는 T[] 배열과 top 인덱스를 포함합니다. 즉, 스택을 Array를 이용하여 구현한 구현체 클래스입니다. 그래서, 이름을 ArrayStack으로 지었습니다.
push() 메소드는 T 타입의 element를 배열에 추가하고 top을 증가시킵니다. pop() 메소드는 배열에서 T 타입의 element를 제거하고 반환하며, peek() 메소드는 배열에서 T 타입의 element를 반환합니다. 하지만, toe을 바꾸지는 않습니다. isEmpty() 메소드는 스택이 비어 있는지 확인합니다.
이제 다음과 같은 예제 코드를 이용하여 Stack 인터페이스와 ArrayStack 클래스를 사용해보겠습니다.
Stack<Integer> stack = new ArrayStack<>(10); stack.push(1); stack.push(2); stack.push(3); System.out.println(stack.pop()); // 3 System.out.println(stack.peek()); // 2 System.out.println(stack.pop()); // 2 System.out.println(stack.pop()); // 1 System.out.println(stack.isEmpty()); // true
위의 코드에서는 ArrayStack 클래스를 이용하여 Stack 인터페이스를 구현하고, push(), pop(), peek(), isEmpty() 메소드를 호출하여 스택을 조작합니다. Generic 타입을 이용하여 Stack 인터페이스와 ArrayStack 클래스를 추상화하고 구현함으로써, 다양한 타입의 스택을 사용할 수 있습니다.
3.3 제네릭 인터페이스를 구현하여 enum 타입을 구현한 예
다음은 제네릭 인터페이스를 이용하여 enum 타입을 구현한 예제입니다.
public interface MyEnum<T> { T getValue(); } public enum Color implements MyEnum<String> { RED("FF0000"), GREEN("00FF00"), BLUE("0000FF"); private final String value; Color(String value) { this.value = value; } public String getValue() { return value; } }
위 예제에서는, MyEnum이라는 제네릭 인터페이스를 정의하였습니다. MyEnum 인터페이스는 getValue() 메소드를 선언하며, 이는 제네릭 타입 T를 반환합니다.
그리고 Color라는 enum 타입을 선언하였습니다. Color enum 타입은 MyEnum 인터페이스를 구현하였으며, 이를 위해 String 타입의 값을 각 항목에 대해 정의하였습니다.
Color enum 타입의 생성자는 String 타입의 값을 받으며, 이는 Color의 값(value)을 나타냅니다. Color enum 타입은 MyEnum 인터페이스의 getValue() 메소드를 구현하고 있으며, 이 메소드는 Color의 값을 반환합니다.
이렇게 제네릭 인터페이스를 구현하면, 다양한 타입의 값을 다루는 enum 타입을 만들 수 있습니다. 예를 들어, MyEnum 인터페이스의 타입 매개변수를 Integer로 바꾸어서, 값으로 숫자를 다루는 enum 타입을 만들 수도 있습니다.
이번 포스팅에서는 자바 제네릭을 이용하여 다양하게 활용할 수 있는 예제를 알아보았습니다.
잘못된 점이나 문의 사항 있으시면 댓글 달아주시면 감사하겠습니다.
긴 글 읽어 주셔서 감사합니다.