본문 바로가기
Programming Languages/Java

Chapter 23. 제네릭

by 더 이프 2023. 1. 17.
728x90

목차


    1. 제네릭

    ■ 제네릭이란?

    • 데이터의 타입을 일반화하는 것을 의미
    • 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법
    • 데이터 타입을 미리 지정할 때 <>를 사용하여 지정
    • 제네릭은 일반 자료형 사용 불가
    • 객체의 타입 안정성을 높일 수 있음
    • 제네릭의 타입 변수에 extends 키워드를 사용하여 특정 타입만을 사용하도록 제한 가능

    ■ 와일드카드

    • 와일드카드란 이름에 제한을 두지 않음을 표현하는데 사용
    • 물음표(?) 기호를 사용하여 와일드카드를 사용
    • 와일드카드는 생성 시 자동으로 자료형을 가져옴

     

    2. 예시

    ■ TestData

    package j18_제네릭;
    
    public class TestData<T, E> {
        // int 자료형을 클래스화 시켜놓은 것 wrapper Class(래퍼 클래스)
        // 제네릭은 일반 자료형을 쓸 수 없음
    	private T data1;
    	private E data2; 
    
    	public TestData(T data1, E data2) {
    		this.data1 = data1;
    		this.data2 = data2;
    	}
    
    	@Override
    	public String toString() {
    		return "TestData [data1=" + data1 + ", data2=" + data2 + "]";
    	}
    	
    	
    	
    }

    ■ CMRespDto

    package j18_제네릭;
    
    // Commit Message Response Data Transfer Object
    // 클라이언트가 서버에게 요청을 날리면 동일한 형식으로 응답해주는 응답 인터페이스
    public class CMRespDto<T> {
    
    	private int code;
    	private String message;
    	private T data;
    
    	public CMRespDto(int code, String message, T data) {
    		super();
    		this.code = code;
    		this.message = message;
    		this.data = data;
    	}
    
    	@Override
    	public String toString() {
    		return "CMRespDto [code=" + code + ", message=" + message + ", data=" + data + "]";
    	}
    
    }

    ■ Main

    package j18_제네릭;
    
    import j17_스태틱.싱글톤.C;
    
    public class Main {
    
    	public static void main(String[] args) {
    
    		// ?는 생성 시 자동으로 자료형을 가져옴
    		// 가능한 자료형을 명시하는 것이 좋음 
    		TestData<?, ?> td = new TestData<>("김준일", 30);
    		
    		TestData<String, Integer> td = new TestData<String, Integer>("김준일", 30);
    		TestData<String, Double> td2 = new TestData<String, Double>("junil", 100.05); // 생성될 때 타입 결정
    		System.out.println(td);
    		System.out.println(td2);
    
    		// generic 안에 generic 타입의 자료형을 가져올 수 있음
    		// data에 td의 자료형인 TestData<String, Integer>를 넣음
    		CMRespDto<TestData<String, Integer>> cm =
    				new CMRespDto<TestData<String, Integer>>(200, "성공", td);
    		
    		// td의 자료형을 자동으로 가져옴
    //		CMRespDto<TestData<?, ?>> cm =
    //				new CMRespDto<TestData<?, ?>>(200, "성공", td);
    //		CMRespDto<?> cm =
    //				new CMRespDto<>(200, "성공", td);
    		
    		System.out.println(cm);
    		
    	}
    }

    ■ Main2

    package j18_제네릭;
    
    public class Main2 {
    
    	// 멤버 메소드는 생성해야지만 즉 객체 생성을 해야지 호출 가능
    	// extends 뒤의 자료형을 상속받은 경우만 와일드카드로 허용 
    	// super 뒤의 자료형과 상속하는 클래스만 와일드카드로 허용 
    	/*
    	 * 예시
    	 * Person을 상속받은 Student, Teacher
    	 * <? extends Person> Person포함 하위 객체인 Student, Teacher가능
    	 * <? super Student> Student포함 상위 객체인 Person 가능
    	 */
    	/*
    	 * ? 와일드카드 제약
    	 * extends	대상 객체 하위
    	 * super	대상 객체 상위
    	 */
    	public CMRespDto<?> reponse(CMRespDto<?> cmRespDto) {
    		System.out.println("[응답데이터]");
    		System.out.println(cmRespDto);
    		return cmRespDto;
    	}
    	
    	// <?> 와일드카드 : 어디에든 가져갈 수 있음, Object로 형변환 되었다고 생각
    	public static void main(String[] args) {
    		Main2 main = new Main2();
    		CMRespDto<String> hello =
    				new CMRespDto<String>(200, "성공", "안녕하세요");
    		
    		CMRespDto<Integer> score = 
    				new CMRespDto<Integer>(200, "성공", 85);
    		
    		System.out.println("hello");
    		// Object로 형변환 되었다고 생각함 왜냐하면 <?>로 정의되어 있어 모호하기 때문
    		System.out.println(main.reponse(hello));
    		
    		System.out.println("score");
    		System.out.println(main.reponse(score));
    	}
    }