Java Generic & Wildcard & Wrapper

2023. 4. 1. 11:23·📘 Backend/Java

📘 Generic

타입을 추후에 지정할 수 있도록 일반화 해두는 것


예시

제네릭을 사용하지 않았을때 작성한 비효율적인 코드

class Basket {
    private String item;

    Basket(String item) {
        this.item = item;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }
}
class BasketString { private String item; ... }
class BasketInteger { private int item; ... }
class BasketChar { private char item; ... }
class BasketDouble { private double item; ... }

하지만 아래 예시로 단 하나의 Basket 클래스 만으로
모든 타입의 데이터를 저장할 수 있는 인스턴스 생성가능

class Basket<T> {
    private T item;

    public Basket(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

위의 Basket 클래스는 다음과 같이 인스턴스화도 가능하다

Basket<String> basket1 = new Basket<String>("기타줄");

위의 코드는 "Basket 클래스 내의 T를 String으로 바꿔라" 라는 의미이기도 하며, 실행하면 타입<T>가 전부 String이 됨


Generic Class 정의

  • Generic이 사용된 클래스를 칭함
  • 클래스 변수에는 타입 매개변수를 사용못함 ex) static T item1; // X

기본 형식

  • class Basket<T> // 임의의 타입 매개변수 T 선언
  • class Basket<T, V> // 임의의 타입매개변수 여러개 선언

Generic Class 사용

  • 멤버를 구성하는 코드에 특정한 타입지정이 되지않은 클래스이므로, 제네릭을 인스턴스화를 할때 타입지정 해줘야함
  • 단, 타입 매개변수에 치환될 타입으로 기본타입 지정 X , Wrapper Class O
Basket<String>  basket1 = new Basket<String>("Hello");
Basket<Integer> basket2 = new Basket<Integer>(10);
Basket<Double>  basket3 = new Basket<Double>(3.14);

위의 코드에서 new Bastet<> 의내용은 생략 가능(참조변수의 타입으로 유추 가능하기 때문)


Generic Class 다형성 적용

class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

class Basket<T> {
    private T item;

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

public static void main(String[] args) {
        Basket<Flower> flowerBasket = new Basket<>();
        flowerBasket.setItem(new Rose());      // 다형성 적용
        flowerBasket.setItem(new RosePasta()); // 에러
}

제한된 Generic Class

  • 타입 매개변수를 선언할때 extends로 상속이 되면 상위클래스로 지정된 클래스의 하위 클래스만 지정하도록 제한
    • ex) class Basket<T extends Flower>
  • 특정 클래스와 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 & 를 사용하여 제한
    • ex) class Basket<T extends Flower & Plant> // 무조건 클래스명을 먼저 써야함
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

class Basket<T extends Flower> {
    private T item;

        ...
}

public static void main(String[] args) {

        // 인스턴스화 
        Basket<Rose> roseBasket = new Basket<>();
        Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러

Generic Method

  • 클래스 전체가 아닌 클래스 내부의 특정 메소드만 제네릭 선언
  • 제네릭 클래스/메소드 는 서로 다른 타입의 매개변수로 간주
  • static 메소드에서도 선언/사용 가능
class Basket<T> {                        // 1 : 여기에서 선언한 타입 매개변수 T와 
        ...
        public <T> void add(T element) { // 2 : 여기에서 선언한 타입 매개변수 T는 서로 다른 것입니다.
                ...
        }
}

아래의 예시는 제네릭 메소드의 호출 방법이며 제네릭 메소드에서 선언한 타입매개변수의 구체적 타입이 지정됨

Basket<String> basket = new Bakset<>(); // 위 예제의 1의 T가 String으로 지정됩니다. 
basket.<Integer>add(10);                // 위 예제의 2의 T가 Integer로 지정됩니다. 
basket.add(10);                         // 타입 지정을 생략할 수도 있습니다. 

📘 와일드카드

  • 일반적으로 extends 나 super를 조합하여 사용

와일드카드 ex)

<? extends T>
<? super T>

<? extends T>는 와일드카드에 상한 제한을 두는 것으로서,

T와 T를 상속받는 하위 클래스 타입만 타입 파라미터로 받을 수 있도록 지정


반면, <? super T>는 와일드카드에 하한 제한을 두는 것으로, T와 T의 상위 클래스만 타입 파라미터로 받도록 함


참고로, extends 및 super 키워드와 조합하지 않은 와일드카드(<?>)는 <? extends Object>와 같다

즉, 모든 클래스 타입은 Object 클래스를 상속받으므로, 모든 클래스 타입을 타입 파라미터로 받을 수 있음을 의미


class Phone {}

class IPhone extends Phone {}
class Galaxy extends Phone {}

class IPhone12Pro extends IPhone {}
class IPhoneXS extends IPhone {}

class S22 extends Galaxy {}
class ZFlip3 extends Galaxy {}

class User<T> {
        public T phone;

        public User(T phone) {
                this.phone = phone;
        }
}

위 코드의 상속 계층도

