ToBe끝판왕

[ JAVA ] 제네릭 ( Generic ) 본문

■ 프로그래밍 SKILLS/JAVA

[ JAVA ] 제네릭 ( Generic )

업그레이드중 2024. 10. 26. 01:28
반응형



 


 

 

제네릭 ( Generic )

 

 

1) Generic 이란 ?

 

• Generic에 대해 알아보자

-  Class , Interface, Method 에 타입 매개변수를 추가해 코드의 유연성과 안정성을 높일수 있는 기능

-  다양한 타입을 처리가 가능토록 하여, 컴파일 시 타입 안정성을 보장한다.

-  특히, 컬렉션 프레임워크에서 자주 사용된다.

-  컴파일 시, 타입을 체크하여 타입 오류를 방지한다.

 

 

• Generic 타입 매개변수 명명 관례

-  T  :  Type을 의미하며, 일반적인 타입을 나타낼 때 사용

-  E  :  Element의 약어로, 주로 컬렉션의 요소를 나타낼 때 사용

-  K, V  :  Key 와 Value 의 약어로, 주로 Map 과 같은 키 - 값 구조에서 사용

-  N  :  Number의 약어로, 숫자를 나타낼 때 사용

 

 

• Generic 사용 제한

-  기본 타입 ( int, double 등 ) 대신 래퍼 클래스 ( Integer, Double 등 ) 을 사용해야 한다.

-  정적 ( Static ) 멤버에 사용 불가능

 

 


 

 

2) Generic 예시

 

 

• Generic 사용 예시 1

package hello.blog.generic;

public class GenericBoxMain {

    public static void main(String[] args) {

        GenericBox<Integer> integerBox = new GenericBox<Integer>();
        // Integer 타입만 허용, 다른 타입의 경우 컴파일시 오류 발생
        integerBox.set(10);
        Integer integer = integerBox.get();
        System.out.println("integer = " + integer);

        GenericBox<String> stringBox = new GenericBox<String>();
        stringBox.set("hello");
        String str = stringBox.get();
        System.out.println("str = " + str);

        // 제네릭이기 때문에 모든 타입이 가능
        GenericBox<Double> doubleBox = new GenericBox<Double>();
        doubleBox.set(10.5);
        Double doubleValue = doubleBox.get();
        System.out.println("doubleValue = " + doubleValue);

        // 타입 추론 -> 제네릭 객체 생성시 생성하는 제네릭 타입 생략 가능
        GenericBox<Integer> integerBox2 = new GenericBox<>();
        integerBox2.set(20);
        Integer integer2 = integerBox2.get();
        System.out.println("integer2 = " + integer2);
    }
}

 

// 결과

integer = 10
str = hello
doubleValue = 10.5
integer2 = 20

 

 

 

• Generic 사용 예시 2

 

package hello.blog.generic;

public class GenericMain {

    public static void main(String[] args) {

        Pair<Integer, String> pair1 = new Pair<>();
        pair1.setFirst(1);
        pair1.setSecond("data");
        System.out.println(pair1.getFirst());
        System.out.println(pair1.getSecond());
        System.out.println("pair1 = " + pair1);

        Pair<String, String> pair2 = new Pair<>();
        pair2.setFirst("key");
        pair2.setSecond("value");
        System.out.println(pair2.getFirst());
        System.out.println(pair2.getSecond());
        System.out.println("pair2 = " + pair2);

    }
}

 

package hello.blog.generic;

public class Pair<T1, T2> {

    private T1 first;
    private T2 second;

    public T1 getFirst() {
        return first;
    }

    public void setFirst(T1 first) {
        this.first = first;
    }

    public T2 getSecond() {
        return second;
    }

    public void setSecond(T2 second) {
        this.second = second;
    }

    @Override
    public String toString() {
        return "Pair{" +
                "first=" + first +
                ", second=" + second +
                '}';
    }
}

 

// 결과

1
data
pair1 = Pair{first=1, second=data}
key
value
pair2 = Pair{first=key, second=value}

 

 

 

 

