티스토리 뷰

728x90
반응형

목표

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

 

스터디 목차

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

 

1. 제네릭 사용법

 

제네릭 이란?

자바에서 제네릭(generic)이란 데이터의 타입(data type)을 일반화(generalize)하는 것을 의미한다.

제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 지정하는 방법이다.

컴파일시에 미리 타입검사를 수행하면 다음과 같은 장점이 있다.

 

  • 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있다.
  • 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.

 

JDK 1.5 이전에서는 여러 타입을 사용하는 대부분의 클래스나 메소드에서 인수나 반환값으로 Object 타입을 사용했다.

하지만 이 경우에는 반환된 Object 객체를 다시 원하는 타입으로 타입 변환해야 하며, 이때 오류가 발생할 가능성도 있다.

도입된 제네릭을 사용하면 컴파일 시에 미리 타입이 정해지므로, 타입 검사나 타입 변환과 같은 번거로운 작업을 생략할 수 있게된다.

 

제네릭 사용법

자바에서 제네릭 타입은 타입을 피라미터로 가지는 클래스와 인터페이스를 말한다. 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 < > 부호가 붙고 사이에 타입 파라미터가 위치한다.

 

public class Main{
    public static void main(String[] args)
    {
        TestGeneric<String> stringType = new TestGeneric<String>();
        TestGeneric<Integer> integerType = new TestGeneric<Integer>();

        stringType.sample = "Hello";
        integerType.sample = 1;

        stringType.showYourType();
        integerType.showYourType();
    }
    public static class TestGeneric<T>
    {
        public T sample;

        public void showYourType()
        {
            if(sample instanceof Integer)
                System.out.println("Integer 타입이군요!!");
            else if(sample instanceof String)
                System.out.println("String 타입이군요!!");
        }
    }
}

 

TestGeneric 클래스의 멤버변수인 sample 멤버변수는 T라는 Type을 가진다. 하지만 T라는 타입은 존재하지 않는 타입이다. T타입은 나중에 TestGeneric 클래스의 인스턴스가 생성될 때 결정이 된다.

StringType 객체 선언부를 보면 <>안에 타입을 지정하게 되는데 이때 들어가는 타입이 멤버변수 sample의 타입으로 결정된다.

 

이런식으로 객체 생성 시점에 타입이 결정되기 때문에 의도하지 않은 타입의 객체 저장을 막을 수 있고 명시적으로 타입을 지정하였기 때문에 객체를 참조할 때 명시적으로 형 변환을 해줄 필요가 없다.

 

복수 제네릭

위에서는 한 개의 제네릭을 사용하지만 복수개의 제네릭을 사용하는것도 가능하다.

 

public class Main{
    public static void main(String[] args)
    {
        TestGeneric<String, Integer> generic = new TestGeneric<String, Integer>();
    }
    public static class TestGeneric<T, K>
    {
        public T sample;
        public K sapmle2;
    }

}

 

제네릭의 구분은 쉼표(,)를 통해 하며 <T, K>와 같은 형식으로 사용하며 T,K 말고도 어떠한 문자도 사용 가능하다.

 

 

 

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

 

바운디드 타입

타입 파라미터들은 바운드(bound) 될 수 있다. 바운드 된다는 의미는 제한된다는 의미인데 메소드가 받을 수 있는 타입을 제한 할 수 있다는 것이다.

 

Unbounded type (<T>,<?>)

 

제네릭 타입 선언 후 아무런 키워드도 붙히지 않으면 unbounded type 이다.

Unbounded type 타입 파라미터로 선언된 Parameterized type은 모든 타입 파라미터에 대해 불변(Invariant) 하다.

Cat → Animal 일때 <Cat> 와 <? extends Animal> 는 서로 아무런 연관관계를 가지지 않는 각각 별개의 타입이다.

 

List<Animal> animals = new ArrayList<>(); // unbounded type parameter
List<Cat> cats = new ArrayList<>();

animals = cats // Fail, 서로 다른 타입으로 판단한다.

 

Upper bounded type (<T extends Animal>,<? extends Animal>)

 

Upper bounded type은 제네릭 타입 선언 후 extends 키워드를 이용하여 구현 가능하다.

Upper bounded type 타입 파라미터로 선언된 Parameterized type는 자기 자신 혹은 하위 클래스의 파라미터에 대해 공변(Covariant) 하다.

클래스가 아니라 인터페이스를 구현해야 한다는 제약이 필요하다면, 이때도 'implements'가 아닌 'extends'를 사용한다.

예를 들어 Cat → Animal 이면 <Cat> → <? extends Animal> 이다.

 

List<? extends Animal> animals = new ArrayList<>(); // upper bounded parameterized type
List<Cat> cats = new ArrayList<>();
List<KoreanShortHair> koreanShortHairs = new ArrayList<>();

animals = cats; // Ok, cats 는 animals 의 서브타입이다.
animals = koreanShortHairs; // Ok, koreanShortHairs 는 animals 의 서브타입이다.

 

Lower bounded type (<T super Cat>,<? super Cat>)

 

