자바스터디 - 14주차

megaseunghan·2022년 8월 19일
0

자바스터디

목록 보기
14/15
post-thumbnail

목표

자바의 제네릭에 대해 학습하세요.

학습할 것 (필수)

  • 제네릭 사용법
  • 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
  • 제네릭 메소드 만들기
  • Erasure

제네릭이란

  • JAVA 5부터 새로 추가된 기능이다.
  • 객체의 타입을 파라미터화 해서 컴파일 시에 구체적인 타입이 결정되도록 한다.

장점

  1. 컴파일시 강한 타입 체크 : 컴파일 과정에서 타입이 결정되기 때문에 의도하지 않은 타입이 잘못 형변환되어 사용될 수 있는 문제를 막는다.
  2. 타입 변환을 제거 : 제네릭을 사용하지 않으면 불필요한 타입 변환을 하는데, 이는 성능에 악영향을 끼친다. 제네릭을 사용함으로써 이 과정을 생략할 수 있다. 또, 코드가 간결해진다.

제네릭 사용법

제네릭 타입은 클래스와 메서드에 사용할 수 있다. 선언시 클래스 또는 메서드 뒤에 <>이 붙고 <>사이에는 타입 파라미터가 위치한다.

선언

  • 제네릭을 사용하지 않았을 때
public class NonGenericsClass {
    Object item;
    
    void setItem(Object item) {
        this.item = item;
	}
    
    Object getItem() {
        return item;
    }
}
  • 제네릭을 사용할 때
public class GenericsClass<T> {
    T item;
    
    void setItem(T item) {
        this.item = item;
    }
    
    T getItem() {
        return item;
    }
}
  • 사용 예제
public class GenericsClass<T> {
    ...
  public static void main(String[] args) {
        GenericsClass<Integer> integerGenerics = new GenericsClass<>();
        integerGenerics.setItem(3);
        Integer item = integerGenerics.getItem();
        System.out.println(item);
        
        GenericsClass<String> stringGenerics = new GenericsClass<>();
        stringGenerics.setItem("hi");
        String item = stringGenerics.getItem();
        System.out.println(item);
    }
}

타입 파라미터에 Integer, String을 넣어봤다. 컴파일 시 클래스 타입이 달라지는 것을 확인할 수 있다.

제네릭 주요 개념(바운디드 타입, 와일드 카드)

바운디드 타입

제네릭으로 사용되는 파라미터 타입을 제한할 수 있는 것을 말한다.

예를 들어 숫자를 연산하는 제네릭 메소에는 Number타입과 그 하위 타입의 인스턴스만 가져야 한다. 이것이 바운디드 타입이 필요한 이유다.

바운디드 타입은 extends 키워드를 붙이고 상위 타입을 명시하면 되는데 이 때 extends는 상속이 아닌 종류의 의미로 사용된다.

public <T extends 상위타입> 리턴타입 메소드명(매개변수, ...) {
    ...
}
  • 타입 파라미터에 저장되는 구체적인 타입은 상위 타입이거나 상위 타입의 하위 || 구현 클래스만 가능하다.
  • 메서드의 중괄호 안에서 타입 파라미터의 변수로 사용 가능한 것은 상위 타입의 멤버로 제한된다.

와일드 카드

일반적으로 코드에서의 ?를 와일드카드라고 부른다. 제네릭 타입을 매개변수나 리턴타입으로 사용할 때 바운디드 타입과 마찬가지로 타입 파라미터를 제한할 목적으로 사용된다.

와일드 카드를 사용하는 경우는 상위, 하위 타입으로의 변환이 가능한 것을 제한하기 위함이다.

와일드 카드 형태

  1. 제네릭타입<?> : 제한 없음

    • 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스가 대입될 수 있다.
  2. 제네릭타입<? extends 상위타입> : UpperBounded WildCards

    • 타입 파라미터를 대치하는 구체적인 타입으로 하위 타입만 올 수 있다.
  3. 제네릭타입<? super 하위타입> : LowerBounded WildCards

    • 타입 파라미터를 대치하는 구체적인 타입으로 상위 타입만 올 수 있다.

제네릭 메서드 만들기

제네릭 메서드란

매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메서드를 말한다.

선언 방법

  • 리턴 타입 앞에 <>를 추가하고 타입 파라미터를 기술한다.
  • 타입 파라미터를 리턴타입과 매개변수에 사용한다.
public <타입 파라미터> 리턴타입 메소드명(매개변수, ...) {
    ...
}
  • 클래스의 타입 파라미터와 메소드의 타입 파라미터의 이름이 같다면?
    - 메소드에 대입되는 타입 파라미터는 클래스에 정의된 타입 파라미터와는 별개이다. 같은 문자 T를 대입해도 서로 다르다.

Erasure

참조

제네릭은 제네릭 도입 전 코드와의 호환성 유지를 위한 작업을 동시에 진행했다. 따라서 코드의 호환성을 위해 erasure 방식을 사용한다.

제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 Raw type이라고 한다. Raw type을 사용하는 것

erasure 방식은 컴파일 타입에만 타입 제약 조건을 정의하고, 런타임에서는 타입을 제거한다.

  • 타입 소거 전
public class Example<T> {
    public void method(T type) {
        System.out.println(type.toString());
    }   
}
  • 타입 소거 후
public class Example {
    public void method(Object type) {
        System.out.println(type.toString());
    }
}

위처럼 unbounded type에서는 Object로 바뀌게 된다.

그럼 bounded type은 어떻게 바뀔까?

  • 타입 소거 전
public class Example<T extends Comparable<T>> {
    public void method(T type) {
        System.out.println(type.toString());
    }
}
  • 타입 소거 후
public class Example {
    public void method(Comparable type) {
        System.out.println(type.toString());
    }
}

<T extends Comparable>와 같이 제한된 제네릭을 걸어두면 제한시킨 타입인 Comparable 타입으로 변환이 된다.

0개의 댓글