# 자바 제네릭

* **제네릭**
    
    * 다양한 타입의 객체를 다루는 메서드
        
    * 컬렉션 클래스에서 컴파일 시에 타입을 체크한다
        
        * 컴파일 타입에 타입 파라미터들이 대입된 타입으로 대체됨
            
    * 미리 사용할 타입을 명시해서 형 변환을 하지 않아도 되게 함
        
        * **객체의 타입에 대한 안전성 향상 및 형 변환의 번거로움 감소**
            
        * **비슷한 기능을 지원하는 경우 코드의 재사용성이 높아짐**
            
    * 타입 파라미터
        
        * 단순히 임의의 참조형 타입을 말함
            
        * Privitive Type은 사용할 수 없고 Wrapper Type을 포함한 Reference Type(참조 타입)을 사용해야 한다
            
        * T: reference Type
            
        * E: Element
            
        * K: Key
            
        * V: Value
            
        * N: Number
            
    * 제네릭 와일드 카드(타입 파라미터 제한)
        
        * &lt;?&gt;
            
            * &lt;? extends Object&gt;와 같은 의미
                
            * 타입에 제한이 없음(Object)
                
        * &lt;? extends T&gt;
            
            * T 또는 T를 상속받은 타입들만 사용 가능
                
        * &lt;? super T&gt;
            
            * T 또는 T의 조상 타입만 사용 가능
                
    * 제네릭 클래스, 제네릭 메서드 예시
        
        ```java
        // 제네릭 클래스
        class ClassName<E> {
        	
        	private E element;	// 제네릭 타입 변수
        	
        	void set(E element) {	// 제네릭 파라미터 메소드
        		this.element = element;
        	}
        	
        	E get() {	// 제네릭 타입 반환 메소드 
        		return element;
        	}
        	
            //아래 메서드의 T타입은 제네릭 클래스의 타입과 다른 독립적인 타입이다.
            //E로 이름이 같아도 다른 독립적인 타입
        	<T> T genericMethod(T o) {	// 제네릭 메소드
        		return o;
        	}
         
        }
         
        public class Main {
        	public static void main(String[] args) {
        		
        		ClassName<String> a = new ClassName<String>();
        		ClassName<Integer> b = new ClassName<Integer>();
        		
        		a.set("10");
        		b.set(10);
        	
        		System.out.println("a data : " + a.get());
        		// 반환된 변수의 타입 출력 
        		System.out.println("a E Type : " + a.get().getClass().getName());
        		
        		System.out.println();
        		System.out.println("b data : " + b.get());
        		// 반환된 변수의 타입 출력 
        		System.out.println("b E Type : " + b.get().getClass().getName());
        		System.out.println();
        		
        		// 제네릭 메소드 Integer
        		System.out.println("<T> returnType : " + a.genericMethod(3).getClass().getName());
        		
        		// 제네릭 메소드 String
        		System.out.println("<T> returnType : " + a.genericMethod("ABCD").getClass().getName());
        		
        		// 제네릭 메소드 ClassName b
        		System.out.println("<T> returnType : " + a.genericMethod(b).getClass().getName());
        	}
        }
        ```
        
        * 실행결과
            
            ![](https://blog.kakaocdn.net/dn/czs31x/btq8zxKbZ05/ftKMjz295wRPDhCSa2UZtK/img.png align="left")
            
    * **메서드에서 별도로 독립적으로 제네릭 유형을 선언하는 이유**
        
        * 정적 메서드로 선언할 때 필요하다
            
        * 제네릭은 new 생성자로 클래스 객체를 생성하고 &lt;&gt; 괄호 사이에 파라미터로 넘겨준 타입으로 지정이 된다
            
        * 하지만 static은 실행전 메모리에 올라가야 하므로 객체가 생성되기 전에 이미 타입을 정해줘야 한다
            
* 참고 자료
    
    * [자바 \[JAVA\] - 제네릭(Generic)의 이해](https://st-lab.tistory.com/153)