Lower bounded type은 제네릭 타입 선언 후 super 키워드를 붙히고 원하는 타입을 적으면 된다.

Lower bounded type 타입 파라미터로 선언된 Parameterized type 는 자기 자신 혹은 상위 클래스의 타입 파라미터에 대해 반 공변성(Contravariant) 하다.

예를 들어 Cat → Animal 이면 <Animal> → <? super Cat> 이다.

 

List<Animal> animals = new ArrayList<>();
List<? super Cat> superCats = new ArrayList<>(); // lower bounded parameterized type
List<KoreanShortHair> koreanShortHairs = new ArrayList<>();
        
cats = animals; // Ok, animals 는 superCats 의 서브 타입이다.
cats = koreanShortHairs; // Fail, KoreanShortHair 는 Cat 의 상위클래스가 아니다.

 

Multi bound

 

Upper bounded type에 한하여 N개의 bound 적용이 가능하다. 이때 사용되는 연산자는 &이다.

자바는 다중 상속이 허용되지 않는다. 따라서 부모 클래스가 2개 이상일 수 없으므로 Multi bound 에서 bound 할 수 있는 클래스 타입은 0 ~ 1개 이다.

위와 같은 맥락으로 인터페이스 타입은 bound 개수 제한이 없다.

클래스 타입과 인터페이스 타입을 같이 사용할 경우 클래스 타입이 제일 앞에 선언되어야 한다.

 

class A {}
interface B {}
interface C {}

class Test <T extends A & B & C>

public <T extends Number & Comparable<? super T>> int compareNumbers(T t1, T t2){
    return t1.compareTo(t2);
}

 

Test 클래스의 타입 파라미터 T 는 A 의 서브타입이고, B 와 C 를 구현해야한다.

 

compareNumbers 메소드의 타입 파라미터 T 는 Number 의 서브타입이고, Comparable 를 구현해야한다.

 

와일드카드 (wildcard)

<?>와 같이 물음표를 이용하여 제네릭 타입을 표현하는 것을 와일드 카드라고 부른다.

어떤 타입이든 가리지 않고 전달이 가능하다.

 

class TestClass <?> { } // 불가능

public void invokeTest(<?> parameter) { } // 불가능

 

제네릭 클래스의 파라미터, 제네릭 메소드의 인자 자체로는 사용이 불가능하다.

  • unbounded wildcard (<?> // 모든 타입가능 <? extends Object>와 같음)
  • upper bounded wildcard (<? extends T> // T와 자손들만 가능)
  • lower bounded wildcard ( <? super T> // T와 조상들만 가능)

Type bound 파트에서 대부분 다뤘던 내용이다.

 

 

 

3. 제네릭 메소드 만들기

 

제네릭 메소드는 매개 타입과 리턴타입으로 타입 파라미터를 갖는 메소드를 말한다.

구현을 하기 위해선 리턴 타입 앞에 <> 다이아몬드 기호를 추가하고, 타입 파라미터를 기술한 다음 리턴타입과 매개타입으로 타입파라미터를 사용하면 된다.

 

public class Box<T> {
	private T t;
    
    public T getT() { return t; }
    public void setT(T t) {this.t = t; }
    
}

 

 

 

4. Type erasure

 

자바 컴파일러는 컴파일 과정에서 제네릭에 대해 타입 소거(Type erasure)를 진행한다.

타입 소거란 타입정보를 컴파일 타임에만 유지하고, 런타임에는 삭제시켜 버리는 것인데 과거 제네릭이 없던 버전과의 하위 호환성을 위해서이다.

 

제네릭 타입이 <T extends Fruit> 라면 T->Fruit로 치환

제네릭 타입을 제거 후 타입이 일치하지 않으면, 형변환을 추가한다.

 

 

 

 

 

Reference


 

www.tcpschool.com/java/java_generic_concept

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

lktprogrammer.tistory.com/177

 

[Java] 자바 - 제네릭(Generic)

자바(Java)에서 제네릭(Generic)은 클래스 내부에서 사용하는 데이터의 타입(Type)을 클래스의 인스턴스를 생성할 때 결정하는 것을 의미합니다. 객체의 타입을 컴파일 시점에 체크하기 때문에 타입

lktprogrammer.tistory.com

vagabond95.me/posts/generic-guide/

 

[Java] Generic 도장깨기 - 기록은 기억을 지배한다

제네릭을 활용할 일이 많은데 겉핥기 식으로만 알고 있다는 생각이 들어 이번 기회에 관련 내용들을 정리했다. 무엇인가? 제네릭은 클래스, 인터페이스 및 메서드를 정의할 때 내부에서 사용될

vagabond95.me

limkydev.tistory.com/59

 

[Java] 제네릭 메서드(Generic Method)

제네릭 메소드에 대해서 알아보도록 하겠습니다. 제네릭 메소드는 매개 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 말합니다. 구현을 하기 위해선 리턴 타입 앞에 <>다이아몬트 기호

limkydev.tistory.com

 

 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30