hayu's 개발 일지

99클럽 코테 스터디 18일차 TIL + 제네릭(Generic) 본문

기술/java

99클럽 코테 스터디 18일차 TIL + 제네릭(Generic)

hayu00 2024. 6. 7. 21:02

학습 키워드

- 제네릭(Generic)

 

공부한 내용

제네릭(Generic)

  • 자바에서 제네릭은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미한다.

-> 자바에서 제네릭은 generic 타입 및 메소드를 정의하고 사용 할 수 있는 언어적 특성이다.

  • 객체 별로 다른 타입의 자료가 저장될 수 있도록 한다.
ArrayList<String> list = new ArrayList<>();
List<Integer> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
  • 이 예시 코드에서 꺾쇠 괄호가 제네릭이다. 괄호 안에는 타입명을 기재한다. 이렇게 하면 리스트 클래스의 자료형의 타입은 String 타입으로 지정되어 문자열 데이터만 리스트에 적재될 수 있게 된다.
  • 제네릭은 배열의 타입을 지정하듯이 리스트 자료형과 같은 컬렉션 클래스나 메서드에서 사용할 내부 데이터 타입(type)을 파라미터(parameter) 주듯이 외부에서 지정하는 즉, 타입을 변수화 한 기능이다.

→ 파라미터 타입이나 리턴 타입에 대한 정의를 외부로 미룬다. → 타입에 대해 유연성과 안정성을 확보한다. → 런타임 환경에 아무런 영향이 없는 컴파일 시점의 전처리 기술

  • 변수를 선언할 때 변수의 타입을 지정해주듯이 제네릭은 객체(Object)의 타입을 지정해주는 것이라고 보면 된다.

제네릭 사용 이유

⇒ 타입을 유연하게 처리하며, 잘못된 타입 사용으로 발생할 수 있는 런타임 타입 에러를 컴파일 과정에서 검출한다.

  • 자바 컴파일러는 코드에서 잘못 사용된 타입 때문에 발생하는 문제점을 제거하기 위해 제네릭 코드에 대해 강한 타입 체크를 진행한다. 실행 시 타입 에러가 나는 것 보다는 컴파일 시에 미리 타입을 강하게 체크해서 에서를 사전에 방지하는 것이 좋다.
  • 또한 제네릭 코드를 사용하면 타입을 국한하기 때문에 요소를 찾아올 때 타입 변환을 할 필요가 없어 프로그램 성능이 향상되는 효과를 얻을 수 있다.

제네릭 사용법

  • 클래스, 인터페이스 또는 메서드에 선언할 수 있다.
  • 동시에 여러 타입을 선언할 수 있다.
  • 와일드 카드를 이용하여 타입에 대하여 유연한 처리를 가능하게 한다.
  • 제네릭 선언 및 정의 시에 타입의 상속 관계를 지정할 수 있다.
  • 제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다. 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 <> 부호가 붙고 사이에 타입 파라미터가 위치한다.
public class MyClass<T>
public interface MyInterface<T>
  • 타입 파라미터는 정해진 규칙은 없지만 일반적으로 대문자 알파벳 한글자로 표현한다.

자주 사용하는 타입인자

타입인자 설명

<T> Type
<E> Element
<K> Key
<N> Number
<V> Value
<R> Result

제네릭 타입의 매개 변수

  • 제네릭은 <>꺾쇠 괄호 키워드를 사용하는데 이를 다이아몬드 연산자라고 한다. 그리고 이 꺾쇠 괄호 안에 식별자 기호를 지정함으로써 파라미터화 할 수 있다.
  • 메서드가 매개 변수를 받아 사용하는 것과 비슷하여 제네릭의 타입 매개 변수(parameter) / 타입 변수라고 한다.

타입 파라미터 정의

  • 이 타입 매개변수는 제네릭을 이용한 클래스나 메서드를 설계할 때 사용된다.
  • 예를 들어 클래스명 옆에 <T> 기호로 제네릭을 붙이면 해당 클래스 내부에서 식별자 기호 T 를 클래스 필드와 메서드의 매개 변수의 타입으로 지정되어 있다.
class FruitBox<T> {
    List<T> fruits = new ArrayList<>();

    public void add(T fruit) {
        fruits.add(fruit);
    }
}
  • 제네릭 클래스를 만들고 이를 인스턴스화 할 때 파라미터를 지정해서 보내는 것 처럼 생성 코드에서 꺾쇠 괄호 안에 지정해주고 싶은 타입명을 할당해주면, 제네릭 클래스 선언문 부분으로 가서 타입 파라미터 T가 지정된 타입으로 모두 변환되어 클래스의 타입이 지정되는 것이다.
// 제네릭 타입 매개변수에 정수 타입을 할당
FruitBox<Integer> intBox = new FruitBox<>(); 

// 제네릭 타입 매개변수에 실수 타입을 할당
FruitBox<Double> intBox = new FruitBox<>(); 

// 제네릭 타입 매개변수에 문자열 타입을 할당
FruitBox<String> intBox = new FruitBox<>(); 

// 클래스도 넣어줄 수 있다. (Apple 클래스가 있다고 가정)
FruitBox<Apple> intBox = new FruitBox<Apple>();

타입 파라미터 생략

  • 제네릭 객체를 사용하는 문법 형태를 보면 양쪽 두 군데에 꺾쇠 괄호 제네릭 타입을 지정함을 볼 수 있다. 하지만 맨 앞에서 클래스명과 함께 타입을 지정해주었는데 굳이 생성자까지 제네릭을 지정해 줄 필요가 없다.(중복)
  • 따라서 jdk 1.7 버전 이후부터,  new 생성자 부분의 제네릭 타입을 생략할 수 있게 되었다. 제네릭 나름대로 타입 추론을 해서 생략 된 곳을 넣어주기 때문에 문제가 없는 것이다.
FruitBox<Apple> intBox = new FruitBox<Apple>();

// 다음과 같이 new 생성자 부분의 제네릭의 타입 매개변수는 생략할 수 있다.
FruitBox<Apple> intBox = new FruitBox<>();

 

회고

발생한 문제

- 자료구조를 공부하다가 제네릭에 대한 이야기가 나와서 공부를 하게 되었다.

 

해결 방법

- 제네릭에 대해 공부하고 정리했다.

 

알게된 내용

- 제네릭의 사용이유와 사용법에 대해 공부하게 되었다.

 

 

 

참고 자료

- https://velog.io/@heetaeheo/%EC%9E%90%EB%B0%94-%EC%A0%9C%EB%84%A4%EB%A6%AD%EC%9D%B4%EB%9E%80

- https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%A0%9C%EB%84%A4%EB%A6%ADGenerics-%EA%B0%9C%EB%85%90-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0