• 제네릭에 "타입 매개변수 상한" 을 두기 예시

 

package hello.blog.generic.animal;

public class Animal {

    private String name;
    private int size;

    public Animal(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String getName() {
        return name;
    }

    public int getSize() {
        return size;
    }

    public void sound() {
        System.out.println("동물 울음 소리");
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", size=" + size +
                '}';
    }
}

 

package hello.blog.generic.animal;

public class Cat extends Animal{
    public Cat(String name, int size) {
        super(name, size);
    }

    @Override
    public void sound() {
        System.out.println("냐옹");
    }
}

 

package hello.blog.generic.animal;

public class Dog extends Animal{
    public Dog(String name, int size) {
        super(name, size);
    }

    @Override
    public void sound() {
        System.out.println("멍멍");
    }
}

 

package hello.blog.generic.animal;

public class AnimalHospital <T extends Animal>{

    private T animal;

    public void set(T animal) {
        this.animal = animal;
    }

    public void checkUp() {
        System.out.println("동물 이름: " + animal.getName());
        System.out.println("동물 크기: " + animal.getSize());
        animal.sound();
    }

    public T getBigger(T target) {
        return animal.getSize() > target.getSize() ? animal : target;
    }
}

 

package hello.blog.generic.animal;

public class AnimalHospitalMain {

    public static void main(String[] args) {

        AnimalHospital<Dog> dogHospital = new AnimalHospital<>();
        AnimalHospital<Cat> catHospital = new AnimalHospital<>();

        Dog dog = new Dog("멍멍이1", 100);
        Cat cat = new Cat("냐옹이1", 300);

        // 개 병원
        dogHospital.set(dog);
        dogHospital.checkUp();

        // 고양이 병원
        catHospital.set(cat);
        catHospital.checkUp();

        // 개병원에 고양이 전달 -> 컴파일 오류 발생 ( 다른 타입 입력 )
        // dogHospital.set(cat);

        // 개 타입 반환
        dogHospital.set(dog);
        Dog biggerDog = dogHospital.getBigger(new Dog("멍멍이2", 200));
        System.out.println("biggerDog = " + biggerDog);
    }
}

 

 

-  < T extends Animal > 을 통해 상한이 Animal 이 된다.

-  T 에 타입 인자로 Animal, Cat, Dog 만 들어올 수 있다. ( 전혀 관계 없는 타입인자를 컴파일시 막는다. )

-  Animal이 제공하는 getName(), getSize() 메서드가 사용 가능하다.

 

 

▶  타입 매개변수 상한을 사용해서 타입 안정성을 지키면서 상위 타입의 기능 (메서드) 까지 사용 가능하였다.

     즉, 코드 재사용과 타입 안정성 모두를 가져 갈 수 있다.

 

 

 


 

 

3) Generic 메서드

 

 

-   특정 메서드 단위로 제네릭을 도입할 수 있다.

-  <T> T genericMethod( T t ) 와 같이 사용한다.

-  메서드를 실제 호출하는 시점에 타입을 지정하고 호출한다. ( 타입 안정성 보장 )

 

 

※  제네릭 클래스의 경우, 클래스 내 모든 메서드에 제네릭이 적용된다.

 

※  정적 메서드의 경우 제네릭 클래스가 아닌 메서드 단위로 제네릭을 도입해야 한다.

 

※  인스턴스 메서드의 경우 제네릭 메서드가 제네릭 클래스보다 우선순위가 높다 

 

 

 

▶  실무에서는 직접 제네릭을 사용하여 무언가를 설계하거나 만드는일이 드물며, 제네릭을 통해 만들어진

     프레임워크나 라이브러리를 가져다 사용하는 경우가 많다. 

     그러므로, 이미 만들어진 코드의 제네릭을 읽고 이해하는 정도면 충분하다고 볼 수 있다. 

 

 

 

※ 해당 내용은 인프런 김영한 강사님의  "실전 자바 중급2" 인강의 자료와 예시들을 참고하였습니다

반응형
Comments