티스토리 뷰
클래스 설계할 때마다 제네릭 문법을 항상 까먹는다. 제네릭을 직접 사용할 일은 많지 않을 수 있다. 하지만 각종 라이브러리들에서 자주 쓰이므로 꼭 알아두는 것이 좋다. 그래서 정리해보는 제네릭 문법 포스팅.
사진출처: https://www.nisdon.com/2017/09/java-parametric-polymorphism-generics-udemy-course.html
제네릭(Generic)은 코드블럭 내부에서 쓸 자료형을 외부에서 지정하는 기법을 뜻한다. 여러가지 자료형을 허용하고 싶을 때 Object로 선언해버리면 깔끔하지만, 그렇게하면 원하지 않는 자료형이 입력되었을 때의 오류를 컴파일 시점에 잡아낼 수 없다.
1. Generic Class
클래스 내부에서 사용될 자료형을 지정하는 것이다. 대표적인 적용 예는 ArrayList가 있다. 사용 예를 보면 어떤 의미인지 알게 될듯.
class Foo<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } }
2. Generic Method
굳이 클래스에 제네릭을 선언하지 않고, 메소드에만 제네릭을 선언하는 방법도 있다. 이때 주의해야할 점이 있는데, 파라미터 타입 또는 리턴타입에 제네릭을 선언했으면 메소드의 리턴타입 앞에도 똑같이 선언해 주어야 한다. 글로 표현하니 애매하니까, 아래 예제를 함께 보면 좋다.
class Koo { // 두개 이상의 파라미터에도 각각 제네릭을 설정할 수 있다. public <N1, N2> Integer exampleOne(N1 t, N2 e) { return (Integer)t + (Integer)e; } // 먼저 나왔던 Foo 클래스를 리턴타입으로 정의한 메소드 public <String> Foo<String> exampleTwo() { return new Foo<>(); } }
3. Generic Interface
제네릭 클래스와 비슷하다. 클래스들이 인터페이스를 조금 더 유연하게 구현(implement)할 수 있다.
interface Roo <T1, T2, T3> { T1 implementThis(T1 t1); T2 implementThis(); T3 maintainGeneric(T3 t3); } // 제네릭에 어떤 자료형의 정의하느냐에 따라 유연하게 구현 가능. class roo <String, Integer, T3> implements Roo<String,Integer,T3> { @Override public String implementThis(String s) { return s; } @Override public Integer implementThis() { return null; } // 이렇게 제네릭을 유지하는 방법도 있음. @Override public T3 maintainGeneric(T3 t3) { return null; } }
4. Generic을 더 멋지게 써보자
지금까지 제네릭에 대해 어느정도 알아봤다. 그런데 Generic Interface를 제외하면 Object를 사용하는 것과 큰 차이가 없어보인다. 와일드카드를 사용하지 않아서 그렇다. 아까 소개했던 예제를 다시한 번 째려보자.
class Koo { public <N1, N2> Integer exampleOne(N1 t, N2 e) { // t와 e에 숫자가 아닌 것이 들어오면 오류 발생!! return (Integer)t + (Integer)e; } } public class Main { public static void main(String [] args) { Koo koo = new Koo(); int result = koo.exampleOne("abc","efg"); System.out.println(result); } }
exampleOne 메소드에는 사실상 아무거나 들어올 수 있는 상황인데, 메소드 내부에서는 Integer로 강제 형변환하고 있다. 위 소스코드는 오류 없이 멀쩡하게 실행시킬 수 있지만, 실행하면 아래와 같은 오류가 발생한다. (컴파일 시점에 오류를 잡아내지 못한다.)
개발자의 실수를 줄이기 위해서는 exampleOne의 파라미터 타입을 숫자의 형태로 제한할 필요가 있어보인다. 이렇게 하면 된다.
class Koo { public <N1 extends Integer, N2 extends Integer> Integer exampleOne(N1 t, N2 e) { return Integer.valueOf(t) + Integer.valueOf(e); } }
E - Element
K - Key
N - Number
T - Type
V - Value
-끝-
'IT > 개발팁' 카테고리의 다른 글
Spring에서 request와 response를 JSON format 으로 한번에 로깅하기 (0) | 2019.03.24 |
---|---|
[SpringBoot] .properties 파일의 상수를 Enum에 초기화하기 (0) | 2019.01.25 |
생성자의 매개변수가 많을 때 쓰면 좋다 - Builder Pattern(빌더 패턴) (0) | 2018.07.22 |
JavaScript와 객체지향 프로그래밍(OOP) 구현 (0) | 2018.03.15 |
JavaScript의 this 바인딩 (0) | 2018.02.25 |