자료구조 #9 - 제네릭 사용법

HongInSung·2022년 11월 29일
0
post-thumbnail

이 포스트는 FastCampus에 이 강의를 보고 포스팅되었습니다.
문제가 될 시 삭제될 예정입니다.

제네릭 얘 어떻게 쓰는건데?

사용법을 알아보기 위해 가정을 하나 해봅시다.
자 여기에 3D 프린터가 있다 칩시다.
3D 프린터는 어떤 입체적인 모양을 뽑는 데 쓰죠? 그 모양을 뽑는 데는 재료가 듭니다.
이 재료가 뭐냐에 따라 다르죠.
일단 제네릭을 안 쓰고 코딩해보겠습니다.

No Generic Version

{
  "프로젝트 이름" : "3D 프린터",
  "제네릭 사용 여부" : false,
  "개발 도구" : "IntelliJ 2022.2.4",
  "개발 자바 버전" : 18,
}

일단 각 재료에 대한 클래스를 만들어야 합니다.
일단 저는 예시로 플라스틱파우더로 하겠습니다.

public class Powder {
    public String toString() {
        return "재료는 Powder 입니다.";
    }
}
public class Plastic {
    public String toString() {
        return "재료는 Plastic 입니다.";
    }
}

그 다음으로는 이 두가지 재료를 사용할 클래스 2개를 만들어야 합니다.

public class ThreeDPrinter1 {
    private Powder material;

    public Powder getMaterial() {
        return material;
    }

    public void setMaterial(Powder material) {
        this.material = material;
    }
}
public class ThreeDPrinter2 {
    private Plastic material;

    public Plastic getMaterial() {
        return material;
    }

    public void setMaterial(Plastic material) {
        this.material = material;
    }
}

이렇게 하면 클래스도 2개 만들어야 하고, 번거롭습니다.
그래서 선대 개발자분들은 재료 자료형을 직접 넣는 대신 Object 클래스를 이용하였었습니다.

public class ThreeDPrinter3 {
    private Object material;

    public Object getMaterial() {
        return material;
    }

    public void setMaterial(Object material) {
        this.material = material;
    }
}

근데 이렇게 하면 또 문제가 발생합니다.
테스트 코드를 적어보겠습니다.

public class ThreeDPrinterTest {
    public static void main(String[] args) {
        ThreeDPrinter3 test = new ThreeDPrinter3();

        Powder powder = new Powder();

        test.setMaterial(powder);
        // 여기까지만 해도 문제는 없었음

        Powder p = test.getMaterial();
        // 여기에서 문제 발생.

        Powder p2 = (Powder) test.getMaterial();
        // 강제로 형변환을 해줘야 문제가 해결됨
    }
}

깅제로 형변환도 해줘야 하고, Object도 그닥 좋은 방법은 아닌 것 같습니다.
이제 한번 Generic으로 코딩해보겠습니다.

Generic Version

{
  "프로젝트 이름" : "3D 프린터",
  "제네릭 사용 여부" : true,
  "개발 도구" : "IntelliJ 2022.2.4",
  "개발 자바 버전" : 18,
}

제네릭은 클래스명 뒤에 <T>를 붙여주시고, 자료형을 T로 바꿔주시면 됩니다.

public class GenericPrinter<T> {
    public T material;

    public T getMaterial() {
        return material;
    }

    public void setMaterial(T material) {
        this.material = material;
    }

    public String toString() {
        return material.toString();
    }
}

테스트 클래스를 다시 적어보겠습니다.

public class ThreeDPrinterGTest {
    public static void main(String[] args) {
        GenericPrinter<Powder> GP = new GenericPrinter<>();

        Powder pw = new Powder();

        GP.setMaterial(pw);

        System.out.println(GP.toString());
    }
}

오류가 사라진 것을 확인할 수 있었습니다.

<> <- 얘는 뭐하는 애임?

<>는 다이아몬드 연산자라고 하는 놈입니다.
다이아몬드 연산자가 나오기 전엔 이렇게 써줘야 했었습니다.

GenericPrinter<Powder> GP = new GenericPrinter<Powder>();

하지만 나온 뒤부터는 이렇게 작성이 가능해졌죠.

GenericPrinter<Powder> GP = new GenericPrinter<>();

근데, 만약 T에 아무런 자료형도 안넣으면..?

T에 아무런 자료형도 넣지 않게 된다면, T는 자동으로 Object 형으로 인식합니다.
그래서 T에서 Object 자료형의 메서드를 사용할 수 있죠.

코드 좀

위 코드들은 전부 제 깃허브에 올라가 있습니다.
제네릭 없는 버전은 noGeneric, 제네릭 쓴 버전은 useGeneric 가셔서 소스 보시면 됩니다.

다음시간엔 뭐할거임?

위처럼 T를 쓰면 어떤 자료형이든 넣을 수 있지만, 도리어 문제가 될 수 있습니다.
그래서 다음 시간에는 자료형을 제한할 수 있는 T extend를 배워보도록 하겠습니다.
수고하셨습니다.

profile
안녕하세요! 풀스택 노려보고 있는 홍인성입니다!

0개의 댓글