ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] 14주차 과제 : 제네릭
    Java/온라인 자바 스터디 2021. 7. 4. 16:35
    반응형

    목표

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


    학습할 것 (필수)

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

     

    제네릭 사용법 

    제네릭이란?
    제네릭이란 클래스 혹은 메소드에서 사용할 내부 데이터 타입을 외부에서 지정하는 방법을 말합니다. 이를 통해 일반화 클래스와 메소드를 사용자가 원하는 타입으로 제어할 수 있습니다.

    제네릭 기본 문법
    일반적으로 제네릭 타입은 'T'를 사용하여 표현하지만, 어떤 영문 대문자라도 상관없습니다.

    클래스에 제네릭 사용하기
    제네릭을 사용한 클래스 선언은 아래와 같습니다.

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

    여기에서 'T'는 타입을 대표하는 파라미터입니다. 실제 타입은 클래스가 사용될 때 제시됩니다. 

    예를 들어,

    Box<Integer> box = new Box<>();
    box.set(123);
    Integer value = box.get();

    클래스 Box를 사용할 때 실제로 원하는 타입으로 쉽게 변환되며, 이 타입은 컴파일러에 의해 검사되어 추가적인 캐스팅 없이도 타입 안전을 보장받을 수 있습니다.

    메소드에 제네릭 사용하기
    메소드에도 다음과 같이 제네릭을 사용할 수 있습니다.

    public class GenericMethod {
      
      // T는 제네릭 타입
      public <T> void printArray(T[] array) {
        for(T element : array) {
            System.out.println(element);
        }
      }
      
      public static void main(String[] args) {
      
        GenericMethod gm = new GenericMethod();
    
        Integer[] intArray = {10, 20, 30, 40, 50};
        String[] strArray = {"Hello", "World", "Generics"};
    
        System.out.println("Printing Integer Array");
        gm.printArray(intArray);  // Integer 타입의 배열을 처리
    
        System.out.println("Printing String Array");
        gm.printArray(strArray);  // String 타입의 배열을 처리
      }
    }

    위의 예제에서 printArray 메소드는 Integer 배열 또는 String 배열 등 다양한 타입의 배열을 인자로 받을 수 있습니다. 이처럼 제네릭을 사용하면 메소드가 다양한 데이터 타입에 대응하도록 일반화될 수 있습니다.

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

    바운디드 타입 (Bounded Type)
    바운디드 타입은 제네릭 타입에 특정한 '범위'를 제한하는 문법입니다. 이를 통해 특정 클래스의 하위 클래스 혹은 상위 클래스만을 타입 파라미터로 받게 제한할 수 있습니다.

    다음 코드는 extends를 이용한 바운디드 타입의 사용예입니다.

    public class Box<T extends Number> {
      //...
    }

    위 코드에서 T extends Number는 T는 Number의 서브클래스만 받겠다는 의미입니다. Number 클래스를 확장(extends)한 Integer, Double, Float 등의 클래스 들을 T의 타입으로 사용할 수 있지만, Number와 관련 없는 타입인 String 등과 같은 타입은 사용할 수 없습니다.

    와일드 카드 (Wildcard)
    와일드카드는 '?' 기호로 표현되며, 제네릭의 타입 파라미터가 너무 다양하여 특정 지을 수 없을 때 사용합니다.
    다음은 extends를 사용한 와일드 카드 예시입니다.

    public void printBox(Box<? extends Number> box){
      //...
    }

    위 메소드는 아무 종류의 Number 하위 클래스 타입이든지 받을 수 있는 Box 객체를 인자로 받습니다. 즉, Box<Integer>, Box<Double>, Box<Float> 등을 파라미터로 받을 수 있습니다.

    또한, 다음은 super를 사용한 와일드카드 예시입니다.

    public void printBox(Box<? super Integer> box){
      //...
    }

    이 메소드는 Integer 또는 그의 부모 클래스 타입을 가진 Box 객체를 파라미터로 받을 수 있습니다.
    이처럼, 자바의 제네릭 기능인 바운디드 타입과 와일드 카드는 타입 안전성을 보장하면서도 특정 범위의 클래스 타입만 제한하거나, 다양한 타입을 허용하는 등 타입의 범위를 유연하게 조절할 수 있습니다.


    제네릭 메소드 만들기 

    제네릭 방식은 클래스뿐만 아니라 메소드에서 사용할 수도 있습니다. 제네릭 메소드가 사용되면 해당 메소드는 다양한 데이터 타입에 대응할 수 있게 됩니다.
    제네릭 메소드를 정의하는 방법은 메소드의 리턴 타입 앞에 <T>를 추가하면 됩니다. 여기서 T는 타입 파라미터이며, 일반적으로 대문자 알파벳을 사용합니다. 이는 메소드 호출 시 실제 사용할 데이터 타입을 나타냅니다.

    public <T> void genericMethod(T t) {
      // method body
    }

    위 메소드는 입력 파라미터의 타입을 매개변수로 받습니다. 이를 통해 메소드는 어떤 데이터 타입에도 대응할 수 있게 되며 실제 타입은 메소드 호출 시 결정됩니다.

    다음은 제네릭 메소드를 사용하는 예제입니다.

    public class MyGenericClass {
        
        public <T> void print(T input) {
            System.out.println(input);
        }
        
        public static void main(String[] args) {
            MyGenericClass myGenericClass = new MyGenericClass();
            myGenericClass.print(10);    // 출력: 10
            myGenericClass.print("Hello World"); // 출력: Hello World
            myGenericClass.print(5.5);   // 출력: 5.5
        }
    }

    위 예제에서 print() 함수는 제네릭 메소드로서, 어떠한 데이터 타입도 인자로 받을 수 있으며, 실제 데이터 타입은 메소드 호출 시점에 결정됩니다. 이처럼, 제네릭 메소드를 사용하면 메소드의 재사용성을 크게 높일 수 있습니다.


    Erasure

    제네릭은 자바에서 유형의 안정성을 높이고 코드 재사용성을 향상시키는 방법입니다. 예를 들어, List<String>은 문자열만 저장할 수 있는 List를 의미합니다.
    그러나 제네릭 정보는 런타임에 사라진다는 것입니다. 이를 '타입 소거(Type Erasure)'라고 합니다.

    List<Integer> list = new ArrayList<Integer>();

    위와 같은 코드가 있다면 소거 후 아래와 같이 됩니다.

    List list = new ArrayList();

    이렇게 되는 이유는 이전의 자바 코드와 호환성을 유지하기 위해서입니다. 이를 통해 제네릭이 도입된 자바 5 이후의 코드도 자바 5 이전의 JVM에서 실행할 수 있습니다.
    따라서, 제네릭은 컴파일 시점에 데이터 타입을 체크하여 오류를 잡아주지만, 런타임에서는 제네릭 정보가 없기 때문에, 제네릭 코드를 런타임에 데이터 타입 정보를 요구하는데 사용할 수 없습니다.

     

    참조 : https://github.com/whiteship/live-study/issues/14

    반응형

    댓글

Designed by Tistory.