본문 바로가기

Java/이론

제네릭(Generic)

정의 : generic 타입 및 메소드를 정의하고 사용할 수 있는 언어적 특성

List<Integer> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

 

위와 같이 " <> " 부분이 클래스 타입이 명시된 부분이다.

이것을 제네릭(Generic)이라고 부르며, 제네릭 파라미터는 꺽쇠안에 포함하여 전달한다.

 

● 파라미터 타입이나 리턴 타입에 대한 정의를 외부로 미룬다.

● 타입에 대해 유연성과 안전성을 확보한다.

● 런타임 환경에 아무런 영향이 없는 컴파일 시점의 전처리 기술

 

※ 런타임 에러는 프로그램이 작동 중에 에러가 나는 것이고, 컴파일은 프로그램 작동 전에 컴파일러가

코드 해석 중에 아예 해석을 못하겠다고 포기하고 에러내는 것이다. 그러므로 프로그램이 실행되고

작동되는 것보다 굳이 따지자면 컴파일 에러가 차라리 낫다.

 

사용법은 다음과 같다.● 클래스, 인터페이스 또는 메소드에 선언 가능● 동시에 여러 타입을 선언 가능하다.● 타입에 대하여 유연한 처리를 가능하게 한다.● 제네릭 선언 및 정의 시에 타입의 상속 관계를 지정할 수 있다.

 

관습적으로 통용하는 것이지 타입 파라미터는 정해진 것이 없다.개인이 클래스를 만들어서 해도 무관하다.

 

 

제네릭 클래스

class ExClassGeneric<T> {
    private T t;

    public void setT(T t) {
        this.t = t;
    }
			
    public T getT() {
        return t;
    }
}

 

→ 실제 클래스가 사용될 때 ExClassGeneric exGeneric = new ExClassGeneric<>(); 

    이런 식으로 구체적인 타입을 지정하면서 사용하면 타입 변환을 최소화 시킬 수 있다.

 

제네릭 인터페이스

interface ExInterfaceGeneric<T> {
    T example();
}

class ExGeneric implements ExInterfaceGeneric<String> {

    @Override
    public String example() {
        return null;
    }
}

 

→ 인터페이스로 타입을 미리 지정하지 않았다가 implements하면서 String으로 변환하는 코드이다.

 

제네릭 메소드

class People<T,M>{
    private T name;
    private M age;
	
    People(T name, M age){
        this.name = name;
        this.age = age;
    }

    public T getName() {
        return name;
    }
    public void setName(T name) {
        this.name = name;
    }
    public M getAge() {
        return age;
    }
    public void setAge(M age) {
        this.age = age;
    }
	
    //Generic Mothod
    public static<T,V> boolean compare(People<T,V>p1, People<T,V>p2) {
        boolean nameCompare = p1.getName().equals(p2.getName());
        boolean ageCompare =p1.getAge().equals(p2.getAge());
        return nameCompare && ageCompare;
    }
}

public class ExGeneric {
    public static void main(String []args){
        //타입 파라미터 지정
        People<String,Integer> p1 = new People<String,Integer>("Jack",20);
        //타입 파라미터 추정
        People<String,Integer> p2 = new People("Steve",30);
        //GenericMothod 호출
        boolean result = p1.compare(p1,p2);
        System.out.println(result);
    }
}

 

제네릭 메서드를 정의할 때는 리턴타입이 무엇인지와는 상관없이 제네릭 메서드라는 것을 컴파일러에게

    알려주어야 한다.

 

제네릭 와일드카드

public class Calc {
    public void printList(List<?> list) {
       for (Object obj : list) {
    	   System.out.println(obj + " ");  
       }
    }

    public int sum(List<? extends Number> list) {
      int sum = 0;
      for (Number i : list) {
    	  sum += i.doubleValue();  
      }
      return sum;
    }

   public List<? super Integer> addList(List<? super Integer> list) {
      for (int i = 1; i < 5; i++) {
    	 list.add(i); 
      }
      return list;
    }
}

 

와일드카드 타입에는 세 가지 형태의 물음표(?) 키워드가 표현된다.

 

● 제네릭타입<?> : 타입 파라미터를 대치하는 것으로 모든 클래스가 인터페이스타입이 올 수 있다.

● 제네릭타입<? extends 상위타입>  : 와일드카드의 범위를 특정 객체의 하위 클래스만 올 수 있다.

● 제네릭타입<? super 하위타입>  : 와일드 카드의 범위를 특정 객체의 상위 클래스만 올 수 있다.

 

'Java > 이론' 카테고리의 다른 글

[ Java ] vs [ SQL ]  (0) 2024.07.05
Javax → Jakarta  (0) 2024.06.28
String, StringBuilder, StringBuffer  (0) 2024.06.25
암호화  (0) 2024.06.23
Java Version(8, 11, 17)  (0) 2024.06.22