제너릭(Generic)

귀찮Lee·2022년 5월 17일
0

Java

목록 보기
5/15
post-custom-banner

◎ 제너릭(Generic)

  • 제너릭 : 클래스에서 다룰 객체를 미리(객체 생성시에) 명시해줌으로써 형 변환을 하지 않고 사용하는 것

  • 필요성

    • 내부 코드는 동일한지만 다른 타입의 field, Method, Class들이 필요하다면, 이를 하나하나 전부 만드는 것은 비효율적이다.
    • 최상위 클래스인 Object를 이용한다면, 다형성으로 인해 쉽게 다룰 수 있을 것이다. 그러나 매번 수동 형변환을 해주어야 해서 일부 비효율적이다.
    public class genericTest {
        public static void main(String[] args) {
            Basket basket = new Basket();
            basket.set('A');
            char A = (char) basket.get(); // 매번 가져올 때마다 수동 형변환이 필요
    }
    
    class Basket {
        private Object object;
        public void set(Object object) { this.object = object; }
        public Object get() { return object; }
    }
    • 따라서 상황마다 다르게 타입을 설정 해주어야할 필요성이 있음
  • 다운 캐스팅의 문제점

    • 컴파일러가 다운 캐스팅의 오류를 발견하지 못한다.
    • 행 시 타입이 맞지 않으면 TypeCastException 오류를 발생시킨다.
    • 시 타입을 검사하는 instanceof 메서드는 매우 비싼 연산이다.
    • 다운 캐스팅 자체가 가독성이 저하된다.
    • 참고 : https://jihyeong-ji99hy99.tistory.com/121
  • 장점

    • 타입체크와 형변환을 생략해서 간결한 코드 작성이 가능
    • 클래스나 메서드 내부에서 사용되는 객체의 타입 안정성을 제공

◎ 제네릭 클래스(Generic Class)

  • 제네릭 클래스(Generic Class)

    • 제네릭 타입을 선언한 클래스
    • 객체를 생성하는 시점에 실제 타입을 지정
    • 클래스 내에서 전역변수처럼 사용
  • 제네릭 클래스 표현 방법, 예시

    public class 클래스명<타입 매개변수>{ ... }
    public interface 인터페이스명<타입 매개변수>{ ... }
    --------------------------
    class Basket2<T> {
        private T t;
        public T get() { return t; }
        public void set(T t) { this.t = t; }
    }
    
    public class genericTest {
        public static void main(String[] args) {
            // 사용 방법
            Basket2<Character> basket2 = new Basket2(); // 객체 생성시 특정 타입 지정
            basket2.set('A');
            char A = basket2.get();
    
            // 객체 생성시 아래와 같이 생략 가능
            Basket2<Character> basketExample1 = new Basket2();
            Basket2<Character> basketExample2 = new Basket2<>();
            Basket2<Character> basketExample3 = new Basket2<Character>();
        }
    }
    • 타입 매개변수 예시

      타입인자설명
      < T >Type
      < E >Element
      < K, V >Key, Value
      < R >Result
  • 용어 정리

    public class Basket<T>
    -----------------------------
    Basket // 원시 타입 (여기서 '원시'는 primitive가 아니라, raw를 의미)
    Basket<T> // T Basket
    T // 타입 매개변수, 타입 변수
    <> // 다이아몬드 연산자

◎ 제네릭 메서드(Generic Method)

  • 제네릭 메소드(Generic Method)

    • 제네릭 타입을 선언한 메소드
    • 호출되는 시점에서 실제 제네릭 타입을 지정
    • 해당 메서드 안에서만 사용할 수 있는 지역 변수처럼 사용
    • 해당 객체가 입력될 때까지 어떤 타입이 들어오는지 알 수 없으므로, Object 클래스의 메서드만 사용 가능
    public class genericMethodTest {
        public static void main(String[] args) {
    
            String stringExample = UseGenericMethod.ToString(3453);
            System.out.println(stringExample.getClass()); // 3453
    
            System.out.println(UseGenericMethod.equal1234(1234)); // true
            System.out.println(UseGenericMethod.equal1234("1234")); // false
        }
    }
    
    class UseGenericMethod {
        public static <T> String ToString(T t) {
            return t.toString();
        }
        public static <T> boolean equal1234(T t) {
            return t.equals(1234);
        }
    
        // 특정 타입에서만 사용 할 수 있는 메서드는 사용불가
        // public static <T> int hashcode (T t1,T t2) {return Integer.sum(t1,t2);}
    }

◎ 와일드카드(wild card)

  • 와일드카드(wild card)
    • 제한을 두지 않는 기호
    • 타입 파라미터가 의미있게 사용되지않는다면 와일드카드 사용하는 것이 유용하다.
    • 클래스의 객체를 메소드의 매개변수로 받을 때, 그 객체의 타입 변수를 제한할수도 있다.
    <?> //타입 매개변수에 모든 타입 사용
    <? extends T> //T 타입과 T타입을 상속받는 하위 클래스 타입만 사용
    <? super T> // T 타입과 T타입을 상속받은 상위 클래스 타입만 사용
  • 사용 예시
public class WildcardTest {
    public static void main(String[] args) {
        LowerClass1 lowerClass1 = new LowerClass1();
        LowerClass2 lowerClass2 = new LowerClass2();
        CoverClass<LowerClass1> coverLowerClass1 = new CoverClass<>(lowerClass1);
        CoverClass<LowerClass2> coverLowerClass2 = new CoverClass<>(lowerClass2);

        UseWildcard.getVariable1(coverLowerClass1);
        UseWildcard.getVariable1(coverLowerClass2);

        UseWildcard.showAddress(coverLowerClass1);
        // UseWildcard.showAddress(coverLowerClass2); // ERROR : super 조건에 어긋남
    }
}

class UpperClass {int variable1 = 3;}
class LowerClass1 extends UpperClass {int variable2;}
class LowerClass2 extends UpperClass {int variable3;}
class CoverClass<T>{
    T element;
    CoverClass(T element){this.element = element;}
}

class UseWildcard{

	// 기본 예시
    static Number process(List<? extends Number> list){
        return list.get(0);
    }
    
    // 활용 예시
    static int getVariable1(CoverClass<? extends UpperClass> coverClass){
        return coverClass.element.variable1;
    }
    static void showAddress(CoverClass<? super LowerClass1> coverClass){
        // super 또는 ? 일 때는 Object의 메서드만 사용 가능
        System.out.println(coverClass);
        // System.out.println(coverClass.element.variable2); // 사용불가
    }
}

https://jinbroing.tistory.com/228 참고해서 더 공부할 것

profile
배운 것은 기록하자! / 오류 지적은 언제나 환영!
post-custom-banner

0개의 댓글