img

  • call : 휴대폰의 기본적인 통화 기능으로, 모든 휴대폰에서 사용할 수 있는 기능입니다.
    • → ? extends Phone으로 타입을 제한할 수 있습니다.
  • faceI : 애플의 안면 인식 보안 기능으로, 아이폰만 사용 가능합니다.
    • → ? extends IPhone으로 타입을 제한할 수 있습니다.
  • samsungPay : 삼성 휴대폰의 결제 기능으로, 삼성 휴대폰에서만 사용 가능합니다.
    • → ? extends Galaxy로 타입을 제한할 수 있습니다.
  • recordVoice : 통화 녹음 기능을 일컬으며, 아이폰을 제외한 안드로이드 휴대폰에서만 사용 가능합니다.
    • → ? super Galaxy로 타입을 제한할 수 있을 것으로 보입니다.
class PhoneFunction {
    public static void call(User<? extends Phone> user) {
        System.out.println("-----------------------------");
        System.out.println("user.phone = " + user.phone.getClass().getSimpleName());
        System.out.println("모든 Phone은 통화를 할 수 있습니다.");
    }

    public static void faceId(User<? extends IPhone> user) {
        System.out.println("-----------------------------");
        System.out.println("user.phone = " + user.phone.getClass().getSimpleName());
        System.out.println("IPhone만 Face ID를 사용할 수 있습니다. ");
    }

    public static void samsungPay(User<? extends Galaxy> user) {
        System.out.println("-----------------------------");
        System.out.println("user.phone = " + user.phone.getClass().getSimpleName());
        System.out.println("Galaxy만 삼성 페이를 사용할 수 있습니다. ");
    }

    public static void recordVoice(User<? super Galaxy> user) {
        System.out.println("-----------------------------");
        System.out.println("user.phone = " + user.phone.getClass().getSimpleName());
        System.out.println("안드로이드 폰에서만 통화 녹음이 가능합니다. ");
    }
}

📘 Wrapper 클래스

  • 값에 Null이 들어올 수 있을때 NPE를 방지하기 위해 많이 사용한다.
  • 프로그래밍을 하다보면 기본타입의 데이터를 객체로 표현해야 할 경우가 있는데 이때 사용함
  • 자바의 모든 기본타입은 값은 갖는 객체생성이 가능하며, 이를 포장객체라고 부르며, 기본타입의 값을 내부에 두고 포장
  • 래퍼 클래스로 감싸고 있는 기본타입 값은 외부에서 변경X, 값을 변경하려면 새로운 포장객체를 생성해야함

기본 타입에 대응하는 Wrapper 클래스의 종류

img

저작자표시 (새창열림)

'📘 Backend > Java' 카테고리의 다른 글

Java Try-with-Resource & Multi Catch  (0) 2023.04.01
Java Exception  (0) 2023.04.01
Java Enum  (0) 2023.04.01
Java 객체 지향 프로그래밍 - 2  (0) 2023.04.01
Java 객체 지향 프로그래밍 - 1  (0) 2023.04.01
'📘 Backend/Java' 카테고리의 다른 글
  • Java Try-with-Resource & Multi Catch
  • Java Exception
  • Java Enum
  • Java 객체 지향 프로그래밍 - 2
신건우
신건우
조용한 개발자
  • 신건우
    우주먼지
    신건우
  • 전체
    오늘
    어제
    • 분류 전체보기 (422)
      • 📘 Frontend (71)
        • Markup (1)
        • Style Sheet (2)
        • Dart (8)
        • Javascript (12)
        • TypeScript (1)
        • Vue (36)
        • React (2)
        • Flutter (9)
      • 📘 Backend (143)
        • Java (34)
        • Concurrency (19)
        • Reflection (1)
        • Kotlin (29)
        • Python (1)
        • Spring (42)
        • Spring Cloud (5)
        • Message Broker (5)
        • Streaming (2)
        • 기능 개발 (5)
      • 💻 Server (6)
        • Linux (6)
      • ❌ Error Handling (11)
      • 📦 Database (62)
        • SQL (31)
        • NoSQL (2)
        • JPQL (9)
        • QueryDSL (12)
        • Basic (4)
        • Firebase (4)
      • ⚙️ Ops (57)
        • CS (6)
        • AWS (9)
        • Docker (8)
        • Kubernetes (13)
        • MSA (1)
        • CI & CD (20)
      • 📚 Data Architect (48)
        • Data Structure (10)
        • Algorithm (8)
        • Programmers (17)
        • BaekJoon (5)
        • CodeUp (4)
        • Design Pattern (4)
        • AI (0)
      • ⚒️ Management & Tool (8)
        • Git (7)
        • IntelliJ (1)
      • 📄 Document (10)
        • Project 설계 (6)
        • Server Migration (3)
      • 📄 책읽기 (2)
        • 시작하세요! 도커 & 쿠버네티스 (2)
      • 🎮 Game (4)
        • Stardew Vally (1)
        • Path of Exile (3)
  • 블로그 메뉴

    • 링크

      • Github
    • 공지사항

    • 인기 글

    • 태그

      Lock #Thread #Concurrency
      GStreamer #Pipeline
      React #Markdown
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.0
    신건우
    Java Generic & Wildcard & Wrapper
    상단으로

    티스토리툴바