새소식

TIL

[TIL] 240430 <자바> 제네릭

  • -

 

 

public class Generic<T> {  //제네릭 클래스 - 원시타입 (T : 타입변수)

    private T t;

	// 객체의 static 멤버에는 사용불가
    //  : 타입 변수는 인스턴스 변수로 간주되어서
    //    모든 객체에 동일하게 동작해야 하는 static 필드 특성상 사용불가
    public T get() {
        return this.t;
    }

    public void set(T t) {
        this.t = t;
    }

    public static void main(String[] args) {
		
        // 인스턴스를 만들기 위해 타입 변수에 들어갈 실제 변수의 값을 넣어줌(String)
        // 기본 타입 사용불가 -> 기본타입에 해당하는 Wrapper 클래스 사용할 것!
        Generic<String> stringGeneric = new Generic<>();
        
		// 타입 변수로 대체해뒀던 곳에 String이 들어가 있기 때문에 사용가능
        stringGeneric.set("Hello World");
				
        String tValueTurnOutWithString = stringGeneric.get();

        System.out.println(tValueTurnOutWithString);
    }
}

 

  • 제네릭 사용을 통하여 타입 언어에서 “중복되거나 필요 없는 코드를 줄이면서 타입 안정성을 해치지 않을 수 있음!"
  • 다수의 타입변수 사용 가능
  • 다형성(상속과 타입의 관계)는 그대로 적용되며, 와일드카드를 통해 제네릭의 제한을 구체적으로 정할 수 있음
    1. <? extends T> : T와 그 자손들만 사용 가능
    2. <? super T> : T와 그 조상들만 가능
    3. <?> : 제한 없음
  • 제네릭 배열은 생성불가

 

  • 제네릭은 클래스 또는 메서드에 사용가능
    • 제네릭 클래스 (원시 타입)
      • 클래스 이름 뒤에 <> 문법 안에 들어가야 할 타입 변수를 지정.
      • 선언해둔 타입변수는 해당 클래스 내에서 특정한 타입이 들어갈 자리에 대신 들어갈 수 있음
      • 제네릭을 통해 구현한 클래스를 사용 시, 인스턴스를 만들기 위해서 타입 변수에 들어갈 실제 변수의 값을 넣어줘야함
      • 객체의 static 멤버에 사용불가
        (타입 변수는 인스턴스 변수로 간주되기 때문에, 모든 객체에 동일하게 동작해야하는 static필드특성상 사용불가)


    • 메서드를 스코프로 제네릭을 별도로 선언가능
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }

                - 반환타입 앞에 <> 제네릭 사용시, 해당메서드에만 적용되는 제네릭 타입변수 선언 가능

                - 타입변수를 클래스 내부의 인스턴스 변수 취급하기 때문에
                  제네릭 클래스의 타입 변수를 static 메서드에서는 사용할 수 없지만,
                  제네릭 메서드의 제네릭 타입변수는 해당 메소드에만 적용되기 때문에
                  메소드 하나를 기준으로 선언하고 사용가능

                - 같은 이름의 변수를 사용했더라도 제네릭 메소드의 타입변수와 제네릭 클래스의 타입변수는 다르다

 

 

★ 제네릭 활용한 클래스/메서드 사용 시
     제네릭의 타입 인수로는 기본 타입(primitive type) 사용 불가!
     대신 기본 타입에 해당하는 Wrapper 클래스를 사용해야함

 

 

 

Collection 다시 보기

출처 : https://www.javatpoint.com/collections-in-java

  1. Collection(집합적 자료)라는 속성은 Iterable(순회 가능)이라는 속성을 상속받고 있습니다.
  2. Collection의 하위 ‘속성’으로는 List, Queue, Set 등이 있습니다.

  3. List의 실제 구현체들은 Arr, Linked, Vector, Stack들이 있습니다.

  4. <상황에 맞는 적절한 자료구조를 택하기>
    (1) 인터페이스, 즉 속성에서는 코드를 보고 “어떠한 일을 해주는지” 알수있음
    (2) 클래스, 즉 실제 구현체에는 위의 어떠한 일을 “어떻게 해주는지” 알수있음

    → 즉 내가 지금 데이터를 다루는데 필요한 기능을 어떠한 것들이 해주는지는 인터페이스에서 찾고,
        어떠한 방식으로 해줘야 유리할지는 실제 구현체를 보고 판단하면됨
  5. 가장 좋은 방법은, 자주 코드를 접하며 어떠한 상황에 어떠한 자료구조를 주로 사용하는지 보고,
    주로 사용하는 구현체들은 실제 명세를 봐서 어떠한 특징이 있는지 잘 알아두는 것이 중요함!

 

 

 

제네릭과 함께 List<E> 코드 살펴보기

// 실제 java.util의 List 코드
public interface List<E> extends Collection<E> {
		int size();
        boolean isEmpty();
		...
		boolean addAll(Collection<? extends E> c);
		boolean add(E e);
		...
}
  • List 인터페이스는 제네릭 인터페이스
  • 타입 변수 E : 리스트에 저장되는 데이터의 타입
  • 실제로 List 속성을 가지는 구현체들에 있는 add() 메소드 같은 경우, 리스트 인터페이스에 지정한 E라는 타입을 추가하는 데 사용됨
  • 메서드의 인자에 두가지 조건을 만족하는 뭔가를 넘겨받은 경우에만, addAll로 일괄적으로 추가가능
    1. Collection 타입에 속하는 것,
    2. List의 타입 변수 E의 자손 클래스를 원소로 가지고 있을 것

 

 

 

 

(참고)  Wrapper 객체

 

  1.  char, int, long과 같은 것들은 실제로 “값” 이상의 의의를 가지지 않는 경우가 더 많기 때문에, 비용이 많이 드는 객체로 다루는 대신 원시 타입 값 그대로를 사용함 (값 이상의 의의를 가지지 않는 경우에는 성능상의 이유로)
  2. 객체 특성을 이용한 추상적인 기능을 사용하려거나, 기본형 값 대신 객체로 저장해야 하거나, 객체로의 “기능”이 필요할 때 우리는 원시형 값들을 잠시 객체로 만들어 사용가능 → Wrapper Class
  3. 기본값을 객체화하는 것을 '박싱'이라고 하며, 객체를 다시 기본값으로 만드는 것을 '언박싱'이라고함
    (오토 박싱, 오토 언박싱도 존재)
  4. 박싱해서 객체화된 원시 값들은 이제 클래스처럼 구현되어 있는 메소드들을 자유롭게 이용가능, 객체만 할 수 있는 것들을 할수있게됨
Integer num = new Integer(17);  // Boxing
int n = num.intValue(); // UnBoxing

Character ch = 'X'; // AutoBoxing
char c = ch; // AutoUnBoxing

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.