[Java] 제네릭

이지현·2022년 3월 29일
1
post-thumbnail

📕1. 제네릭

1-1. 제네릭이란?

  • 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미
  • 어떤 값이 하나의 참조 자료형이 아니니 여러 참조 자료형을 사용할 수 있도록 프로그래밍하는 것을 제네릭 프로그래밍 이라고 한다

    💡 즉, 클래스를 정의 할 때는 데이터 타입을 확정하지 않고 인스턴스를 생성할 때 데이터 타입을 지정하는 기능이 제네릭이다.

1-2. 제네릭을 사용하는 이유

하나의 예시를 들어서 알아보자 !

  • 3D프린터를 예로 들어보면,

  • 3D 프린터는 재료를 가지고 입체 모형을 만드는일을 한다.
    프린터에 쓰이는 재료는 여러가지가 있을 수 있는데, 쌓아 올려 입체 모형을 만드는 경우에
    파우더플라스틱 액체 를 사용한다.

그러면 다음과 같이 파우더를 재료로 사용하는 3D 프린터 클래스 코드를 먼저 만들어 보자

💡 파우더를 재료로 사용하는 3D 프린터 클래스 💡

public class ThreeDprinter {
    // 재료가 파우더인 경우
    private Powder material;

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

    public Powder getMaterial() {
        return material;
    }
} ////////////////////////// class
  • 재료가 파우더인 3D 프린터 클래스를 만들어 보았는데, 재료가 플라스틱 액체일 경우는 또 클래스를 만들어야 하는지 의문이 든다

일단 재료가 플라스틱 액체일 경우의 클래스도 만들어보자 !

💡 재료가 플라스틱 액체일 경우의 클래스 💡

public class ThreeDprinter {
    // 재료가 플라스틱 액체인 경우
    private Plastic material;

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

    public Plastic getMaterial() {
        return material;
    }
} ////////////////////////// class
  • 이렇게 두 가지의 경우에 따라서 쓸 수 있도록 따로 따로 구현을 해놨더니
    재료만 다르지 기능은 똑같다.

재료만 다를 뿐인데 굳이 두개의 클래스를 만들 필요가 있을까?

  • 어떤 재료든 쓸 수 있도록 변수의 자료형을 Object 로 사용하여 Object 를 활용한 제네릭 프로그래밍을 만들어보자
💡 Object 를 활용한 제네릭 프로그래밍 💡

public class ThreeDprinter {
    // 모든 타입을 Object로 선언
    private Object material;

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

    public Object getMaterial() {
        return material;
    }
} ////////////////////////// class
  • Object 는 모든 클래스의 최상위 클래스이기 때문에 아무 클래스나 다 받을 수가 있게 되었다.

그러면 Object로 선언한 ThreeDPrinter에 파우더를 재료로 사용할 경우 코드를 입력해보자!

💡 Object로 선언한 ThreeDPrinter에 파우더를 재료로 사용할 경우 💡

ThreeDPrinter printer = new ThreeDPrinter();

Powder p1 = new Powder();
printer.setMaterial(p1);    // 자동으로 형 변환이 된다.

Powder p2 = (Powder)printer.getMaterial();  // 직접 형 변환을 해야된다.
  • 이처럼, 여러 참조 자료형이 쓰일 수 있는 곳에 특정한 자료형을 지정하지 않고, 클래스나 메서드를 정의한 후 사용하는 시점에 어떤 자료형을 사용할 것인지 지정하는 방식을 제네릭 방식이라고 한다.

1-3. 제네릭 클래스 정의하기

  • 제네릭에서는 여러 참조 자료형을 사용해야 하는 부분에 Object가 아닌 하나의 문자로 표현한다.

위에서 예를 든 ThreeDPrinter제네릭 클래스로 정의해보자

💡 제네릭 클래스 정의하기 💡

public class GenericPrinter<T> {
    private T material;

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

    public T getmaterial() {
        return material;
    }
}/////////////////// class
  • 위 코드에서 Ttype의 약자로 자료형 매개변수 라고 부른다.
  • 나중에 클래스를 사용할 때 T 위치에 실제 사용할 자료형을 지정하면 된다.
  • T 외에도 다른 문자도 사용할 수 있다.
    Eelement
    Kkey
    Vvalue

의미가 이렇다는것이지 꼭 이런 문자를 사용해야 하는것은 아니다.

1-4. 자료형을 제한하는 <T extends 클래스>

  • 위에서 예시로 든 3D프린터의 경우 재료가 여러가지 있을 수 있지만,
    물은 재료가 될 수 없다고 가정하면 물의 타입은 사용할 수 없도록 제한을 둘 수 있다

아래에서 예시를 통해 알아보자!

💡 자료형을 제한하는 <T extends 클래스> 💡

public class GenericPrinter<T extends Material> {
	private T material;
}
  • 각각 PowderPlastic 클래스가 Material 을 상속 받는다고 했을 경우
  • 클래스 이름에 <T extends Material> 이라고 명시하여 사용할 수 있는 자료형에 제한을 둘 수 있다.
  • 만약 Materil 클래스를 상속받지 않은 Water 클래스를 사용하면 오류가 발생할 것이다.

📕2. 다이아몬드 연산자<>

  • 자바 7 부터는 제네릭 자료형의 클래스를 생성할 때 생성자에 사용하는 자료형을 명시하지 않을 수 있다

그동안 우리가 많이 사용한 ArrayList를 살펴보자!

💡 다이아몬드 연산자<> 💡

ArrayList<String> list = new ArrayList<>();
  • 여기에서 <>다이아몬드 연산자 라고 한다
  • 선언된 자료형을 보고 생략된 부분이 String 임을 컴파일러가 유추할 수 있기 때문에 생성 부분에서는 생략이 가능하다.
profile
개발 공부 중인 지현이

0개의 댓글