지네릭스의 전반적 개념(1)

2022. 5. 11. 10:57·자바/지네릭스

1. 지네릭스란?

- 지네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 대해서 타입 체크를 해주는 기능을 말한다. 

 

- 그러므로, 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄어든다.

 

- 타입 안정성을 높이는 것은 의도치 않은 타입의 객체가 저장되는 것을 막고, 저장된 객체를 꺼내올 때 원래의

타입과 다른 타입으로 잘못 형변환되어 발생할 수 있는 오류를 줄여준다는 뜻이다.

 

- 예를 들면, ArrayList 컬렉션 클래스에 다양한 객체를 담을 수 있지만 한 종류의 객체를 담는 경우가 많다. 그런데도

꺼낼 때 마다 타입 체킹을 하거나 사용자가 원하지 않는 종류의 객체를 저장하는 것을 막지 못하는 불편한 점이 있다.

그러한 것을 해결할 수 있는 것이 바로 '지네릭스'이다.

 

 

- 아래는 지네릭스를 적용 전과 후를 보여준다.

적용 전 적용 후
class Box{
     Object item;
     
     void setItem(Object item) { this. item = item; }
     Object getItem(){ return item; }
}
class Box<T>{
     T item;
     
     void setItem(T item) { this. item = item; }
     T getItem(){ return item; }
}

 

( 이때, Box<T>에서 T를 '타입 변수' 라고 한다. )

( T를 무조건 쓸 필요 없으며, K이나 V 또는 알파벳 어느 것이든 쓰면 된다. )

( 되도록이면 의미 있게 쓰이도록 하자. ex) Map<K,V> )

 

 

( 그래서 위 적용 후의 Box 클래스의 생성자는 아래와 같이 생성하면 된다. )

Box<String> b = new Box<String>();
// T 대신 String으로 타입 지정

// b.setItem(new Object());
// String 이외 다른 타입 불가능 에러

b.setItem("ABC");
// String이므로 정상

String item = b.getItem();
// 지네릭스 전에는
// String item = (String) b.getItem()
// 이였음.

 

 

( 지네릭스는 JDK 1.5에서 처음 도입된 것이기 때문에, 이전 코드와 호환을 위해 생성자를 생성할 때 타입 변수에

타입을 지정하지 않아도 컴파일이 가능하다. )

( 그러나, 아래와 같이 경고가 발생하게 된다. )

Box b = new Box();
// T는 Object로 간주. 정상

b.setItem("ABC")
// 경고발생

b.setItem(new Object());
// 경고발생

 

 

 

 

2. 지네릭스의 용어

class Box<T>{}

 

( 여기서 Box<T>는 지네릭스 클래스라고 부른다. T의 Box라고도 불린다. )

( T는 Box<T>의 타입변수 또는 타입 매개변수라 부른다. )

( Box는 원시타입이라고 부른다. )

 

 

Box<String> b = new Box<String>();

 

( <String>을 대입된 타입 즉, 매개변수화된 타입이라고 부른다. )

( Box<String>은 지네릭 타입 호출이라고 부른다. )

 

 

 

 

3. 지네릭스의 제한

 

- 지네릭스에서 불가능한 것이 아래와 같이 두 가지가 있다.

(1) 모든 객체에 대해 동일하게 동작해야하는 static 멤버에 타입 변수 T를 사용할 수 없다.

: 이유는 타입 문자 T는 인스턴스 변수로 간주하며, static 멤버는 항상 대입된 타입의 종류에 관계없이

동일해야 하기 때문이다.

 

 

(2) 지네릭 타입의 배열을 생성하는 것도 허용되지 않는다. 배열 타입의 선언은 가능하지만, 'new T[10];'

같은 것은 불가능하다.

: 이유는 new 연산자 때문인데, 이 연산자는 컴피일 시점에 타입 T가 뭔지 정확히 알아야 한다.

: 그러나, new T[10]을 클래스 로드하는 과정에서 선언했기 때문에 불가능하다.

 

( 꼭 지네릭 배열을 생성해야할 필요가 있을 때는, new 연산자 대신 'Reflection API'의 newInstance()와 같이

동적으로 객체를 생성하는 메서드로 배열을 생성하거나, 아래와 같이 생성한다. )

 

 

 

 

4. 지네릭 클래스의 객체 생성과 사용

- Box<T> 같은 지네릭 클래스가 있다고 가정해보자. 

 

( 그렇다면, 참조변수와 생성자에 대입된 타입이 일치해야 한다. 그렇지 않을 경우 에러가 발생한다. )

( 또한 상속 관계에서도 에러가 발생한다. 아래의 코드를 보고 이해하자. )

Box<Apple> appleBox = new Box<Apple>();
// 가능

Box<Apple> appleBox = new Box<Grape>();
// 에러

Box<Fruit> appleBox = new Box<Apple>();
// 에러

 

 

( 그러나, 아래와 같이 두 지네릭 클래스의 타입이 상속관계에 있고, 대입된 타입이 같은 것은 가능하다. )

( 다형성이 가능하다는 것이다. )

