Java 기본 (7) - Generic(제네릭)

김정욱·2021년 6월 18일
0

Java

목록 보기
7/13
post-thumbnail

ref :
https://st-lab.tistory.com/153
https://yaboong.github.io/java/2019/01/19/java-generics-1/

개념

  • 제네릭스다양한 타입의 객체들을 다루는 메서드컬렉션 클래스컴파일 시의 타입체크를 해주는 기능이다
    -자바의 정석
  • 제네릭(Generic)은 클래스 내부에서 사용할 데이터 타입외부에서 지정하는 기법을 의미
    -생활코딩
  • 제네릭다양한 버그컴파일 타임에 발견할 수 있도록 코드에 안정성을 더한다
    -Oracle Javadoc

표기

  • 정해져 있지는 않지만, 일반적으로 위의 의미로 사용
  • 타입으로는 반드시 참조 타입(Reference Type)만 올 수 있음
    (primitive type불가능)

클래스 / 인터페이스

기본 선언

public class ClassName <T> { ... }
public Interface InterfaceName <T> { ... }

제네릭 클래스 사용

  • <Type> 을 통해서 직접 타입(Type)을 명시해주어야 한다
public class ClassName <T, K> { ... }

public class Main {
	public static void main(String[] args) {
		ClassName<String, Integer> a = new ClassName<String, Integer>();
	}
}

메소드 (제네릭 메소드)

[ 개념 ]

  • 메소드선언 부에 적은 제네릭으로, 리턴타입파라미터 타입정해지는 메소드
  • 반환타입 / 파라미터 하나제네릭이라고 제네릭 메소드가 아님

[ 특징 ]

  • 컴파일러에게 타입을 미리 알려주기 때문static 으로 선언하여 사용 가능
  • 제네릭 메소드타입 파라미터(Type Parameter)제네릭 클래스별도로 취급
    : 제네릭 클래스<T> 를 사용하고, 제네릭 메서드<T> 를 사용해도 서로 다름!

[ 선언 방법 ]

  • 반환(return) 타입 제네릭에 대한 선언
  • 컴파일러에게 제네릭 메서드라는 것을 알려주기 위해 리턴타입을 정의하기 전제네릭 타입에 대한 정의를 반드시 적어야 함

[ 호출 방법 ]

  • 명시적으로 호출할 때 타입을 지정하는 방법 --> 권장
  • 타입을 지정하지 않고, 컴파일러에게 추론하도록 하는 방법
public class Util {

    public static <T> Box<T> boxing(T t) {
        Box<T> box = new Box<T>();
        box.setT(t);
        return box;
    } 
 }


 public class Main {
    public static void main(String[] args) {
         /* 명시적 호출 */
        Box<Integer> box1 = Util.<Integer>boxing(100);

         /* 컴파일러 추론 호출 */
        Box<String> box2 = Util.boxing("암묵적호출");
    }
}

한정적 타입 매개변수(Bounded Type Parameter)

[ 개념 ]

  • 제네릭으로 사용타입 파라미터범위한정적으로 제한하는 방법
  • 한정적으로 범위를 좁히는데 3가지 방법이 존재
    • extends
    • super
    • ? (와일드 카드)

[ extends ]

  • 표기
    • <? extends T>
  • 설명
    • TT의 자손 타입가능
    • 상한 경계 라고 부름
    • 인터페이스클래스추상클래스나 모두 extends 키워드 사용
  • 예시
/* T는 Comparable 인터페이스의 서브클래스들로만 정의할 수 있도록 제한 */
public class GenericArrayList<T extends Comparable<T>>
// Comparable를 구현한 클래스들은 비교 가능하게 됨

[ super ]

  • 표기
    • <? super T>
  • 설명
    • TT의 부모(조상) 타입가능
    • 하한 경계 라고 부름
    • 인터페이스클래스추상클래스나 모두 super 키워드 사용
  • 예시
/* T는 Number의 상위 클래스만 타입으로 가지도록 제한 */
public class MyClass<T super Number>

[ ? ] (와일드 카드)

  • 표기
    • <?>
  • 설명
    • <? extends Object>의미가 동일
    • 'unbounded wildcard' 라고 부름
    • ? 자리에는 모든 참조 타입(reference type) 이 올 수 있다
  • 주 사용 용도
    • Object Class에서 지원하는 기능사용하는 메서드구현할 때
      • 매개변수로 List<T>List<Object> 는 다르게 동작
      • List<T> : ObjectObject를 상속한 모든 클래스 객체대신 가능
      • List<Object> : Object 타입객체만 가지는 List
      • 즉, 제네릭에서는 상속관계가 적용되지 않아서 Object만 받을 수 있게 됨
        (만약 List<Object> 인데 List<Integer> 호출하면 오류가 발생!!)
    • Type Parameter를 신경쓰지 않아도 되는 메서드를 구현할 때
      • 특정 타입이 정해져 있지 않기 때문에 반드시 readOnly 로 사용해야 함
      • 특정 Type Parameter를 신경쓰지 않아도 즉, 변경하지 않고 읽기만 하면 사용 가능
  • 예시
/* T는 모든 참조 타입이 올 수 있음 */
public class MyClass(List<?> list){
...
}

제네릭을 사용할 수 없는경우

  • new 키워드사용 불가능
    • new 연산자heap 영역충분한 공간이 있는지 확인 후 할당을 함
    • 충분한 공간을 알기 위해서타입(Type)알아야 한다
    • 컴파일 시점new T[5] 같은 예시는 타입을 알 수 없으니 객체를 생성할 수 없다!
  • static 변수에 사용 불가능
    • static 변수인스턴스에 종속되지 않는 클래스 변수로, 모든 인스턴스공통된 저장공간을 공유하는 변수(값 자체가 공유됨)
    • 하나로 공유되는 공유변수생성되는 인스턴스에 따라 타입이 바뀐다는 것 자체가 말이 안됨
    • static 메서드사용 가능

장점

  • 불필요한 타입 변환 최소화
    • 제네릭은 클래스를 설계할 때 구체적인 타입을 명시하지 않고, 타입 파라미터(T)로 대체했다가 실제 클래스를 사용할 때 구체적인 타입(String, Integer 등)지정함으로써 타입 변환최소화
  • 타입 안정성 보장 (with. 컴파일 오류)
    • 컴파일 시점타입을 검사해서 오류를 발생시킨다
    • 런타임 오류가 아닌, 컴파일 오류발생시키는 것은 개발자에게 행복한 일
  • 코드의 재사용성 향상
profile
Developer & PhotoGrapher

0개의 댓글