Java : Generic

Jamangstangs·2022년 2월 22일
0

Roadmap

목록 보기
3/8
post-thumbnail

Java : Generic

Generic

  • 정의 : 클래스 내부에서 사용할 데이터의 Type을 외부에서 지정하는 기법을 의미한다.

    • 매개변수 : 변수에 들어갈 값과 관련된 값
    • Type Parameter -> 타입으로 쓰일 값을 매개변수화 한다.
    • Instance 생성할 때 T라는 Type Parameter 값이 전달되면서 Type이 정해진다.
  • 예제 코드를 보자.

    public class Animal<T> {
      // 현재 data 필드의 Type을 명시적으로 선언하지 않음
      public T data;
    }
    
    // 이때는, data의 Type이 String으로 정해진다. 
    // A1.data의 Type -> String
    Animal<String> A1 = new Animal<String>();
    
    // 이때는, data의 Type이 StringBuilder로 정해진다.
    // A2.data의 Type -> StringBuilder
    Animal<StringBuilder> A2 = new Animal<StringBuilder>():
    • Class를 생성할 때, T라는 Type Parameter에 Type을 전달할때 Type이 정해진다.

복수의 Generic

  • 여러 개의 Generic이 필요한 경우는 어떻게 처리할지 알아보자.

  • Reference Data Type만 Generic에서만 사용이 가능하다.

  • Primitive Data Type에 대해서는 사용이 불가능

    class PersonInfo{
      public int rank;
    	PersonInfo(int rank) { this.rank = rank;}
    }
    
    class Person<T,S>{
      public T info;
      public S id;
      Person(T info, S id){
        this.info = info;
        this.id = id;
      }
    }
    
    public class Main{
      public static void main(String[] args){
    		PersonInfo pi = new PersonInfo(1);
        Interger i = new Integer(2);
        // 이와 같이 기본 데이터 타입은 적용이 불가능하므로, 참조형 데이터 타입으로 바꿔줄 필요가 있다. 
    		Person<PersonInfo, Interger> p1 = new Person<PersonInfo, Interger>(pi,i);
      }
    }

Generic 생략

/* -- Class 구현 부분 -- */
class PersonInfo{
  public int rank;
	PersonInfo(int rank) { this.rank = rank;}
}

class Person<T,S>{
  public T info;
  public S id;
  Person(T info, S id){
    this.info = info;
    this.id = id;
  }
}


public class Main{
  public static void main(String[] args){
		PersonInfo pi = new PersonInfo(1);
    Interger i = new Integer(2);
    /* -- 이전 파트에서 Generic 생략하지 않고 사용한 부분 -- */
		Person<PersonInfo, Interger> p1 = new Person<PersonInfo, Interger>(pi,i);
    /* -- Generic 생략한 부분 -- */
    Person p1 = new Person(pi,i);
  }
}
  • pi, i -> Argument를 생성자에서 전달하면

    Person(T info, S id)

    여기서 info 라는 부분은 pi가 PersonInfo라는 타입으로 들어왔기 때문에 추측이 가능하고

    여기서 id라는 부분은 i가 Interger라는 타입으로 들어왔기 때문에 추측이 가능하다.

  • 따라서, 위와 같은 이유로 Generic을 생략하고 생성자를 호출할 수 있다.

Generic Method

  • Class 단위에서 말고 Method 단위에서도 Generic을 사용할 수 있다.
// 기존의 Person class에 Generic Method를 선언해보겠다. 
class Person<T,S>{
  public T info;
  public S id;
  Person(T info, S id){
    this.info = info;
    this.id = id;
  }
	public <U> void printInfo(U info){
    System.out.println(info)
  }
}

public class Main{
  public static void main(String[] args){
		PersonInfo pi = new PersonInfo(1);
    Interger i = new Integer(2);
    Person p1 = new Person(pi,i);
    /* -- Generic 생략하지 않고 사용한 부분 -- */
		p1.<PersonInfo>printInfo(pi);
    /* -- Generic 생략한 부분 -- */
		p1.printInfo(pi);
    
  }
}
  • 메소드의 Generic도 생략이 가능하다.

Generic 제한

  • 지금까지 Generic을 사용하면 참조형 데이터 타입이라면 어떤 것이든 들어올 수 가 있었다. (기본형 데이터 타입은 애초에 안됨)
  • 그렇다면, 특정 데이터 타입을 제한할 수 있는 방법은 없을까?
    1. extends -> 상속으로 제한한다.
    2. Implements -> 구현으로 제한한다.
// 부모 클래스
abstract class Info{
  public abstract int getLevel();
}

// 자식 클래스
class EmployeeInfo extends Info{
  public int rank;
  EmployeeInfo(int rank) { this.rank = rank; }
  pubic int getLevel(){
    return this.rank;
  }
}

// extends -> 상속으로 제한시키는 방법
class Person<T extends Info>{
  public T info;
	Person(T info) { this.info = info; }
}

// 인터페이스
interface Info{
	int getLevel();
}

// 구현 클래스
class EmployeeInfo implements Info{
  public int rank;
  EmployeeInfo(int rank) { this.rank = rank;}
  public int getLevel(){
    return this.rank;
  }
}

// implements -> 구현으로 제한시키는 방법, 하지만, extends를 써야한다. 
class Person<T extends Info>{
	public T info;
  Person(T info) { this.info = info; }
}

Type Parameter 배열

  • 타입 파라미터로 배열을 초기화 할 수 없다.
  • 이를 위해서는, Object의 배열로 초기화 하고 Type Casting이 필요하다.
public class Test<T> {
	// 이렇게 타입 클래스로 배열을 선언은 가능하다. 
	private T[] array;
    // 하지만, 아래와 같이 초기화 하면 작동하지 않는다ㅡ. 
    array = new T[10];
    // 초기화를 위해서는 Object배열로 초기화가 필요하다. 
    array = (T[]) new Object[10];
}

WildCard Type

  • <?> : 모든 클래스나 인터페이스 타입이 올 수 있다.
  • <? extends UpperType> : 상위 클래스로 제한한 타입이 올 수 있다.
  • <? super LowerType> : 하위 클래스로 제한한 타입이 올 수 있다.
profile
자망스탕스

0개의 댓글