Box<Apple> appleBox = new FruitBox<Apple>();
// 가능. 다형성

 

 

( 또한 JDK 1.7부터 추정이 가능한 경우 타입을 생략할 수 있게 되었다. )

( 아래와 같이 두 코드는 동일하게 인식한다. )

Box<Apple> appleBox = new Box<Apple>();
// 위 아래 동일한 코드
Box<Apple> appleBox = new Box<>();

 

 

( 조심해야 할 것은 아래와 같이 자신이 대입한 타입에만 객체를 생성할 수 있다. )

Box<Apple> appleBox = new Box<Apple>();
appleBox.add(new Apple());
// 정상

appleBox.add(new Grape());
// 에러 발생

 

 

( 그러나 타입 T가 자신의 조상인 Fruit인 경우, ArrayList의 void add(Fruit item) 메서드에서는 아래와 같이

정상적으로 컴파일 할 수 있다. )

Box<Fruit> fruitBox = new Box<Fruit>
fruitBox.add(new Fruit());
// 가능

fruitBox.add(new Apple());
// 가능

 

 

 

 

4-1. 지네릭 클래스의 객체 생성과 사용을 이해하기 위한 예제(1)

: 위에서 봤던 개념을 적용한 예제이다.

 

import java.util.ArrayList;

public class Exercise001 {	
	public static void main(String[] args){
		Box<Fruit> fruitBox = new Box<Fruit>();
		Box<Apple> appleBox = new Box<Apple>();
		Box<Toy>   toyBox   = new Box<Toy>();
//		Box<Grape> grapeBox = new Box<Apple>(); // 에러. 타입 불일치

		fruitBox.add(new Fruit());
		fruitBox.add(new Apple()); // OK. void add(Fruit item)

		appleBox.add(new Apple());
		appleBox.add(new Apple());
//		appleBox.add(new Toy()); // 에러. Box<Apple>에는 Apple만 담을 수 있음

		toyBox.add(new Toy());
//		toyBox.add(new Apple()); // 에러. Box<Toy>에는 Apple을 담을 수 없음

		System.out.println(fruitBox);
		System.out.println(appleBox);
		System.out.println(toyBox);
	}
}

class Box<T> {
	ArrayList<T> list = new ArrayList<T>();
	void add(T item)  { list.add(item); }
	T get(int i)      { return list.get(i); }
	int size() { return list.size(); }
	public String toString() { return list.toString();}
}

class Fruit				  { public String toString() { return "Fruit";}}
class Apple extends Fruit { public String toString() { return "Apple";}}
class Grape extends Fruit { public String toString() { return "Grape";}}
class Toy		          { public String toString() { return "Toy"  ;}}

 

 

 

 

다음장

지네릭스의 전반적 개념(2) (tistory.com)

 

지네릭스의 전반적 개념(2)

 

kind-coding.tistory.com

 

저작자표시 (새창열림)

'자바 > 지네릭스' 카테고리의 다른 글

지네릭 타입의 형변환과 제거  (0) 2022.05.16
지네릭 메서드  (0) 2022.05.13
와일드 카드  (0) 2022.05.12
지네릭스의 전반적 개념(2)  (0) 2022.05.11
'자바/지네릭스' 카테고리의 다른 글
  • 지네릭 타입의 형변환과 제거
  • 지네릭 메서드
  • 와일드 카드
  • 지네릭스의 전반적 개념(2)
백_곰
백_곰
  • 백_곰
    친절한 코딩
    백_곰
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 알고리즘 (with JAVA)
        • 기본 알고리즘
        • 완전 탐색
        • 분할 정복 알고리즘
        • 동적 계획법
        • 탐욕법
        • 코딩 테스트 기출 문제
        • 코드트리 조별과제
      • 백준 (with JAVA)
        • 완전 탐색
        • 분할 정복
        • 그 외
      • 자바
        • 개발 환경 구축하기
        • 팁
        • 기본적인 개념
        • 컬렉션 프레임워크
        • 프로세스와 쓰레드
        • 지네릭스
        • 람다식
        • 스트림
        • 입출력 IO
        • 네트워킹
        • 열거형(enums)
        • java.lang 패키지
        • java.time 패키지
        • 유용한 클래스들
        • 형식화 클래스들
      • 안드로이드 with 자바
        • 응용 문제들
        • 자잘한 문제들
        • 오류 보고서
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      선택 정렬
      코딩트리조별과제
      snail
      코딩테스트
      안드로이드 스튜디오
      안정 정렬
      outputstream
      코드트리
      java.time 패키지
      ServerSocket
      Collections Framework
      불안정 정렬
      java.lang패키지
      역직렬화
      중간연산
      소켓 프로그래밍
      제자리 정렬
      InputStream
      알고스팟
      자바 개념
      file
      스트림
      다형성
      유용한 클래스
      람다식
      serializable
      TCP 소켓 프로그래밍
      문자 기반 스트림
      map()
      Arrays
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    백_곰
    지네릭스의 전반적 개념(1)
    상단으로

    티스토리툴바